git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: Improving merge of tricky conflicts

From
Jeff King <peff@peff.net>
Date
Jul 23, 2020, 18:25 UTC
Message-ID
<20200723182549.GB3975154@coredump.intra.peff.net>
In-Reply-To
<xmqqmu3r5umr.fsf@gitster.c.googlers.com>
On Wed, Jul 22, 2020 at 10:26:04AM -0700, Junio C Hamano wrote:
Show 15 quoted lines
> > The big downside here, of course, is that it's showing the diff for the
> > whole file, not just one hunk (on the other hand, I often find the
> > trickiest conflicts are ones where the changes unexpectedly span
> > multiple hunks).
> 
> Yup, I often find myself comparing the base part (lines between |||
> and ===) with our part (lines between <<< and |||) and their part
> (lines between === and >>>) while looking at the diff3 output to see
> what unique change each side did, in order to come up with a
> conflict resolution.
> 
> I do this often enough to wonder if I should write a small "filter"
> that I can pipe a whole "diff3" <<< ... ||| ... === ... >>> region
> to and convert it into to diffs, but not often enough to motivate
> me to actually write one ;-).

I would definitely have found that useful before (usually when one side made a tiny one-line change and the other side deleted or drastically changed a huge chunk).

It might even be possible to stuff it into xdiff's fill_conflict_hunk(). We have all of the data there, and xdiff in theory can make diffs. :) It might be easier to prototype it as an external filter, though.

Something like the script below seems to work; you can run whole files through it, or do something like ":10,20r!perl foo.pl" in vim to filter a snippet. I won't be at all surprised if somebody more familiar with vim tells me that you can already do something way better than this (I've always found vimdiff pretty confusing).

-- >8 -- #!/usr/bin/perl

use File::Temp; use strict;

my (@base, @ours, @theirs); my $state;

sub flush {
  print @ours;
  print "|||||||\n";
  show_diff(base => \@base, ours => \@ours);
  print "|||||||\n";
  show_diff(base => \@base, theirs => \@theirs);
  print "=======\n";
  print @theirs;
  @ours = @base = @theirs = ();
}
sub show_diff {
  my ($pre_name, $pre_data, $post_name, $post_data) = @_;
  my $pre = File::Temp->new;
  print $pre @$pre_data;
  $pre->flush;
  my $post = File::Temp->new;
  print $post @$post_data;
  $post->flush;
  open(my $diff, '-|', qw(diff -u), $pre->filename, $post->filename);
  # throw away file header, which just mentions tempfiles, and replace
  # it with our own
  <$diff>; <$diff>;
  print "--- $pre_name\n";
  print "+++ $post_name\n";
  while (<$diff>) {
    print;
  }
}
sub state_none {
  if (/^<{7}/) { $state = \&state_ours }
  print
}
sub state_ours {
  if (/^\|{7}/) { $state = \&state_base }
  else { push @ours, $_ }
}
sub state_base {
  if (/^={7}/) { $state = \&state_theirs }
  else { push @base, $_ }
}
sub state_theirs {
  if (/^>{7}/) { flush(); print; $state = \&state_none }
  else { push @theirs, $_ }
}
$state = \&state_none;
while (<>) {
  $state->();
}
Previous: Junio C HamanoNext: Junio C Hamano
Message 5 of 25 in “Improving merge of tricky conflicts”
  1. B. SteblerJul 21, 2020
  2. Johannes SixtJul 22, 2020
  3. Jeff KingJul 22, 2020
  4. Junio C HamanoJul 22, 2020
  5. Jeff KingJul 23, 2020
  6. Junio C HamanoJul 24, 2020
  7. Jeff KingJul 24, 2020
  8. Junio C HamanoJul 24, 2020
  9. Martin von ZweigbergkJan 16, 2021
  10. Jeff KingJan 21, 2021
  11. Martin von ZweigbergkJan 21, 2021
  12. Jeff KingJan 21, 2021
  13. Sergey OrganovJul 22, 2020
  14. Junio C HamanoJul 22, 2020
  15. Sergey OrganovJul 22, 2020
  16. Jeff KingJul 23, 2020
  17. Sergey OrganovJul 23, 2020
  18. Junio C HamanoJul 23, 2020
  19. Jacob KellerJul 24, 2020
  20. Junio C HamanoJul 24, 2020
  21. Sergey OrganovJul 24, 2020
  22. Junio C HamanoJul 24, 2020
  23. Sergey OrganovJul 24, 2020
  24. Junio C HamanoJul 24, 2020
  25. Bono SteblerJul 22, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.