Why does git lose a commit from log after merge?

2019-07-27 07:05发布

问题:

I'm trying to merge a development branch into master. But it seems to undo a commit that was made in master, to the extent that the particular commit no longer appears in the file's git log.

When I'm on the master branch, I can see commit 2d1b9af on Jul 14

c:\src>git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean

c:\src>git log server\Fitnesse\FitNesseRoot\APITest\content.txt
commit 88a68b11b273b98531ae686b85b5733b86706bda
Author: charles
Date:   Fri Jul 15 00:56:44 2016 +0000

    XX-338 Add IsDeleted to Place table

commit 2d1b9afdabd7fbbf970d697bd0c15957a8fd288a
Author: charles
Date:   Thu Jul 14 23:15:28 2016 +0000

    fix FitNesse test which are broken by renaming

commit f1616fed48bb15c1c120cfe016e571f49aae6244
Author: charles
Date:   Tue Jun 21 11:04:53 2016 +1200

    modify fitNesse Test for new API changes.

Then I merge in my large branch.

c:\src>git merge origin/myLargeBranch
Removing server/Database/355_UnitTest.sql
Merge made by the 'recursive' strategy.
 .../packages.config                                |   2 +-
 .../Utilities/Extensions/StringExtensions.cs       |  10 +
 .../Utilities/Throttle.cs                          |  45 ++++

 [ ... etc ]

 .../FitNesseRoot/APITest/content.txt         |  37 +--
 128 files changed, 3705 insertions(+), 481 deletions(-)
 create mode 100644 [ ... ] 

c:\src>git status
On branch master
Your branch is ahead of 'origin/master' by 32 commits.
  (use "git push" to publish your local commits)
nothing to commit, working directory clean

I note here that it alters the file I'm looking at. I haven't actually modified this file since I took the branch. This may be related to my issue, but it's not specifically what I'm asking about.

What's important to me right now, is that he commit from 14 July isn't in my log any more:

c:\src>git log server\Fitnesse\FitNesseRoot\APITest\content.txt
commit f1616fed48bb15c1c120cfe016e571f49aae6244
Author: charles
Date:   Tue Jun 21 11:04:53 2016 +1200

    modify fitNesse Test for new API changes.

commit 16b7beb9d1045f5fe7354c0fdbe637a49bb48ce0
Author: charles
Date:   Tue May 10 10:54:13 2016 +1200

So I'm a little concerned about getting the wrong code in the end. This is a bit of a worry.

But I'm really much more worried that git is now not showing in it's log that the changes were ever made.

What am I missing?

Update After comments from @tim-biegeleisen I've tracked down the actual commit, but am still as confused.

The culprit appears to be a merge from master onto my development branch:

c:\src>git show b5637f9
commit b5637f9a65e415f1b415fad99c9e7a4e6b46ab1a
Merge: cb8ed90 6b5c0e1
Author: GregH <GregH@GREGH-LT001>
Date:   Tue Jul 26 04:25:40 2016 +0000

    Merge from master
[ ... ] 

cb8... is my branch:

c:\src>git checkout cb8ed90
Previous HEAD position was 6b5c0e1... PR 93: Merge DeletePlace to master
HEAD is now at cb8ed90... Added tests for apple messages


c:\src>git log server\Fitnesse\FitNesseRoot\APITest\content.txt
commit f1616fed48bb15c1c120cfe016e571f49aae6244
Author: charles
Date:   Tue Jun 21 11:04:53 2016 +1200

6b5... is master

c:\src>git checkout 6b5c0e1
Previous HEAD position was cb8ed90... Added tests for apple messages
HEAD is now at 6b5c0e1... PR 93: Merge DeletePlace to master

c:\src>git log server\Fitnesse\FitNesseRoot\APITest\content.txt
commit 88a68b11b273b98531ae686b85b5733b86706bda
Author: charles
Date:   Fri Jul 15 00:56:44 2016 +0000

And after the merge, I've lost the commits from 14 and 15 July.

c:\src>git checkout b5637f9
Previous HEAD position was 6b5c0e1... PR 93: Merge DeletePlace to master
HEAD is now at b5637f9... Merge from master

c:\src>git log server\Fitnesse\FitNesseRoot\APITest\content.txt
commit f1616fed48bb15c1c120cfe016e571f49aae6244
Author: charles
Date:   Tue Jun 21 11:04:53 2016 +1200

**Update: ** Suggested by VonC, git log --all shows the commits are still in the history.

Without --all, it's as above, showing latest update jun 21 git log server\Fitnesse\FitNesseRoot\APITest\content.txt (No point repeating it).

But with --all they're there:

c:\src>git log --all server\Fitnesse\FitNesseRoot\APITest\content.txt
commit 88a68b11b273b98531ae686b85b5733b86706bda
Author: charles
Date:   Fri Jul 15 00:56:44 2016 +0000

    XX-338 Add IsDeleted to Place table

commit 2d1b9afdabd7fbbf970d697bd0c15957a8fd288a
Author: charles
Date:   Thu Jul 14 23:15:28 2016 +0000

    fix FitNesse test which are broken by renaming

commit f1616fed48bb15c1c120cfe016e571f49aae6244
Author: charles
Date:   Tue Jun 21 11:04:53 2016 +1200

    modify fitNesse Test for new API changes.

So how come they're undone during the merge?

回答1:

The output you get from git log is actually rather tricky. There are numerous traps you can trigger. The one you are hitting in this case is called "history simplification". Quoting from the documentation:

Sometimes you are only interested in parts of the history, for example the commits modifying a particular <path>. But there are two parts of History Simplification, one part is selecting the commits and the other is how to do it, as there are various strategies to simplify the history.

The following options select the commits to be shown:

<paths>

       Commits modifying the given <paths> are selected.

--simplify-by-decoration

      Commits that are referred by some branch or tag are selected.

Note that extra commits can be shown to give a meaningful history.

The following options affect the way the simplification is performed:

Default mode

       Simplifies the history to the simplest history explaining the final state of the tree. Simplest because it prunes some side branches if the end result is the same (i.e. merging branches with the same content)

--full-history

       Same as the default mode, but does not prune some history.

[snip]

Before you merge, Git simplifies the history as viewed without looking down the path of the merge.

After you merge, Git simplifies the history as viewed while looking down the path (or rather, "both paths" as it were) of the merge. Since you are using the default mode, this allows Git to "prune some side branches", as the documentation says (without going into enough detail about just which side branches are being pruned, although there is more later in the section using the word TREESAME: not spelled out there is the fact that TREESAME is tested after stripping out every file except for those in your listed <paths>).

If you add --full-history you should see your commits return.

Note that history simplification is not turned on if you do not specify some path(s), unless you add some of the specific simplifier options (in the section I snipped).