Thursday, December 06, 2007

A mercurial patch update session

We discussed patch management recently on the Kolab development mailing list and today it was time to upgrade to php-5.2.5. I had to run a patch update cycle again. Some time ago Thomas recommended using mercurial for the patch management. And I must admit that this completely changed the way I deal with code patches and it made my life a lot easier. Let me describe how I currently deal with patches when upstream delivers a new version.
Some time ago I started the patch management on php by downloading the package ...
> wget
... and unpacking it:
> tar xfj php-5.2.4.tar.bz2
Now I turned this version into a mercurial repository and added all files to version control:
> cd php-5.2.4
> hg init
> hg commit --addremove -m "php-5.2.4"
> cd ..
Since I needed to patch php I derived (cloned) a second repository from the original one:
> hg clone php-5.2.4 php-PATCHED
In order to add patches to a repository you have to activate the queue extension within mercurial:
> cat ~/.hgrc
username = Gunnar Wrobel
[extensions] =
That allows to add patches on top of a version controlled repository. This had to be activated on the php-PATCHED repository:
> cd php-PATCHED
> hg qinit -c
The -c option makes the new patch directory that got created by qinit under php-PATCHES/.hg/patches a version controlled directory. This is not strictly necessary but I find it convenient to version control the patches, too. For the Kolab specific patching one patch had to be added to php-PATCHED:
> hg qnew KOLAB_Annotation.patch
> patch -p1 < ~/Kolab-php.patch
> hg qrefresh -m "Provides get/set ANNOTATIONS support to PHP. [Version: 5.2.4]"
qrefresh compiled the changes in php-PATCHED into the KOLAB_Annotation.patch within php-PATCHES/.hg/patches. Now I was able to grab the patch from that location and apply it to the modified packages on both the OpenPKG platform and Gentoo
The whole setup would be useless if we wouldn't need to upgrade our patches from time to time. The following describes the cycle that I perform once upstream released a new version. Fetch the new version:
> wget
Now we clone the original version ...
> hg clone php-5.2.4 php-5.2.5
... and replace it with the new one:
> cd php-5.2.5
> hg locate -0 | xargs -0 rm
> cd ..
> tar xfj php-5.2.5.tar.bz2
> cd php-5.2.5
> hg commit --addremove -m "php-5.2.5"
> cd ..
Now the original repository holds the new version and we need to update our patched version to this. For this we first need to remove all applied patches since we don't know if they apply any longer:
> cd php-PATCHED
> hg qpop -a
qpop -a removes all currently applied patches. They are of course still present in our php-PATCHED/.hg/patches directory. But they are not applied. This allows to cleanly update our base php version now:
> hg pull ../php-5.2.5
> hg update
Pulling and updating brings the php-PATCHED directory to the php-5.2.5 version. Now we can push the stack of patches again and fix any that do not cleanly apply:
> hg qpush
In case our patch fails we need to modify the source until everything is working fine again. Often the changes will be minimal. After the updates the patch has to be refreshed:
> hg qrefresh -m "Provides get/set ANNOTATIONS support to PHP. [Version: 5.2.5]"
> hg qci -m "PHP patch for 5.2.5"
The final command runs hg commit within the php-PATCHED/.hg/patches directory. For a single patch the whole procedure might be a little bit too complicated. It is rather clean though. But the whole story gets really efficient once you have about twenty patches on an application. In that case the mercurial queue extensions comes in really handy.

No comments:

Post a Comment