Most Debian source packages are using the “3.0 (quilt)” format. This means that Debian changes to upstream files are managed in a quilt patch series. Knowledge of quilt is thus a must if you want to get involved in some serious packaging work. Don’t worry, this tutorial will teach you how to use quilt in the context of Debian packaging.
Pre-requisites
Install the packaging-dev package to get a decent set of packages to do Debian packaging. It includes the quilt package.
$ sudo apt-get install packaging-dev
What’s quilt?
Read the description of the Debian package:
Quilt manages a series of patches by keeping track of the changes each of them makes. They are logically organized as a stack, and you can apply, un-apply, update them easily by traveling into the stack (push/pop).
Quilt is good for managing additional patches applied to a package received as a tarball or maintained in another version control system. The stacked organization is proven to be efficient for the management of very large patch sets (more than hundred patches). As matter of fact, it was designed by and for Linux kernel hackers (Andrew Morton, from the -mm branch, is the original author), and its main use by the current upstream maintainer is to manage the (hundreds of) patches against the kernel made for the SUSE distribution.
The various files involved
To better understand the various quilt commands, you should have a basic idea of how the tool works. The “stack of patches” is maintained in a dedicated directory (“patches” by default, but in Debian packages we override this value to “debian/patches”). This directory contains the patch files and a “series” file that gives an ordered list of patches to apply. Example:
$ ls debian/patches/ 01_use_stdlib_htmlparser_when_possible.diff 02_disable-sources-in-sphinxdoc.diff 03_manpage.diff 06_use_debian_geoip_database_as_default.diff series $ cat debian/patches/series 01_use_stdlib_htmlparser_when_possible.diff 02_disable-sources-in-sphinxdoc.diff 03_manpage.diff 06_use_debian_geoip_database_as_default.diff
When quilt is used, it also maintains some internal files in a directory of its own (it’s named “.pc”). This directory is used to know what patches are currently applied (.pc/applied-patches) and to keep backup copies of files modified by the various patches.
Configuring quilt
Before going further, you should put this in your ~/.quiltrc
file:
for where in ./ ../ ../../ ../../../ ../../../../ ../../../../../; do if [ -e ${where}debian/rules -a -d ${where}debian/patches ]; then export QUILT_PATCHES=debian/patches break fi done
This ensures that quilt will always use “debian/patches” instead of “patches” when your current directory is within a Debian source package where debian/patches exists. If you only use quilt for debian packaging, then you can be more expedient and put a simple “export QUILT_PATCHES=debian/patches” in that file.
As a matter of personal preferences, I also have those lines in my ~/.quiltrc:
QUILT_PUSH_ARGS="--color=auto" QUILT_DIFF_ARGS="--no-timestamps --no-index -p ab --color=auto" QUILT_REFRESH_ARGS="--no-timestamps --no-index -p ab" QUILT_DIFF_OPTS='-p'
It enables syntax coloring for the output of several commands and customizes the generated patches to get rid of useless information. I recommend you to use those settings too.
Applying and unapplying patches, navigating in the stack of patches
When you already have a patch series, you can navigate in the stack of patches so that any subset of consecutive patches (starting from the bottom) can be applied. quilt series will list all patches known by quilt.
You can apply all patches with quilt push -a or unapply them all with quilt pop -a. You can also verify what patches are applied (quilt applied) or unapplied (quilt unapplied). quilt push applies the next unapplied patch (i.e. the patch returned by quilt next) and quilt pop unapplies the last applied patch (i.e. the patch returned by quilt top). You can give a patch name as parameter to quilt push/pop and it will apply/unapply all the patches required until the given patch is on the top.
Here are some examples of navigation in a quilt patch series
$ quilt series 02_disable-sources-in-sphinxdoc.diff 03_manpage.diff 06_use_debian_geoip_database_as_default.diff $ quilt applied No patches applied $ quilt next 02_disable-sources-in-sphinxdoc.diff $ quilt push Applying patch 02_disable-sources-in-sphinxdoc.diff patching file docs/conf.py Now at patch 02_disable-sources-in-sphinxdoc.diff $ quilt push Applying patch 03_manpage.diff patching file docs/man/django-admin.1 Now at patch 03_manpage.diff $ quilt applied 02_disable-sources-in-sphinxdoc.diff 03_manpage.diff $ quilt unapplied 06_use_debian_geoip_database_as_default.diff $ quilt pop -a Removing patch 03_manpage.diff Restoring docs/man/django-admin.1 Removing patch 02_disable-sources-in-sphinxdoc.diff Restoring docs/conf.py No patches applied $ quilt push 03_manpage.diff Applying patch 02_disable-sources-in-sphinxdoc.diff patching file docs/conf.py Applying patch 03_manpage.diff patching file docs/man/django-admin.1 Now at patch 03_manpage.diff $ quilt top 03_manpage.diff
Creating a new patch
If there’s no quilt series yet, you want to create the “debian/patches” directory first.
If you already have one, you need to decide where to insert the new patch. Quilt will always add the new patch just after the patch which is currently on top. So if you want to add the patch at the end of the series, you need to run “quilt push -a” first.
Then you can use quilt new name-of-my-patch.diff
to tell quilt to insert a new empty patch after the current topmost patch. In this operation quilt does almost nothing except updating the series file and recording the fact that the new patch is applied (even if still empty at this point!).
Now to add changes in this patch, you’re supposed to modify files but only after having informed quilt of your intent to modify those files. You do this with quilt add file-to-modify
. At this point quilt will make a backup copy of that file so that it can generate the final patch when you’re done with your changes. It’s quite common to forget this step and to be unable to generate the patch afterward. That’s why I recommend you to use quilt edit file-to-modify
which is a shorthand for doing quilt add and then opening the file in your favorite text editor.
If you want, you can review your work in progress with quilt diff
.
When you’re done with the changes, you should call quilt refresh to generate the patch (or to update it if it was already existing). And since you’re a good packager, you call quilt header --dep3 -e
to add DEP-3 meta-information to your patch header.
Importing an external patch
If someone else already prepared a patch, you can just import it right away with quilt import /tmp/the-patch
. If you want to import it under a better name you can use the option “-P better-patch-name”. Like quilt new, it inserts the patch after the topmost patch.
Updating patches for a new upstream version
With some luck, your patches will still apply with some offsets in line numbers (quilt displays those offsets) and sometimes with some fuzz:
$ quilt push [...] Hunk #1 succeeded at 1362 (offset 11 lines). Hunk #2 succeeded at 1533 with fuzz 1 (offset 4 lines). [...]
While offsets are nothing to worry about (it means some lines were added and/or removed before the patched part), fuzz means that patch had to ignore some context lines to find the place where to apply the changes. In that case, you need to double check that patch did the right thing because it might have made changes somewhere where it shouldn’t. Also, you’ll have to update those patches because dpkg-source doesn’t accept any fuzz.
If you’re confident that all patches are correctly applied by quilt, you can refresh them to get rid of those warnings:
$ quilt pop -a [...] $ while quilt push; do quilt refresh; done
That was for the easy case. Now let’s deal with the case where some of the patches no longer apply. There’s one case that is usually nice to have:
$ quilt push Applying patch 04_hyphen-manpage.diff patching file docs/man/django-admin.1 Hunk #1 FAILED at 194. 1 out of 1 hunk FAILED -- rejects in file docs/man/django-admin.1 Patch 04_hyphen-manpage.diff can be reverse-applied
When the patch can be reverse-applied, it means that the upstream authors included the Debian patch (or that they made the same change even though you forgot to forward the patch). You can thus get rid of it:
$ quilt delete -r 04_hyphen-manpage.diff Removed patch 04_hyphen-manpage.diff
Note that without the -r the patch is only dropped from the series file. With -r the patch file is also removed.
But there’s a less desirable case where the patch is still relevant but it doesn’t apply any longer:
$ quilt push Applying patch 01_disable_broken_test.diff patching file tests/regressiontests/test_utils/tests.py Hunk #1 FAILED at 422. 1 out of 1 hunk FAILED -- rejects in file tests/regressiontests/test_utils/tests.py Patch 01_disable_broken_test.diff does not apply (enforce with -f)
In that case, you should follow quilt’s advice to force the patch application, manually apply the parts of the patch that were rejected, and then refresh the patch.
$ quilt push -f Applying patch 01_disable_broken_test.diff patching file tests/regressiontests/test_utils/tests.py Hunk #1 FAILED at 422. 1 out of 1 hunk FAILED -- saving rejects to file tests/regressiontests/test_utils/tests.py.rej Applied patch 01_disable_broken_test.diff (forced; needs refresh) $ vim tests/regressiontests/test_utils/tests.py $ quilt refresh Refreshed patch 01_disable_broken_test.diff
Other quilt commands
You should probably read quilt’s manual page too to learn about the various other commands and options that exist.
There’s at least quilt rename new-name
that you can also find useful to rename the topmost patch (you can use “-P patch-to-rename” to rename a patch which is not currently at the top).
Feedback
Please leave comments if you have suggestions of improvements, or if there are some tips that are good to know. I might incorporate them in this article.
Feel free to share this article with newbie packagers which are struggling with quilt. For your convenience, you can also refer to this article with this URL: https://raphaelhertzog.com/go/quilt
Found it useful? Be sure to not miss other packaging tips (or lessons), click here to subscribe to my free newsletter and get new articles by email.