I have main
:
* 38f4e95 - (HEAD -> main, origin/main) …
* 2abcc91 - nginx configs blue and green …
From main, I merge a branch and now I have:
* 461eb66 - (HEAD -> main,
|
| * 38f4e95 - (origin/main) .
| * 2abcc91 - nginx configs b
| * 320c676 - Merge branch
| |
| * | 46d0cbd - fix filter (3
* | | 7ea521f - EF Migration
I expect HEAD^ after a commit to be “the HEAD from just before I commited anything” i.e. 38f4e95. But it isn’t, it’s a commit from days ago with a whole bunch of work missing. Why?
-
Instead HEAD^2 is what I expect to be HEAD^1 (aka HEAD^).
-
My habit before merging into main is to first merge from main into branch (so issues are found and fixed in the branch). Does this make a difference?
-
Of course the question springs from wanting to undo the merge. It seems like
git reset HEAD^ --hard
should be just the thing for undo last commit, but instead I have to either be really careful or first note down what the “previous” commit was, or else hope that reset from a remote will neatly solves it.
2
Answers
Both
HEAD^1
andHEAD^2
are parents of your merge commit. There’s a nice illustration inman gitrevisions
:It’s because the workflow you describe results in fast-forward merges:
This is exactly why it’s happening! If you have
my-branch
checked out and merge frommain
, thenmain
(commit 38f4e95) is the second parent of that merge commit. When you then switch over tomain
and mergemy-branch
, it’s a fast-forward merge so the branches are equivalent at that moment.Note the first and second parents can’t switch based on the point of view- they are "baked into" the commit.
So, yes, if you need to revert, you’ll want to double-check the first and second parents to make sure you revert the right direction. You can use
git log --first-parent
to see what-m1
would yield. (And even justgit log
will display the parent commits for the merge in the proper order.)Suggestion: Here are 2 possible tweaks you could make to your workflow to prevent this from happening in the future (either of these would prevent it, but I personally prefer both):
main
into your feature branch, you could rebase your branch ontomain
to update it. Then you won’t be adding "back merges" that could likely get fast-forwarded intomain
which flips the desired parent order.main
, choose the--no-ff
option to force creating a new merge commit. Then the first parent will always be what you expect.