Big tool rename.
[git.git] / git-reset.sh
diff --git a/git-reset.sh b/git-reset.sh
new file mode 100755 (executable)
index 0000000..04c1ac0
--- /dev/null
@@ -0,0 +1,97 @@
+#!/bin/sh
+. git-sh-setup || die "Not a git archive"
+
+tmp=/var/tmp/reset.$$
+trap 'rm -f $tmp-*' 0 1 2 3 15
+
+reset_type=--mixed
+case "$1" in
+--mixed | --soft | --hard)
+       reset_type="$1"
+       shift
+       ;;
+esac
+
+rev=$(git-rev-parse --verify --default HEAD "$@") || exit
+rev=$(git-rev-parse --verify $rev^0) || exit
+
+# We need to remember the set of paths that _could_ be left
+# behind before a hard reset, so that we can remove them.
+if test "$reset_type" = "--hard"
+then
+       {
+               git-ls-files --stage -z
+               git-rev-parse --verify HEAD 2>/dev/null &&
+               git-ls-tree -r -z HEAD
+       } | perl -e '
+           use strict;
+           my %seen;
+           $/ = "\0";
+           while (<>) {
+               chomp;
+               my ($info, $path) = split(/\t/, $_);
+               next if ($info =~ / tree /);
+               if (!$seen{$path}) {
+                       $seen{$path} = 1;
+                       print "$path\0";
+               }
+           }
+       ' >$tmp-exists
+fi
+
+# Soft reset does not touch the index file nor the working tree
+# at all, but requires them in a good order.  Other resets reset
+# the index file to the tree object we are switching to.
+if test "$reset_type" = "--soft"
+then
+       if test -f "$GIT_DIR/MERGE_HEAD" ||
+          test "" != "$(git-ls-files --unmerged)"
+       then
+               die "Cannot do a soft reset in the middle of a merge."
+       fi
+else
+       git-read-tree --reset "$rev" || exit
+fi
+
+# Any resets update HEAD to the head being switched to.
+if orig=$(git-rev-parse --verify HEAD 2>/dev/null)
+then
+       echo "$orig" >"$GIT_DIR/ORIG_HEAD"
+else
+       rm -f "$GIT_DIR/ORIG_HEAD"
+fi
+echo "$rev" >"$GIT_DIR/HEAD"
+
+case "$reset_type" in
+--hard )
+       # Hard reset matches the working tree to that of the tree
+       # being switched to.
+       git-checkout-index -f -u -q -a
+       git-ls-files --cached -z |
+       perl -e '
+               use strict;
+               my (%keep, $fh);
+               $/ = "\0";
+               while (<STDIN>) {
+                       chomp;
+                       $keep{$_} = 1;
+               }
+               open $fh, "<", $ARGV[0]
+                       or die "cannot open $ARGV[0]";
+               while (<$fh>) {
+                       chomp;
+                       if (! exists $keep{$_}) {
+                               print "$_\0";
+                       }
+               }
+       ' $tmp-exists | xargs -0 rm -v -f --
+       ;;
+--soft )
+       ;; # Nothing else to do
+--mixed )
+       # Report what has not been updated.
+       git-update-index --refresh
+       ;;
+esac
+
+rm -f "$GIT_DIR/MERGE_HEAD"