This question shows many good ways to use git-mergetool
to show the condition of files before a merge commit using meld
:
Setting up and using Meld as your Git difftool and mergetool
I like the three-panel form with $BASE
in the middle panel.
When I inspect the result of a merge after a commit I'd like to see about the same thing, but with the results of the merge ($MERGED
of git-mergetool
) in the middle pane.
Is there any existing way to coax git into showing this, or do I need to roll my own? Note that I'm not interested in the "combined" diff offered by e.g. git show
.
Here's a script that does it for an individual file which is enough for me. It wouldn't be hard to generalize to dirs.
#!/usr/bin/perl -w
# Given a two-parent merge <commit> and a path to a non-dir file in
# the repo, show the merge of that file in the commit in meld as a
# 3-way diff (symmetric to what `get mergetool --tool meld' shows
# before the merge, i.e. with the finished $MERGED result where $BASE
# would be in the mergetool display). This follows from this question:
# https://stackoverflow.com/questions/34119866/setting-up-and-using-meld-as-your-git-difftool-and-mergetool
#
# The idea is to work around the fact that git mergetool is aware of
# diff3-type features of e.g. meld but all the git-diff stuff (including
# git-difftoot and git-show) is determinedly unaware and instead shows
# various worse 2-pane renderings of what happened.
@ARGV == 2 or die "wrong number of arguments";
my ($commit, $path) = @ARGV;
# Trees aren't supported yet
`git cat-file -t $commit:$path` eq "blob\n"
or die "git cat-file -t doesn't think $commit:$path is a blob";
# Use our own subdir of /tmp to avoid littering /tmp too much
my $tdd = "/tmp/show_merge_with_3_pane_meld.perl.scratch";
-d $tdd or mkdir $tdd or die "mkdir $tdd failed: $!";
# Unpack versions of file into temporary files
my $cap = `git rev-list -n 1 --parents $commit`; # Commit And Parents
$? == 0 or die "git rev-list command failed";
my @cap = map { chomp $_; $_ } split(' ', $cap);
@cap == 3
or die "unexpected number of words in rev-list output, maybe $commit is ".
"not a two-parent merge commit?";
my %cap = ( merged => $cap[0], p1 => $cap[1], p2 => $cap[2] );
my %tf = (); # Temp Files (final names in $tdd to be given to meld)
while ( my ($key, $val) = each %cap ) {
my $tfn = `git unpack-file $val:$path`; # Temp File Name
$? == 0 or die "git unpack-file command failed";
chomp($tfn);
# Verify temp file name form from git-unpack-file and save random part
$tfn =~ m/^\.merge_file_(.*)$/
or die "git unpack-file output doesn't match the expected pattern";
my $tfn_rp = $1; # Temp File Name Random Part
my $otfn = "$key.$tfn_rp"; # Our Temp File Name
# Move to our dir, rename
not system("mv $tfn $tdd/$otfn") or die "mv command failed";
$tf{$key} = $otfn;
}
# Display the merge
not system("cd $tdd && meld $tf{p1} $tf{merged} $tf{p2}")
or die "cd or meld command failed";
# Uncomment if clean-up of temp files is desired
#unlink(map { "$tdd/$_" } values(%tf)) == 3 or die;