| #!/bin/sh | |
| USAGE='[--mixed | --soft | --hard] [<commit-ish>]' | |
| . git-sh-setup | |
| tmp=${GIT_DIR}/reset.$$ | |
| trap 'rm -f $tmp-*' 0 1 2 3 15 | |
| reset_type=--mixed | |
| case "$1" in | |
| --mixed | --soft | --hard) | |
| reset_type="$1" | |
| shift | |
| ;; | |
| -*) | |
| usage ;; | |
| 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 | |
| git-update-ref HEAD "$rev" | |
| 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{$_}) { | |
| # it is ok if this fails -- it may already | |
| # have been culled by checkout-index. | |
| unlink $_; | |
| } | |
| } | |
| ' $tmp-exists | |
| ;; | |
| --soft ) | |
| ;; # Nothing else to do | |
| --mixed ) | |
| # Report what has not been updated. | |
| git-update-index --refresh | |
| ;; | |
| esac | |
| rm -f "$GIT_DIR/MERGE_HEAD" |