Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

View already-committed Git merge in external 3-way diff tool

Is there any way to view a merge that has already been committed in a 3-way diff?

If a huge merge between branches was committed 3 weeks ago, is there any way I can see a 3-way diff of it in an external diff-tool like BeyondCompare3? I'm looking for just the files changed in the merge commit. Bonus if I could get it to only show me the conflicts and anything manually changed, as opposed to seeing the entire difference of a file between the two branches.

I wouldn't mind settling for a 2-way diff if the left side had the <<<<< ===== >>>>> conflict markers and the right side was the committed result.

I tried looking at diff-tree, diff-files, diff, difftool, show, and others and couldn't figure it out. I know gitk will show the changes just in the merge commit but I do not like the over-under diff view and it is very hard to understand when there are tons of changes.

If only I could do something like git difftool --cc firstparent..secondparent..result

like image 827
Sean Avatar asked Jun 12 '12 14:06

Sean


People also ask

How do you check if there are any merge conflicts?

To see the beginning of the merge conflict in your file, search the file for the conflict marker <<<<<<< . When you open the file in your text editor, you'll see the changes from the HEAD or base branch after the line <<<<<<< HEAD .

Which commits are involved in 3-way merge?

3-way merges use a dedicated commit to tie together the two histories. The nomenclature comes from the fact that Git uses three commits to generate the merge commit: the two branch tips and their common ancestor.

How do I revert to a previous merge commit?

You can use the Git reset command to undo a merge. Firstly, you need to check for the commit hash (or id) so you can use it to go back to the previous commit. To check for the hash, run git log or git reflog . git reflog is a better option because things are more readable with it.


1 Answers

Updated answer: My original version of the script below was flawed in the sense that $conflicting_files in fact did not contain only the files that really had conflicts, but all files that were changed in both parent branches (but not necessarily had conflicts). Also, it was not using "the configured merge tool" as advertized in the rationale, but diffuse. I've addressed both issues in the current version of the script.

Original answer: Let's say we have a "master" branch with the main development going on, and a "topic" branch which adds some feature on top of some (older) state of master. By saying that you're looking for just the files changed in the merge commit I assume you're only interested in the changes "topic" introduced to "master" in the merge commit (including any conflict resolution), not in the non-conflicting changes that were done in "master" since "topic" was branched. Further assuming that "master" is the first parent of your merge commit and "topic" is the second, this can be achieved with

git difftool <merge commit>^1 <merge commit> 

Note that it does not make sense to use a 3-way diff here as we are looking at the state that includes any conflict resolution. This is also what GitHub is showing for merge commits, by the way, see e.g. this merge commit which I have used for testing.

To see only the conflicting files and their resolutions in a 3-way diff tool I came up with this script

#!/bin/sh  if [ $# -ne 1 ]; then     echo "Rationale : Show the conflict resolution of a given merge commit in the configured merge tool."     echo "Usage : $(basename $0) <merge commit>"     exit -1 fi  # Test e.g. with https://github.com/git/git/commit/8cde60210dd01f23d89d9eb8b6f08fb9ef3a11b8 our=$1^1 their=$1^2 base=$(git merge-base $our $their)  conflicting_files=$(git merge-tree $base $our $their | grep -A 3 "changed in both" | grep "base" | grep -Po "[^\s]+$") for f in $conflicting_files; do     diffuse -r $our -r $base -r $their $f done 

I'm using Diffuse instead of Beyond Compare because the first can work directly on Git commits as opposed to local files; change the order of arguments to your liking. To use BC, you probably would need to do temporary checkouts; I was also thinking about redoing the merge, applying the known resolution, and run what ever git mergetool is configured, but both of these ideas would require more work to not clutter your working tree and to do the clean up properly.

like image 106
sschuberth Avatar answered Sep 18 '22 12:09

sschuberth