#!/usr/bin/perl -w # # git-me-backwards -- convert a git patch to a regular patch # Copyright (C) 2006 Lennert Buytenhek # # sub parse_hunk { my $hunk = shift; my $removed_or_identical; my $added_or_identical; die "corrupt hunk" unless ($hunk =~ /\@\@ -\d+,(\d+) \+\d+,(\d+) \@\@/); $removed_or_identical = $1; $added_or_identical = $2; while ($removed_or_identical > 0 or $added_or_identical > 0) { my $line; $line = ; die "corrupt hunk" if not defined $line; $hunk .= $line; if ($line =~ /^-/) { $removed_or_identical--; } elsif ($line =~ /^\+/) { $added_or_identical--; } else { $removed_or_identical--; $added_or_identical--; } } die "corrupt hunk" if ($removed_or_identical or $added_or_identical); return $hunk; } my $currentline; sub parse_patch { my $from; my $to; my $patch; $currentline =~ /^--- (.*)$/ or return; $from = $1; $currentline = ; die "corrupt patch" if not defined $currentline; $currentline =~ /^\+\+\+ (.*)$/ or die "corrupt patch"; $to = $1; $currentline = ; while (defined $currentline) { last if ($currentline !~ /^\@\@ /); $patch .= parse_hunk($currentline); $currentline = ; } return ($from, $to, $patch); } my $in_diff_header; my $from; my $to; my $copying; my $renaming; $currentline = ; $in_diff_header = 0; while (defined $currentline) { if ($currentline =~ /^diff --git a\/(\S+) b\/(\S+)/) { $currentline = ; $in_diff_header = 1; $from = $1; $to = $2; $copying = 0; $renaming = 0; next; } if (not $in_diff_header) { print $currentline; $currentline = ; next; } if ($currentline =~ /^copy /) { $currentline = ; $copying = 1; next; } # if ($currentline =~ /^deleted /) { # $currentline = ; # next; # } # if ($currentline =~ /^new /) { # $currentline = ; # next; # } if ($currentline =~ /^rename /) { $currentline = ; $renaming = 1; next; } if ($currentline =~ /^index /) { my $hdrfrom; my $hdrto; my $patch; $currentline = ; $in_diff_header = 0; ($hdrfrom, $hdrto, $patch) = parse_patch(); if (not $copying and not $renaming) { if (defined $hdrfrom) { print "diff -u a/$from b/$to\n"; print "--- a/$from\n"; print "+++ b/$to\n"; print $patch; } next; } if ($renaming) { # delete original print "diff -u a/$from b/$from\n"; print "--- a/$from\n"; print "+++ b/$from\n"; system "diff -up $from /dev/null | tail +3"; } if (not defined $from) { # create new print "diff -u a/$to b/$to\n"; print "--- a/$to\n"; print "+++ b/$to\n"; system "diff -up /dev/null $from | tail +3\n"; next; } system "cp $from /tmp/mergetemp"; open PATCH, "| patch --quiet /tmp/mergetemp"; print PATCH "diff -u $hdrfrom $hdrto\n"; print PATCH "--- $hdrfrom\n"; print PATCH "+++ $hdrto\n"; print PATCH $patch; close PATCH; print "diff -u a/$to b/$to\n"; print "--- a/$to\n"; print "+++ b/$to\n"; system "diff -up /dev/null /tmp/mergetemp | tail +3\n"; unlink "/tmp/mergetemp"; next; } $currentline = ; }