How to git-apply a git word diff
Asked Answered
F

1

11

I needed to edit a messy commit commit that only changed a word in a few subsequent rows, keeping some of those changes and removing others. The changes were easy to see in git diff --word-diff, and in that format I could easily edit the hunks to do what I intended to do, but now I have a file like this

diff --git a/cldf/forms.csv b/cldf/forms.csv
index 46c12a4..0374ece 100644
--- a/cldf/forms.csv
+++ b/cldf/forms.csv
@@ -1783,8 +1783,8 @@ ID,Lect_ID,Concept_ID,Form_according_to_Source,Form,Local_Orthography,Segments,C
1782,adan1251-lawah,day,dilɛlɛ,dilɛlɛ,dilele,d i l ɛ l ɛ,Lit. 'all day'.,datasets_Adang_Lawahing_tsv
1783,adan1251-lawah,day,wɛd saha,wɛd_saha,wed saha,w ɛ d _ s a h a,midday' lit. 'hot sun',datasets_Adang_Lawahing_tsv
1784,adan1251-lawah,morning,lalami,lalami,lalami,l a l a m i,,datasets_Adang_Lawahing_tsv
1785,adan1251-lawah,yesterday,ʔu:mi,ʔuːmi,[-umi-]{+'umi+},ʔ uː m i,,datasets_Adang_Lawahing_tsv
1786,adan1251-lawah,day_before_yesterday,ʔotariŋ alumi,ʔotariŋ_alumi,[-otaring-]{+'otaring+} alumi,ʔ o t a r i ŋ _ a l u m i,,datasets_Adang_Lawahing_tsv
1787,adan1251-lawah,tomorrow,dilɛlɛ,dilɛlɛ,dilele,d i l ɛ l ɛ,,datasets_Adang_Lawahing_tsv
1788,adan1251-lawah,day_after_tomorrow,a:lu,aːlu,alu,aː l u,,datasets_Adang_Lawahing_tsv
1789,adan1251-lawah,twilight_dawn,lalami,lalami,lalami,l a l a m i,"(lit, 'early morning')",datasets_Adang_Lawahing_tsv

which I would like to use as a patch for git apply.

However, vanilla git apply words.diff fails with a fatal: corrupt patch at line 6 – a normal diff file would start with a space in that unaffected line – and I don't see anything that might make git apply accept a word-diff file in its manpage.

How can I convince git apply to take a file of this format as patch? Or how can I easily convert this file into a valid patch?

Federalize answered 15/2, 2019 at 11:19 Comment(2)
I have the same question, so I put a bounty on this one. I will also award the bounty to an answer that shows how to convert the word-diff to a normal diff that can subsequently be applied.Neff
You should check user405725's answer here #8280102 . He explained patches I quite a detail which might give you better insight.Prominent
U
7

I couldn't find a working solution, so I've put together a script that converts word-diff into a regular diff that can be applied:

#!/usr/bin/env perl
# convert-word-diff.pl -- rev. 2, this script is licensed under WTFPLv2

my (@minus, @plus);

sub flush_diff {
  print join("", map { "-$_" } @minus);
  print join("", map { "+$_" } @plus);
  @minus = (); @plus = ();
}

while (my $line = <>) {
  if ($line =~ /^(?:index |diff |\+\+\+ |\-\-\- |@@ )/) {
    flush_diff();
    print $line;
    next;
  }

  my $is_diff_line;

  if ($line =~ /\[\-.*\-\]/ || $line =~ /\{\+.*?\+\}/) {
    my $copy = $line;
    $copy =~ s/\[\-(.*?)\-\]\{\+.*?\+\}/\1/g;
    $copy =~ s/\[\-(.*?)\-\] ( )?/ \1 /g;
    $copy =~ s/\{\+.*?\+\} ?//g;
    push(@minus, $copy);

    $copy = $line;
    $copy =~ s/\[\-.*?\-\]//g;
    $copy =~ s/\{\+(.*?)\+\}/\1/g;
    push(@plus, $copy);
    $is_diff_line = 1;
  }

  unless ($is_diff_line) {
    flush_diff();
    print " $line" ;
  }
}

flush_diff();

Usage:

cat word-diff.txt | perl convert-word-diff.pl | git apply

Hopefully I didn't mess up anything and you are on Linux/Mac and have Perl. :-)

Uninspired answered 11/5, 2019 at 13:29 Comment(7)
@HenriMenke would it be possible for you to share the patch or create a similar patch with dummy data?Uninspired
@HenriMenke OK, after double checking I have found some issues. I've updated the answer with fixed rev. 2 of the converter :-)Uninspired
I'm still getting a corrupt patch but I awarded the bounty anyway to acknowledge your efforts.Neff
@HenriMenke how have you obtained the word-diff? Is there any chance you've edited it manually? It's actually not very straightforward to correctly edit manually :-) I'd appreciate if you could share your diff so that we can fix either the script or the diff.Uninspired
I did git show -w --word-diff on this commit because I wanted to get rid of the excessive reformatting.Neff
@HenriMenke oh, that's interesting. It seems word-diff isn't convertible to regular diff without the converter looking at the unmodified code. Word-diff is empty on the lines where indentation was changed. OK, I'll see if I can fix that in rev3 :-)Uninspired
problem: git diff --word-diff is lossy: printf 'a\n' >a.txt; printf 'a b\n\n' >b.txt; git diff --word-diff=plain --word-diff-regex=. a.txt b.txtShrievalty

© 2022 - 2024 — McMap. All rights reserved.