git/git-reset.sh

69 lines
1.4 KiB
Bash
Raw Normal View History

#!/bin/sh
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
USAGE='[--mixed | --soft | --hard] [<commit-ish>]'
. git-sh-setup
update=
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
reset_type=--mixed
case "$1" in
--mixed | --soft | --hard)
reset_type="$1"
shift
;;
-*)
usage ;;
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
esac
case $# in
0) rev=HEAD ;;
1) rev=$(git-rev-parse --verify "$1") || exit ;;
*) usage ;;
esac
rev=$(git-rev-parse --verify $rev^0) || exit
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
# 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
update=-u
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
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
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
die "Cannot do a soft reset in the middle of a merge."
fi
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
else
git-read-tree --reset $update "$rev" || exit
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
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 -m "reset $reset_type $*" HEAD "$rev"
update_ref_status=$?
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
case "$reset_type" in
--hard )
;; # Nothing else to do
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
--soft )
;; # Nothing else to do
--mixed )
# Report what has not been updated.
git-update-index --refresh
Introduce "reset type" flag to "git reset" I have been feeling that the current behaviour of "git reset" is not quite optimal, but so far could not express exactly what I felt was wrong with it. This patch clarifies it. There are at least two situations you may want to "reset" your working tree. 1. You made a mess in your working tree. You want to switch back to a known good state and start over. This mess may be a result of your own editing, a merge that had too many conflicting changes that you do not feel like to resolve by hand at this moment, or a botched application of a patch you received from somewhere. In this case, you would want to have "git reset HEAD" reset the index file to the tree read from the HEAD commit and the files in the working tree to match index (i.e. "git status" should say "Nothing to commit", without any "unrecorded changes"). The current behaviour leaves the files in the working tree intact, which requires you to run "git checkout -f". Also you need to remember "rm -f" any files that the botched patch may have left in the working tree if the purpose of this "reset" is to attempt to apply it again; most likely the patch would fail if such a file is left behind. 2. You have discovered that commits you made earlier need to be reorganized. The simplest example is to undo the last commit, re-edit some files, and redo the commit. Another simple eample is to undo the last two commits, and commit the changes in those two commits as a single commit. In this case, you would want to have "git reset HEAD^" reset the $GIT_DIR/HEAD to the commit object name of the parent commit of the current commit (i.e. rewinding one commit), leave the index file and the files in the working tree in a state where you can easily make a commit that records a tree that resembles what you have in the current index file and the working tree. The current behaviour is almost OK for this purpose, except that you need to find which files you need to manually run "git add" yourself. They are files that are in the original HEAD commit and not in the commit you are resetting to. The default without the type flag is to do "--mixed", which is the current behaviour. $ git reset [ --hard | --soft | --mixed ] [ <commit-ish> ] A hard reset would be used for 1 and works in this way: (1) remember the set of paths that appear in the current index file (which may even have unmerged entries) and the current $GIT_DIR/HEAD commit. (2) "read-tree --reset" the specified <commit-ish> (default to HEAD), followed by "checkout-cache -f -u -a". (3) remove any files that appear in (1) but not in <commit-ish> from the working tree. (4) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. (5) remove leftover $GIT_DIR/MERGE_HEAD A soft reset would be used for 2 and works in this way: (1) Make sure that the index file is merged and we do not have MERGE_HEAD; otherwise it does not make sense to do soft reset. (2) backup $GIT_DIR/HEAD to $GIT_DIR/ORIG_HEAD and update $GIT_DIR/HEAD with the specified <commit-ish>. Note that with the current behaviour, "git diff" is the way to see what could be committed immediately after "git reset". With the "soft reset" described here you would need to say "git diff HEAD" to find that out. I am not sure what mixed reset (the current behaviour) is good for. If nobody comes up with a good use case it may not be a bad idea to remove it. Signed-off-by: Junio C Hamano <junkio@cox.net>
2005-08-23 08:55:26 +08:00
;;
esac
git-merge --squash Some people tend to do many little commits on a topic branch, recording all the trials and errors, and when the topic is reasonably cooked well, would want to record the net effect of the series as one commit on top of the mainline, removing the cruft from the history. The topic is then abandoned or forked off again from that point at the mainline. The barebone porcelainish that comes with core git tools does not officially support such operation, but you can fake it by using "git pull --no-merge" when such a topic branch is not a strict superset of the mainline, like this: git checkout mainline git pull --no-commit . that-topic-branch : fix conflicts if any rm -f .git/MERGE_HEAD git commit -a -m 'consolidated commit log message' git branch -f that-topic-branch ;# now fully merged This however does not work when the topic branch is a fast forward of the mainline, because normal "git pull" will never create a merge commit in such a case, and there is nothing special --no-commit could do to begin with. This patch introduces a new option, --squash, to support such a workflow officially in both fast-forward case and true merge case. The user-level operation would be the same in both cases: git checkout mainline git pull --squash . that-topic-branch : fix conflicts if any -- naturally, there would be : no conflict if fast forward. git commit -a -m 'consolidated commit log message' git branch -f that-topic-branch ;# now fully merged When the current branch is already up-to-date with respect to the other branch, there truly is nothing to do, so the new option does not have any effect. This was brought up in #git IRC channel recently. Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-06-23 16:37:02 +08:00
rm -f "$GIT_DIR/MERGE_HEAD" "$GIT_DIR/rr-cache/MERGE_RR" "$GIT_DIR/SQUASH_MSG"
exit $update_ref_status