When a certain commit (recursive merge
) has 2 parent commits, as mentioned in here the second parent is the commit on the branch that we merged in, which means containing all the changes introduced by that merge commit. This is ok for recursive merge
. But if it a octopuss merge
like this how do we identify which commit introduce which changes?. Thanks in advance

- 1
- 1

- 3,956
- 8
- 38
- 58
1 Answers
UPDATE - Added some clarification about diff-based approach
It's somewhat misleading to say that the second parent is the source of all changes in a normal merge. There may be manual conflict resolution, or someone may just merge with the --no-commit
option and introduce additional changes during the merge itself. It's more generally applicable to think in terms of how the merge differs from each of its parents, than to think of which parent introduced each change.
Still, it can be useful to think in terms of "where did this change come from". Depending on what information you're really after you could start with one of these:
1) git blame
will tell you the commit from which each line of code originates. Anything that originates from a commit in HEAD^..branchN
must indicate a change on branchN
. But since the info you're given is a commit ID for each and every line of code, considerable post-processing would be needed to zero in on changes.
2) You could do a diff for each branch. Originally I was thinking
git diff HEAD^ HEAD^2
and so on (replacing HEAD^2
with a reference to each merged branch). This is ok, except if the main branch has changed much since the other branches diverged (in which case the inverse of those changes would appear in every diff).
What you really are asking for is the diff between each branch tip and the point where that branch started to diverge; so if you can locate the "common ancestor", maybe just use that:
git diff A HEAD^2
(where A
is the latest commit reachable from both HEAD^
and HEAD^2
). While this is a straight-forward way to express (for one branch at a time) exactly what you mean, it does require tracking down the common ancestor in each case. (There may be a good shortcut I'm not thinking of; I'll come back with an update if it occurs to me.)
And if the branch topology is too messy, this may still be somewhat unclear. For example, if branch3
was actually branched from branch2
, then you'd have to decide whether you mean to diff branch3
against the common ancestor with HEAD
or with branch2
(the former approach meaning some changes would be ascribed to both branch2
and branch3
).
It would be nice to use a single command to generate all the diffs, and on the surface this is what the -m
option to log
or show
would do; but this takes us back to the start of my answer, as you're getting the difference of the merge with each branch (not the changes introduced by each branch) and have to mentally negate each change. (i.e. you would have to look for the one branch whose diff doesn't include a change to know where that change came from).

- 42,148
- 4
- 35
- 52
-
This parent-diffing approach could be applied even to two-parent merges, to distinguish changes that truly came from the other branch from those introduced during the merge, by the way... – Mark Adelsberger Apr 17 '17 at 14:05
-
1Note that `git log -p -m` or `git show -m` on the merge commit will show one diff per parent. If line *L* of `path/to/file.ext` differs in merge-vs-parent1 and merge-vs-parent2 but not in merge-vs-parent3, then the change *to* line *L* came in via parent3. Since the octopus merge strategy refuses to allow conflicting merges, that's a pretty good bet. – torek Apr 17 '17 at 14:24
-
@torek - For a set of significant patches I wouldn't want to do the negative work of figuring out "which of the N diffs doesn't include this" for each change (as needs doing if you diff against the merge commit). Running the diffs against the 1st parent (instead of against the merge commit) helps a little, but the more I think about that, I don't quite like it either (since every diff would contain the inverse of the changes from the "first parent" branch (if any)). Most direct way to see changes from a branch: diff the branch tip vs. common ancestor. Has to be done for each branch, though. – Mark Adelsberger Apr 17 '17 at 14:46