Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Permanently reversing a patch-file

Tags:

linux

diff

patch

Sometimes, for whatever reason, I have to produce patch-files (under Linux) that are in the wrong direction. I know that I can deal with this by using the -R switch when applying it via patch, but it would be nice if there were a way of permanently reversing the patch-file. Is there a utility that can do this, or e.g. a regex that would be guaranteed to work?

UPDATE

Lie Ryan has suggested a neat way of doing this. However, it requires access to the original source file(s). So I suppose I should update my question to state that I'm more after a way of achieving this given only the patch-file itself.

like image 476
Oliver Charlesworth Avatar asked Oct 10 '10 22:10

Oliver Charlesworth


People also ask

How do I reverse a patch file?

Reverse a Patch that is Already Applied (Undo a Patch) You can use the -R option to reverse a patch which is applied already. You can notice from the filesize, that the patch, which is applied already is reversed when we used the -R option.


2 Answers

You can use the tool interdiff(1) from patchutils. In particular, the man page for interdiff says:

To reverse a patch, use /dev/null for diff2.

So,

$ interdiff -q file.patch /dev/null > reversed.patch 

The -q / --quiet prevents the insertion of reverted: lines.

like image 180
camh Avatar answered Sep 25 '22 02:09

camh


Try:

patch -R file.txt file.patch diff file.txt.orig file.txt > file.patch.rev // you can then `rm file.txt.orig file.patch` 

EDIT:

To reverse a unified diff, you need to change three things:

  • the patch header
  • the chunk header
  • the + to - and - to +

So here's how a patch header for a looks like:

--- b.asm   2010-09-24 12:03:43.000000000 +1000     +++ a.asm   2010-09-24 23:28:43.000000000 +1000 

you need to reverse it so it looks like this:

--- a.asm   2010-09-24 23:28:43.000000000 +1000 +++ b.asm   2010-09-24 12:03:43.000000000 +1000     

basically switch the order, and switch +++ to --- and vice versa.

Next, the chunk header:

@@ -29,5 +27,7 @@ 

You need to reverse the numbers, so it look like this:

@@ -27,7 +29,5 @@ 

basically, switch the number pairs

and last, switch every line beginning with + and every line beginning with -.

EDIT:

to switch the chunk header, you can do:

sed -e "s/@@ -\([0-9]\+,[0-9]\+\) +\([0-9]\+,[0-9]\+\) @@/@@ -\2 +\1 @@/" 

to switch + to - and - to +, you can do:

sed -e "s/^+/P/" -e "s/^-/+/" -e "s/^P/-/" 

FINALLY:

to reverse the patch header, do:

head -2 orig.diff | tac | sed -e "s/+++/PPP/" -e "s/---/+++/" -e "s/PPP/---/" > head tail orig.diff -n+3 > tail cat head tail > headtail rm head tail 

So, finally, our (quick and dirty) script looks like:

#!/usr/bin/env sh F="$1" head -2 $F | tac | sed -e "s/+++/PPP/" -e "s/---/+++/" -e "s/PPP/---/" > $F.head tail $F -n+3 | sed -e "s/@@ -\([0-9]\+,[0-9]\+\) +\([0-9]\+,[0-9]\+\) @@/@@ -\2 +\1 @@/" -e "s/^+/P/" -e "s/^-/+/" -e "s/^P/-/" > $F.tail cat $F.head $F.tail  rm $F.head $F.tail 

I tested it, and it seems to work.

though, to make things more maintainable, and cleaner:

#!/usr/bin/env sh swap() {     sed -e "s/^$1/PPP/" -e "s/^$2/$1/" -e "s/^PPP/$2/" } file_header() {     head -2 $1 | tac | swap +++ --- } fix_chunk_header() {     sed -e "s/@@ -\([0-9]\+,[0-9]\+\) +\([0-9]\+,[0-9]\+\) @@/@@ -\2 +\1 @@/"  } fix_lines() {     swap + - } file="$1" file_header $file tail $file -n+3 | fix_chunk_header | fix_lines 
like image 38
Lie Ryan Avatar answered Sep 24 '22 02:09

Lie Ryan