Tuesday, September 29, 2009

Patching SVN: Hunk Failed Happens

Hunks Are Failing...

I see everywhere how to patch working copies using the patch command, with an input of a file created using svn diff. As it goes:

svn diff > iamtheschmitzer.patch


then in a different working copy, apply the patch

patch -p0 < iamtheschmitzer.patch


Not so fast. Getting this error:

Hunk #1 FAILED at 2.


I submitted some rather large patches to Connect yesterday, and they appear to be useless. Every hunk is failing.

I looked into the problem, and patch with -p0 does not seem to work well. I did get patches created for -p1 to work properly.

What am I talking about? A unified diff file gives a patch to the file in question. Patch allows the user to specify how many levels of that directory structure to ignore, with the -p argument. -p0 hasn't worked for me (Debian).

So if your working copy is C:\Projects\NHINC\Current\Product

you should start in C:\Projects\NHINC\Current

and issue the command:

svn diff Product > GATEWAY-17.patch


and it should be applied with -p1, but still from within the working directory

patch -p1 < GATEWAY-17.patch


Finally, patch does not like DOS-style CRLF line endings. Both the patch file and the source file will need to be in unix format to work properly. This whole mess is scripted like this:

# assumes a -p1 patch
PATCH=$1

# patch does not like Windows newlines
echo "Transforming $PATCH to unix"
dos2unix $PATCH


# patch does not like Windows newlines
# modify the target files to unix
for file in `grep Index: $PATCH | sed 's/Index: [^/]*\///'`
do
echo $file
echo "Transforming $file to unix"
dos2unix $file
done

echo "Applying patch file"
patch --verbose -p1 < $PATCH

# patch does not like Windows newlines
# modify the target files to back to Windows
for file in `grep Index: $PATCH | sed 's/Index: [^/]*\///'`
do
echo "Transforming $file to dos"
unix2dos $file
done


Patching Existing Patch Files

Oh lucky you. You have existing patch files, which you can't apply. It's easy to fix with a simple sed script. The file names must have one level of directory structure prepended to them.

Here is a sed script to do it for you:
s/^\(Index:\) /\1 ignoreme\//
s/^\(---\) /\1 ignoreme\//
s/^\(+++\) /\1 ignoreme\//


Save this in a file like fixpatch.sed and run this with

cat mybroken.patch | sed -f fixpatch.sed > myworking.patch


Then apply myworking.patch with patch -p1.

And if this post helped you, leave a comment, link to my blog, or thank @iamtheschmitzer on Twitter.

No comments: