Update (July 30, 2008): I added information about making sure that the patch was successful.
When you install a big-ass web application such as WordPress or MediaWiki, you usually end with a bunch of configuration files and customizations (skins/themes, extension/plugins, uploads, etc.). This makes upgrading the files that come with the application a bit tricky. There’s a simple solution, however, which work regardless of whether you use a revision control system or not.
First of all, you do, of course, always need a revision control system. I personally recommend Git or Subversion, which are both excellent tools. But, that’s not what this post is about. I’m going to use two simple tools which are uniformly available on all (Unixy) platforms: diff and patch.
The procedure is simple:
Download the version of the application which you’re currently running. For our example, we pretend that this version is extracted into the directory webapp-1.4.3.
Then, download the version to which you’d like to upgrade. (We’re assuming that this version is extracted into the webapp-1.6.2 directory.)
Compare the two versions to create a patch file:
$ diff --unified --recursive --new-file webapp-1.4.3 webapp-1.6.2 > webapp-upgrade.diff
Apply the patch to the installation of said web app:
$ cd webapp-installed $ patch --strip=1 --remove-empty-files < ../webapp-upgrade.diff || echo "Some failures!"
Check if everything was patched perfectly
Now, if the patch command returned a non-zero status (printing Some failures!
in the above example), it's time to check which chunks of which files failed. Get a summary by searching all files with an .rej
or a .orig
suffix:
$ find . -name "*.rej"
After manually applying any failed hunks, what's left is to compare your directory containing the patched application to the directory with the contents of the new application archive which you've used to create the patch:
$ cd .. $ diff --unified --recursive --new-file webapp-1.6.2 webapp-installed
Version management
Your upgrade is done. Now, if your using a revision control system, you just need to check in new files and check out deleted files. In Subversion, I do this quickly using the following command sequence:
$ svn status|sed -e '/^\?/!d; s/^\?//'|xargs svn add $ svn status|sed -e '/^\!/!d; s/^\!//'|xargs svn del
If you'd been using Git, you could do this all a little bit more sophisticatedly, but my Git skills are not advanced enough to go around giving others advice. Also, it's nice to learn a generic method before learning more specific tools.
I just used diff and patch to upgrade a messy, old version of the Simple Tags plugin in this WordPress installation to a newer version.
I noticed that this still left a lot of old files hanging around, the same problem as I’ve had the previously with this method. Also, some files wouldn’t get patched. Instead of being mystified by this failure again, I realized that diff and patch simply can’t deal with binary files (beyond reporting whether they differ or not).
Now I’m writing a simple script to use for future updates of this type. It’s not that I need to be able to save space by storing just the differences or anything fancy like that. It’s just that I can’t replace the contents of the old directory with those of the new version, because Subversion insists on keeping those annoying .svn subdirs everywhere in your working copy.