diff-match-patch
diff-match-patch copied to clipboard
Reverse/Unpatch capability
Is there any possibility of reversing a diff/patch, or unpatch
, to go backwards?
For example:
LinkedList<DiffMatchPatch.Diff> diffA_B = diffMatchPatch.diffMain(a, b);
LinkedList<DiffMatchPatch.Patch> patchA_B = diffMatchPatch.patchMake(a, diffA_B);
String rebuiltA = (String) diffMatchPatch.patchApply(patchBToA, b)[0];
// unapply
String rebuiltB = (String) diffMatchPath.unpatch(patchBToA, rebuiltA)[0];
From what I can gather, there may not be enough information in the diff/patch to unapply, but I was hoping to see if this was suggested in the past or if there is an alternate approach to reversing a diff/patch without having to create a new diff/patch from B -> A.
Thanks!
@mgagliardo91 I was able to achieve this by simply changing DELETE operations in my diff to INSERT operations, and vice versa. In this (Java) example I am able to get back to the original string by applying the reversed patch.
public static void main(String[] args) {
DiffMatchPatch diffMatchPatch = new DiffMatchPatch();
String a = "some text";
String b = "this is some text that is different";
LinkedList<DiffMatchPatch.Diff> diffAToB = diffMatchPatch.diffMain(a, b);
LinkedList<DiffMatchPatch.Diff> diffBToA = reverseDiff(diffAToB);
LinkedList<DiffMatchPatch.Patch> patchBToA = diffMatchPatch.patchMake(diffBToA);
String rebuiltB = (String) diffMatchPatch.patchApply(patchBToA, b)[0]; //unapply
System.out.println(rebuiltB); //prints out "some text"
}
private static LinkedList<DiffMatchPatch.Diff> reverseDiff(LinkedList<DiffMatchPatch.Diff> diffs) {
for(DiffMatchPatch.Diff diff : diffs) {
if(diff.operation == DiffMatchPatch.Operation.DELETE) {
diff.operation = DiffMatchPatch.Operation.INSERT;
}
else if(diff.operation == DiffMatchPatch.Operation.INSERT) {
diff.operation = DiffMatchPatch.Operation.DELETE;
}
}
return diffs;
}
Hopefully that's helpful to you. It would be nice to have an easier way to do this.
@davidhorton thanks 👍 From what I remember, an operation such as REPLACE
lost information of what was being replaced, so I couldn't determine how to get that data back when attempting an unapply
. It's been some time now, so that may have been with a different diff library, but I believe it was here.
@mgagliardo91 Maybe you can store reverse deltas instead? Instead of diffMain(a, b) you could do diffMain(b, a)
I think I've found a more space efficient solution than storing 2 patches. You not only have to reverse all DELETE
's to INSERT
's and vice versa, but you also need to swap the length1
<-> length2
and start1
<-> start2
of each patch to make it work correctly. I haven't been able to find an example where the reverse patch fails to apply correctly to the second text to get the first one:
const reversePatch = patch => {
return patch.map(patchObj => ({
diffs: patchObj.diffs.map(([ op, val ]) => [
op * -1, // The money maker
val
]),
start1: patchObj.start2,
start2: patchObj.start1,
length1: patchObj.length2,
length2: patchObj.length1
}));
};