Programmatically display all git rerere resolutions used during merge

662 views Asked by At

When doing a merge with rerere enabled, and all conflicts are resolved with rerere, it just prints something like:

Resolved 'a.c' using previous resolution.
Resolved 'b.c' using previous resolution.
Resolved 'c.c' using previous resolution.

I would like to see the before diff (with conflict markers) and after resolution diff. I know I can do:

git checkout -m a.c
git diff
git rerere
git diff
git checkout -m b.c
git diff
git rerere
git diff
...

to kind of see the pre/post images it's using for each resolution. But is there some way to retrieve that information, or the rerere fingerprints used, without manually parsing the git merge hash output for each Resolved X using previous resolution. message.

2

There are 2 answers

0
Adam On

It feels like you're looking to compare ours, theirs and resolution. From here it seems that git diff will refuse to compare 3 files. I've amended the example from that post to provide this example;

git diff --name-only master feature |\
    xargs -I % bash -c "diff3 <( git show master:% ) <( cat % ) <( git show feature:% )"

The output from diff3 is more complicated but it's a complicated thing that you're doing.

Replication Steps

Initialise the repo.

Horba@cake ~ $ git init MergeDiff/
Initialized empty Git repository in /home/Horba/MergeDiff/.git/
Horba@cake ~ $ cd MergeDiff/
Horba@cake ~/MergeDiff $ vim README.md
Horba@cake ~/MergeDiff $ git add README.md 
Horba@cake ~/MergeDiff $ git commit -m "Init."
[master (root-commit) 5250b3f] Init.
 1 file changed, 3 insertions(+)
 create mode 100644 README.md
Horba@cake ~/MergeDiff $ git branch feature
Horba@cake ~/MergeDiff $ git config rerere.enabled true
Horba@cake ~/MergeDiff $ git config rerere.autoupdate true
Horba@cake ~/MergeDiff $ vim README.md 
Horba@cake ~/MergeDiff $ git add README.md
Horba@cake ~/MergeDiff $ git commit -m "Work on master."
[master 8c12c43] Work on master.
 1 file changed, 1 insertion(+), 1 deletion(-)
Horba@cake ~/MergeDiff $ git checkout feature
Switched to branch 'feature'
Horba@cake ~/MergeDiff $ vim README.md
Horba@cake ~/MergeDiff $ git commit -m "Work on feature."
[feature 4b8ad3d] Work on feature.
 1 file changed, 1 insertion(+), 1 deletion(-)
Horba@cake ~/MergeDiff $ git checkout master
Switched to branch 'master'

Conduct the initial merge.

Horba@cake ~/MergeDiff $ git merge feature 
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Recorded preimage for 'README.md'
Automatic merge failed; fix conflicts and then commit the result.
Horba@cake ~/MergeDiff $ cat README.md
# MergeDiff

<<<<<<< HEAD
Init - master changes
=======
Init - Work on feature
>>>>>>> feature

Store a resolution.

Horba@cake ~/MergeDiff $ vim README.md
Horba@cake ~/MergeDiff $ git rerere
Recorded resolution for 'README.md'.
Horba@cake ~/MergeDiff $ cat README.md
# MergeDiff

Init - Resolved
Horba@cake ~/MergeDiff $ git merge --abort

Merge again using rerere.autoupdate.

Horba@cake ~/MergeDiff $ git merge feature 
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Staged 'README.md' using previous resolution.
Automatic merge failed; fix conflicts and then commit the result.
Horba@cake ~/MergeDiff $ cat README.md
# MergeDiff

Init - Resolved
Horba@cake ~/MergeDiff $ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    modified:   README.md

Traditional diff doesn't help.

Horba@cake ~/MergeDiff $ git diff feature master HEAD
diff --cc README.md
index ca2c305,ca2c305..24b898d
--- a/README.md
+++ b/README.md
@@@ -1,3 -1,3 +1,3 @@@
  # MergeDiff

--Init - master changes
++Init - Work on feature

diff3 can do it.

Horba@cake ~/MergeDiff $ diff3 <(git show master:README.md) <(git show feature:README.md) <( cat README.md )
====1
1:1,3c
  # MergeDiff

  Init - master changes
2:0a
3:0a
====2
1:6c
3:3c
  Init - Resolved
2:3c
  Init - Work on feature
0
ElpieKay On

The postimage and preimage are stored in .git/rr-cache/$hex. After the auto-merge is done, we have a file whose content is the same with the postimage.

Here is a quick and dirty bash function to print the preimage of X, or the diff between HEAD's version and the preimage. A side effect is that dangling blobs will be created.

# input: file path
# output: the preimage with conflict markers, 
#         or the diff between HEAD's version and the preimage. 
#         If the file path does not exist in rerere cache, return nothing.
function foo(){
    p=$1
    current=`git hash-object $p`
    for hex in `ls .git/rr-cache`;do
        posthash=`git hash-object .git/rr-cache/$hex/postimage`
        if [ "$posthash" = "$current" ];then
            git diff HEAD:$p $(git hash-object -w .git/rr-cache/$hex/preimage)
            # To print the preimage
            #cat .git/rr-cache/$hex/preimage
            return
        fi
    done
}

foo a.c