git reset HEAD~1
I was under the impression that the ~1 meant: start at the HEAD, follow 1 link, and set the HEAD tag to that new commit node. I was expecting
git reset HEAD~2
to follow 2 links and then set the HEAD tag. However, if I try it, I get an error:
$ git reflog
c83bbda HEAD@{0}: reset: moving to HEAD~1
44c3540 HEAD@{1}: commit: you will be garbage soon
c83bbda HEAD@{2}: reset: moving to HEAD~1
aee7955 HEAD@{3}: commit: back to 4 lines
c83bbda HEAD@{4}: reset: moving to HEAD~1
19ec1d5 HEAD@{5}: commit: 3 lines
c83bbda HEAD@{6}: reset: moving to HEAD~1
a049538 HEAD@{7}: commit: added new line
c83bbda HEAD@{8}: commit (initial): first commit
$ git reset --hard HEAD~2
fatal: ambiguous argument 'HEAD~2': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
Apparently I was mistaken, but the doc page for git reset is not very useful in clarifying this. So, what does the ~1 mean and why do I need it?
HEAD~1 is "the first parent of HEAD", while HEAD~2 is "the first parent of the first parent of HEAD, and so on (so HEAD~n for some n is like HEAD followed by n ^ symbols and no numbers). Again, all the specifics are in the git-rev-parse manual page.
Be careful when mixing git reset with "revisions counting backwards from HEAD". git reset will, in general, change the value of HEAD, e.g.:
$ git checkout master # now on tip of "master" branch
$ git branch save master # copy branch tip to another label, for safekeeping
$ git reset HEAD^ # or git reset HEAD~1
moves HEAD (and master) to its first parent. Another way to name that parent is save^, and yet another is save~1. After the move finishes, though, HEAD now names that parent revision, so HEAD^ names its parent:
$ git reset HEAD^
moves you back another step, so that master and HEAD now name the same commit that save~2 names. This is easy to see using git rev-parse, which tells you the commit-ID that some symbolic-name maps to:
$ git rev-parse save~2 master
0f5a13497dd3da8aff8e452c8f56630f83253e79
0f5a13497dd3da8aff8e452c8f56630f83253e79
At this point, you can restore master to the save-point with:
$ git reset save
which moves HEAD and master back to the saved revision, and then you can delete save safely if you like:
$ git branch -d save
Note that you could save a save-point with git tag too: the only difference between a branch and a tag is the behavior of new check-ins when "on a branch" (tags don't move, branches do) and check-outs (tags put you in "detached HEAD" = not-on-a-branch state, branch names put you in "on-a-branch" state).
See git help revisions or Git - Revision Selection for more details on how to specify a commit:
<rev>~<n>, e.g. master~3A suffix
~<n>to a revision parameter means the commit object that is the<n>thgeneration ancestor of the named commit object, following only the first parents. I.e.<rev>~3is equivalent to<rev>^^^which is equivalent to<rev>^1^1^1.
This syntax can be used with most Git commands, so it's not specific to git reset.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With