Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.7k views
in Technique[技术] by (71.8m points)

git show of a merge commit

when I have a merge commit and run git show #commit, it shows only commit log, not the the diff to the real change, like

commit c0f50178901e09a1237f7b9d9173ec5d1c4936c
Merge: ed234b ded051
Author: abc
Date:   Mon Nov 21 15:56:33 2016 -0800

    Merge branch 'abc'

I understand the real commit is in merge log, but I want to save typing, is there a way to show the diff in one?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

TL;DR: use git show -m c05f017 or git show --first-parent c05f017, or perhaps git diff c05f017^ c05f017.


There's a fundamental error in your question: commits are not diffs; commits are snapshots. This might seem like a distinction without a difference—and for some commits, it is. But for merge commits, it's not.

When git show (or git log -p) shows a commit as a diff, it's doing so by comparing the commit's snapshot to something else. The git diff command does the same thing: it compares one commit to another commit. (Or it can compare a commit to the work-tree, or to the contents of the index, or a few other combinations as well.)

For ordinary commits, it's trivially obvious what to compare: compare this commit's snapshot to the previous (i.e., parent) commit's snapshot. So that is what git show does (and git log -p too): it runs a git diff from the parent commit, to this commit.

Merge commits don't have just one parent commit, though. They have two parents.1 This is what makes them "merge commits" in the first place: the definition of a merge commit is a commit with at least two parents.


1A merge commit can have three or more parents. These are called "octopus merges". They don't do anything special, though, and are mainly for showing off. :-) You can ignore them here.


When there are two parents, which one(s) should git show compare against?

What git log -p chooses to do by default is not to compare at all. You can make it show something by adding various flags (see below).

What git show chooses to do by default is more complicated. Since there are two parents, git show first compares against the "first parent",2 then compares against the second parent. Then—this part is quite crucial—it combines the two diffs, producing a so-called "combined diff".

For the next section, let me note a tricky, but very useful, bit of Git syntax. If you have a commit ID like c05f017, you can add a caret or "hat" character ^ after that, to name a parent commit. You can optionally add another number to select which parent. For regular (non-merge) commits there's only one, so c05f017^ is the parent. For merge commits, c05f017^ and c05f017^1 both mean the first parent, while c05f017^2 means the second parent.


2I put this in quotes because the first parent idea is especially important in Git, as we will see in a moment. In other words, Git cares most about which parent is first, while the rest are just "the rest".


Combined diffs

The combined diff format is described in the documentation, but a key bit is first described here, so as to make it especially obscure:3

Note that combined diff lists only files which were modified from all parents.

That is, suppose M is a merge commit, and diffing M^1 vs M says file mainline.txt and common.txt were both changed. Suppose further that diffing M^2 and M says that file sidebranch.txt and common.txt were both changed. The combined diff will show only common.txt, skipping both mainline.txt and sidebranch.txt because those two files were only modified from one parent (each). (Even then Git may show only some of the diffs for common.txt.)


3It took me a long time to find this in the documentation, as I kept looking at the other section.


Splitting the diffs

The -m option—m probably stands for merge here—tells Git to, in effect, "split" the merge. That is, instead of trying to combine the diffs against each parent into one big combined diff, just show the diff against each parent, one diff at a time.

This is sometimes what you want. When it's not what you want, you can run your own explicit git diff to just diff against one of the two parents (or see below).

Which parent should you diff against?

Usually, the correct answer is "the first parent".

The key to the "first parent" notion is that when Git makes a merge commit, it always records the branch you're on at the time, as the first parent. The other branch becomes the second parent.

That is, if you're on develop and you merge topic:

$ git checkout develop
$ git merge topic

Git will make a new commit—a merge commit, with two parents—on your current branch, develop. The first parent of the merge commit will be the commit that was the tip of develop just a moment ago. The second parent will be the commit that is (still) the tip of topic.

Since you're usually concerned with what the merge brought in, comparing against the first parent will give you that. So usually that's what you want. For this reason, git show allows you to run git show --first-parent. That "splits" the commit and then git show only diffs against the first parent. (This is a bit different than git show -m, which splits the commit twice: the first split compares against the first parent, and the second split compares against the second parent.)

Similarly, you can run git log -p --first-parent Here, the --first-parent flag has an even more important effect: the log operation does not look at any of the side branch's commits at all, only those on the main (first-parent) line. Note that if your Git is older than 2.31, you still need the -m flag as well (when using git log, that is; git show defaults to --cc and hence does not require the -m, and all of this was cleaned up in Git 2.31).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...