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.
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.
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.
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:
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With