Applying a patch which introduces new directories

Applying a patch using patch(1) can fail if it contains patches to files in non-existing directories.

This situation can happen, for instance, when you work in a git repository and commit a subdirectory with some files in it, then squash all your commits into a single commit using git rebase -i and finally create a diff file using git format-patch.

In my case I had to apply my work done in a git repository on top of a subversion branch. During the development I added tons of test fixtures in a fixtures/ directory. But when applying the final patch on top of the subversion branch my test fixtures all ended up in the root directory overwriting each other as that’s what patch(1) does when it comes across a non-existing directory.

Solution

Assuming your diff file is called 0001-Your-Changes.patch, the following Ruby script will scan your diff file and create all neccessary directories:

cat 0001-Your-Changes.patch \
| ruby -n -E utf-8 -e \
  'puts $1.split("/")[1..].join("/")if$_=~/^[+]{3}\s(.*)$/' \
| ruby -n -r fileutils -e 'FileUtils.mkdir_p(File.dirname($_))'

Then proceed by running patch -p1 < 0001-Your-Changes.patch as usual.

Check the -n command line option of ruby(1), which behaves similar to sed and awk.