1

I had a branch which was merged off of commit A of branch main. I made a few changes and ended up like this:

A-B-C-D

I then merged the branch back to main introducing a merge commit. A fast-forward merge would have sufficed but our policy is to create a merge commit. I noticed a spelling mistake in the merge's commit message and did a git commit --amend to correct it. The history now looks like this. Where E is the merge commit.

A-B-C-D-E

Parents of E are displayed by git log as Merge: A D.

The problem now is that main does no longer contain the changes of commits B, C or D.

  • For example C changed file foo/bar but when opening the file as of E the file is in state `A´.
  • Also a git log -- foo/bar does not list commit C.
  • Executing git diff A E shows an empty diff as does git show E.

This is the corresponding section from my reflog:

E HEAD@{93}: commit (amend): Finish Hotfix
Z HEAD@{94}: commit (merge): Finsh Hotfix
A HEAD@{95}: checkout: moving from hotfix to main
D HEAD@{96}: commit: Changes
C HEAD@{97}: commit: Changes
B HEAD@{98}: commit: Changes
A HEAD@{99}: checkout: moving from main to hotfix

When I try to merge the changes again (git merge D) git states Already up to date..

  • How did I end up like this? Caused amending the problem?
  • What is my best option to fix this issue without cluttering the history too much? The branches have been pushed already a few days ago and cannot be rewritten anymore.
sigy
  • 2,408
  • 1
  • 24
  • 55
  • "git log -- foo/bar does not list commit C" That does not prove what you think it proves, because by default this command will not branch into the second parent of a merge. – matt Dec 23 '20 at 14:29
  • @matt Ok, thanks for pointing this out. Nevertheless the file does not contain the changes made to it by commit `C` – sigy Dec 23 '20 at 15:04
  • Well, something is going on that you have not told us. If you truly merged, with a merge commit, and then immediately did a commit amend, then (as you say) A and D are still the parents of the amended commit (it is a merge commit) and the changes in both branches are present in the amended merge commit. So either you did some other stuff you haven't told us about, or else your method of testing whether the "changes are present" is faulty. – matt Dec 23 '20 at 19:12
  • For example you say "Nevertheless the file does not contain the changes". Okay, so maybe it doesn't contain the changes _now_. But that would be due to something done _later_. We are on HEAD minus 93; there are 92 later commits in there that could have reversed those changes. – matt Dec 23 '20 at 19:13
  • To trace what happened in D, C, and B, `git checkout E` (detached, just temporary) and then say `git show HEAD^2`, then `git show HEAD^2~1`, then `git show HEAD^2~2`. – matt Dec 23 '20 at 19:27
  • @matt Thank you for your help. `E` is the tip of branch `main` so no later commit could have reverted the changes. I double checked the merge commit's parents and they are indeed `A` and `D`. I checked out `E` as per your suggestion and checked `git show HEAD^2` and its previous commits. They are indeed `D`, `C` and `B` and the diffs are correct. Also `git show E` shows an empty diff. – sigy Dec 24 '20 at 11:07

2 Answers2

4

Amending a merge commit, in and of itself, does not somehow magically undo the effects of the merge. Therefore one is forced to conclude that there is something wrong with the story. Either your tests for investigating what happened are themselves flawed, so that you are not getting a true picture, or else there was more going on that you have not told us about.

Although this will not help the situation very much, I will just enact the scenario as you have described it, to prove that the amended commit does not negate the merge.

Constructing the history:

$ git init
$ echo a > a; git add .; git commit -m'a' 
$ git branch hotfix
$ git checkout hotfix
$ echo b > b; git add .; git commit -m'b'
$ echo c > c; git add .; git commit -m'c'
$ echo d > d; git add .; git commit -m'd'
$ git checkout master
$ git merge --no-ff hotfix # write commit message in editor

Checking what we've got after the merge:

$ ls
a   b   c   d
$ git log --oneline --graph
*   2eb6b68 (HEAD -> master) Merge branch 'hotfix'
|\  
| * ec24fa1 (hotfix) d
| * 052560f c
| * 74d6f9a b
|/  
* 220dd03 a

Amending the merge commit and checking what we've got after:

$ git commit --amend # write new commit message in editor
$ ls
a   b   c   d
$ git log --oneline --graph
*   7a7d731 (HEAD -> master) Improved merge branch 'hotfix'
|\  
| * ec24fa1 (hotfix) d
| * 052560f c
| * 74d6f9a b
|/  
* 220dd03 a

As you can see, the amended merge commit was just swapped in for the original merge commit without upsetting the history or the outcome.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

I am still not sure what caused the problem in the first place but it seems I made a mistake during the merge.

However, I was confused by the fact that git show E does not show any changes. This is caused by a misconception of mine of how git show works. How it works is explained in detail in this answer. So executing git show -m E shows how the merge commit reverts all the changes of B, C and D.
After understanding this I think that a revert commit it the most elegant solution to fix the problem. That is executing git revert -m2 E.

sigy
  • 2,408
  • 1
  • 24
  • 55