I eventually solved this using a solution similar to artyom's.
Step 1: Explode the patch into lots of separate patches, one for each hunk.
I used this script to do this:
#!/usr/bin/python2
import sys
header = []
writing_header = False
patchnum = 0
patch = open(sys.argv[1], "r")
out = open("/dev/null", "w")
for line in patch.readlines():
if line.startswith("diff"):
header = []
writing_header = True
if line.startswith("@@"):
out.close()
out = open(str(patchnum) + ".diff", "w")
patchnum += 1
writing_header = False
out.writelines(header)
if writing_header:
header.append(line)
else:
out.write(line)
out.close()
Example usage:
$ cd directory_containing_patch
$ mkdir foo
$ cd foo
$ explode.py ../huge_patch.diff
This will populate the current directory with files called 0.diff 1.diff et cetera.
Step 2: Apply each patch, discarding already applied patches.
I used this script to do this:
#!/bin/bash
if [[ $# -ne 1 || ! -d "${1}/" ]]; then
echo "Usage: $0 dirname"
exit 1
fi
find "$1" -name \*.diff | while read f; do
OUTPUT=$(patch -s -p1 -r- -i"$f")
if [ $? -eq 0 ]; then
rm "$f"
else
if echo "$OUTPUT" | grep -q "Reversed (or previously applied) patch detected!"; then
rm "$f"
fi
fi
done
Example usage:
$ cd directory_containing_code
$ apply_patches.bash directory_containing_patch/foo
This will delete any of the previously generated patches that apply cleanly or that have already been applied. Any patches left in foo
are rejects that need to be manually examined and merged.