Reputation: 31929
Typically, I have this situation in git
master
and there are one common ancestor commit and two merge commitsfeature-branch-1
or feat1
feat2
Both branches were auto-merged by git, but I know there were some "conflicting" changes and I am concerned how were they resolved, however, displaying the diff of any two commits gives loads of changes in lots of unrelated files.
Is it possible to see the diff between the merge commits of feat1
and feat2
, but only with the files appearing in feat1
that were affected by feat2
?
Upvotes: 0
Views: 1508
Reputation: 487993
Both branches were auto-merged by git, but I know there were some "conflicting" changes and I am concerned how were they resolved ...
There is, at the moment, no great way to show this. (The new "merge-ORT" feature is an enabling technology that will allow for the "great way", or at least, a simple one-line-command way, to do that, but it's not here yet.)
In my opinion, the best way to find out how the conflicts were handled is to re-perform the merge. You'll get the conflicts when you do this. You don't have to finish the merge: just get the conflicts. You now have a list of all conflicted files, and can compare what's in the merge snapshot to what is in any given other commit.
To re-perform a merge, check out the merge commit's first parent, perhaps as a detached HEAD, perhaps in an added work-tree since you will likely just throw it away afterward. The commands below assume you have a place to do this (a <path>
outside your main work-tree) and the hash ID of the merge commit you wish to test:
git worktree add --detach <path> <hash>^1
cd <path> # or pushd, if using bash, zsh, etc
git merge <hash>^2
The result is the same set of merge conflicts that happened last time, assuming whoever did the merge used the same set of git merge
options.
You can now view any of the merge conflicts and compare them to what's stored in the merge result. For instance, if file conflicted.ext
is the one in question:
git show <hash>:conflicted.ext > resolved.ext
and you can now compare, in whatever comparison tool you like—your editor, a three way merge handler, whatever—the conflicted file and the resolved file. If you like, you can get the three merge-input files easily as well, with git checkout-index --stage=all conflicted.ext
.
Now, as to your final question:
Is it possible to see the diff between the merge commits of feat1 and feat2, but only with the files introduced in feat1 that were affected by feat2?
You can have git diff
diff any particular files, but it's misleading to think in terms of files. Think in terms of commits, because git diff
itself compares the snapshots stored in some commit. You must name the two commits first.1 So if M1
is the hash ID of merge commit #1 on master
, which merges commits P1
(the parent on master, which is probably the merge base commit shown in blue at the left edge of your graph2) and P2
(presumably the rightmost green commit). you have to pick two of these three commits.
In this particular case (where P1
is presumably the merge base commit), we can figure out which files were "introduced in feat1
" by simply comparing the merge result snapshot with the merge base snapshot. Any files whose status is A
(newly added) must necessarily have come from feat1
. If, however, we'd had any commits on master
between the merge base and the final merge, newly-added files could have come from those other commits on master
. So this case is easy enough:
git diff --name-only --diff-filter=A <P1> <M1>
gets us a list of such files. If we assume that this merge went well, we can now inspect the M2
merge with particular attention to these files. But if we just repeat the M2
merge, that's probably just as easy, and maybe even easier.
1There is a thing called a combined diff, and git show
of a merge commit produces it and git diff
can be made to produce one. However, combined diffs deliberately leave stuff out. The intent of a combined diff is, I think, to help show merge conflicts, but the mechanism that combined diff uses to choose what to leave out makes this intent fall quite flat. In particular, if someone incorrectly resolved a conflict by picking just one parent's version of some file, the combined diff will omit that file entirely and thus hide the fact that the merge was wrong.
2I think in this case they have it right, but my experience with Atlassian software over the years has been that some of their graphs are a bit dodgy. (This isn't unusual: GitHub have the same problem. Graphs are hard.)
Upvotes: 1
Reputation: 111
You want to list the files which where modified by both of your merge commits:
1 - List the changed files for one commit:
git show <SHA> --name-only --pretty=format:
2 - Compare the file lists for your two merge commits and get the intersection:
comm -12 <(git show SHA1--name-only --pretty=format: |sort -u) <(git show SHA2--name-only --pretty=format: |sort -u)
3 - Now you have your file list, you can diff all the files in a loop, e.g:
for r in `comm -12 <(git show SHA1--name-only --pretty=format: |sort -u) <(git show SHA2--name-only --pretty=format: |sort -u)`; do git difftool SHA1 SHA2 "$r"; done
Of course, you have to replace SHA1 and SHA2 by your merge commits.
Upvotes: 2