Home > database >  Why is an empty Merge Commit being Produced
Why is an empty Merge Commit being Produced

Time:03-13

Dev wants to update featureBranch with updated changes from origin/master branch, and then push their local changes to origin/featureBranch

git checkout featureBranch
git add .
git commit -n -m "message"
git checkout master
git fetch
git checkout featureBranch
git merge master --no-verify
git push origin featureBranch

I see a completely blank commit (merging with dev), with 0 additions and 0 removals. Why?

CodePudding user response:

There is not enough information in the question to say exactly why you got a merge commit, but there are several possibilities:

  • A merge commit is necessary. This occurs if the two branch-tip commits are both ahead of the shared (common) merge base commit. That can happen even if there are no changes involved in making the merge.

  • A merge commit was forced. That happens with GitHub's MERGE button always, and with command-line Git, happens if you specify the --no-ff option. You can include this option in your configuration, in which case we would not see it on the command line.

  • A fast-forward was possible but the argument to git merge was that of a tag and the tag:

    is not stored in its natural place in the refs/tags/ hierarchy

    (as described in the git merge documentation, under the --ff, --no-ff, --ff-only options).

(in decreasing order of probability). The last would require that the name master be resolved to a tag object, which is pretty unlikely but not technically impossible. The middle would occur if you configured merge.ff to false. The first is the most likely as it is quite common.

I see a completely blank commit (merging with dev), with 0 additions and 0 removals. Why?

No commit is ever blank (nor empty, despite the git commit --allow-empty option spelling). A commit always contains:

  • a full snapshot of every file (with the usual compression and de-duplication), plus
  • metadata.

A merge commit contains metadata listing two or more parent hash IDs: that's what makes it a merge commit in the first place. An ordinary (non-merge) commit has one parent, and at least one commit in every non-empty repository is the very first commit and therefore has no parent, making it a (usually the) root commit. Every commit also has a full snapshot of every file: merge commits are no different here.

Suppose we have the following series of commits, and two branch names br1 and br2 selecting their tip commits:

          I--J   <-- br1
         /
...--G--H
         \
          K--L   <-- br2

Running:

git checkout br1 && git merge br2

will, if all goes well, produce the new merge commit M on branch br1 and leave us with:

          I--J
         /    \
...--G--H      M   <-- br1 (HEAD)
         \    /
          K--L   <-- br2

The snapshot for commit M is that made by:

  • finding the differences (various files changes) from H to J;
  • finding the differences from H to L as well;
  • combining (merging) those differences; and
  • applying the combined differences to the snapshot from commit H.

This keeps the H-to-J changes and adds the H-to-L changes, if you like to view it that way, or it keeps the H-to-L changes and adds the H-to-J changes: sums are (at least for non-conflict cases) commutative, like integer arithmetic: 3 7 = 10, but 7 3 = 10 too.

If whoever made the br2 changes copied exactly the br1 changes, the "sum" that Git makes here will be to keep just one copy of the changes. So the snapshot in M will match both of those in J and L (which themselves both match). That would show as no additions and no removals.

If whoever made one of the two branches made a change, then reverted it, so that the snapshot in one of J or L matched the snapshot in H, that "side" of the merge would have no contribution, and the snapshot in M would match the other commit. If the "side" that had a net-zero contribution was br2, that too would show as no additions and no removals.

Without more (e.g., the output from git log --graph, perhaps with --oneline, and/or the results of git merge-base from before the merge plus the appropriate git diff commands to see what changes Git is merging, and/or the result of git config --get merge.ff) we can't say which of these might have triggered the "empty" merge (to misuse the word "empty" the way Git does).

  • Related