Home > Back-end >  git checkout HEAD~N isn't going to the commit I expect
git checkout HEAD~N isn't going to the commit I expect

Time:11-09

I'm seeing behavior where git checkout HEAD~N isn't going back N commits in my git history.

If my commit history looks like this

git log --oneline -n 5

3ad352f (HEAD -> develop, origin/develop, asdf) commit message
93eeda7 Merged in branch (pull request #224)
911eb78 (origin/sdfa, asdf) Removes txt file
4b9de92 branch1
7a162e3 Merged in branch1 (pull request #223)

And I do a git checkout HEAD~5 it was my understanding that my HEAD should then point to the commit 5 commits ago. However when I run this command I see something like this:

$ git checkout HEAD~5

$ git rev-parse HEAD
49569625ffe9bfc13fdd4f1f5baab9a72ef7ca02

$ git rev-list --count `git rev-parse HEAD`..develop
13

It appears that I actually checked out a commit 13 commits ago instead of 5 like I expected.

Can anyone explain what is going on, and how I can actually checkout a commit N commits ago?

CodePudding user response:

If your intention is to checkout 7a162e3 Merged in branch1 (pull request #223) :

  • the easiest, unambiguous way is to run git checkout 7a162e3 (you have the sha, use it)
  • if you had run git log --oneline --graph -n 5, you would probably have seen something like :
3ad352f * (HEAD -> develop, origin/develop, asdf) commit message
93eeda7 * Merged in branch (pull request #224)
        |\
911eb78 | * (origin/sdfa, asdf) Removes txt file
4b9de92 | * branch1                                
7a162e3 * Merged in branch1 (pull request #223)

(note: from the commit messages in your question, I'm not sure I understand the correct history of your repo, do check in your terminal how your commits are related)

If the history was as above, counting the "first parents" from your active commit, you would have computed HEAD~2 (instead of HEAD~5)


<commit>~N will only follow a sequence of "first parents" starting from <commit>, while git log or git log --oneline without other options will list (in a flat list) commits coming from merged branches, which will "add" to the count of displayed commits.

git log or git rev-list both have a --first-parent option, to also restrict the list of displayed commits to this "first parents" sequence :

git log --oneline --first-parent HEAD~5..HEAD  # will list only 5 commits
git rev-list --count --first-parent HEAD~5..HEAD  # will display '5'

I also highly recommend to abuse the --graph option of git log, to make sense of how the commits you see depend on one another :

git log --oneline --graph   # you will have a view of what commits are merges,
                            # and what commits come from side branches

extra note

since HEAD (which is equivalent to HEAD~0) is displayed in git log's output, you also have an "off by one" error in -n 5 : in the list displayed by git log -n 5, you will see at most HEAD~4, not HEAD~5.

CodePudding user response:

"5 commits ago" means following the parent lineage of the current commit. You cannot simply count the lines in the output of git log --oneline.

  • Related