Most Debian packages are managed with a version control system (VCS) like git, subversion, bazaar or mercurial. The particularities of the 3.0 (quilt) source format are not without consequences in terms of integration with the VCS. I’ll give you some tips to have a smoother experience.
All the samples given in the article assume that you use git as version control system.
1. Add .pc to the VCS ignore list
.pc
is the directory used by quilt to store its internal data (list of applied patches, backup of modified files). It’s also created by dpkg-source so that quilt knows that the patches are in debian/patches
(and not in patches
which is the default directory used by quilt). For that reason, the directory is kept even if you unapply all the patches.
However you don’t want to store this directory in your repository, so it’s best to put it in the VCS ignore list. With git you simply do:
$ echo ".pc" >>.gitignore $ git add .gitignore $ git commit -m "Ignore quilt dir"
The .gitignore
file is ignored by dpkg-source, so you’re not adding any noise to the generated source package.
2. Unapply patches after the build
If you store upstream sources with non-applied patches (most people do), and if you don’t build packages in a temporary build directory, then you probably want to unapply the patches after the build so that your repository is again in a clean status.
This is now the default since dpkg-source will unapply any patch that it had to apply by itself. Thus if you start the build with a clean tree, you’ll end up with a clean tree.
But you can still force dpkg-source to unapply patches by adding “unapply-patches” to debian/source/local-options
:
$ echo "unapply-patches" >>debian/source/local-options $ git add debian/source/local-options $ git commit -m "Unapply patches after build"
svn-buildpackage always builds in a temporary directory so the repository is left exactly like it was before the build, this option is thus useless. git-buildpackage can also be told to build in a temporary directory with --git-export-dir=../build-area/
(the directory ../build-area/
is the one used by svn-buildpackage, so this option makes git-buildpackage behave like svn-buildpackage in that respect).
3. Manage your quilt patches as a git branch
Instead of using quilt to manage the Debian-specific patches, it’s possible to use git itself. git-buildpackage comes with gbp-pq (“Git-BuildPackage Patch Queue”): it can export the quilt serie in a git branch that you can manipulate like you want. Each commit represents a patch, so you want to rebase that branch to edit intermediary commits. Check out the upstream documentation of this tool to learn how to work with it.
There’s an alternative tool as well: git-dpm. Its website explains the principle very well. It’s a more complicated than gbp-pq but it has the advantage of keeping the history of all branches used to generate the quilt series of all Debian releases. You might want to read a review made by Sam Hartman, it explains the limits of this tool.
4. Document how to review the changes
One of the main benefit of this new source format is that it’s easy to review changes because upstream changes are kept as separate patches properly documented (ideally using the DEP-3 format). With the tools above, the commit message becomes the patch header. Thus it’s important to write meaningful commit messages.
This works well as long as your workflow considers the Debian patches as a branch that you rebase on top of the upstream sources at each release. Some maintainers don’t like this workflow and prefer to have the Debian changes applied directly in the packaging branch. They switch to a new upstream version by merging it in their packaging branch. In that case, it’s difficult to generate a quilt serie out of the VCS. Instead, you should instruct dpkg-source to store all the changes in a single patch (which is then similar to the good old .diff.gz
) and document in the header of that patch how the changes can be better reviewed, for example in the VCS web interface. You do the former with the --single-debian-patch
option and the latter by writing the header in debian/source/patch-header
:
$ echo "single-debian-patch" >> debian/source/local-options $ cat >debian/source/patch-header <<END This patch contains all the Debian-specific changes mixed together. To review them separately, please inspect the VCS history at http://git.debian.org/?=collab-maint/foo.gitEND
Rogério Brito says
Another tip that helps with being friendly for VCS’es, when generating the patches is to tell quilt to not put dates on the diffs, use some “generic” prefixes for the names of the files to be patched and don’t generate Index: lines.
I have this on my .quiltrc file, among other things:
QUILT_REFRESH_ARGS=”-p ab –no-timestamps –no-index”
Regards,
Rogério Brito.
Elessar says
I thought that one had to use the -i switch to tell dpkg-source to ignore common VCS files. Is it now the default behaviour?
Raphaël Hertzog says
With 3.0 source packages, yes, it’s the default behavior.
Elessar says
Good to know, thanks. It will save me some time, just typing debuild to build and check my packages.
Colin Watson says
My preferences disagree quite strongly from your point 2. I absolutely adore keeping the patches applied in revision control. This means that I can use ‘bzr blame’ on files and see Debian-specific changes cleanly interspersed with upstream code, use ‘bzr log -n0’ on a file and see all the changes to it regardless of whether they were made upstream or in Debian, and so on. This is priceless when investigating complex bugs.
Colin Watson says
Also, it’s eminently possible to generate nice quilt series with this approach, approaches such as point 3 certainly help but you can manage without. I do it with openssh, which has a long and complex quilt series. I described the methods I use rather loosely here:
http://www.chiark.greenend.org.uk/ucgi/~cjwatson/blosxom/debian/2010-03-25-thoughts-on-3.0-quilt-format.html
Elessar says
I used to do the same (store sources with patches applied under Git). But it has a painful drawback: when there is a new upstream version, merging it onto the Debian branch leads to the correct sources with merged modifications, but completely confuses quilt: refreshing quilt patches leads to having patched between the old upstream version and the new patched one.
Colin Watson says
What you do is unapply the quilt patches first, do a merge (which should be trivial) and then step your way back up the quilt stack resolving conflicts and refreshing as needed. It does mean you’re effectively interleaving two revision control systems, but it works fine and doesn’t create spurious conflicts.
Raphaël Hertzog says
Are you committing the removal of the patches before the merge? That way it could indeed work at the cost of some spurious changes in the history.
AFAIK Git at least doesn’t allow a merge on an unclean tree.
Colin Watson says
No, there’s no need to. ‘man git merge’ says “Warning: Running git merge with uncommitted changes is discouraged: while possible, it leaves you in a state that is hard to back out of in the case of a conflict.” – but you should never actually get a conflict when doing this, because popping all the quilt patches should have brought you back to a point equivalent to an upstream revision, so that’s OK.
By default, ‘bzr merge’ refuses if there are uncommitted changes, but you can use ‘bzr merge –force’. No spurious changes need to be introduced into the history.
Raphaël Hertzog says
Hi Colin, I know of your preference, it’s still recorded in a dpkg-dev bug (http://bugs.debian.org/572204). 🙂
In theory, I also prefer when the changes appear directly in the VCS. But keeping debian/patches/, .pc and the VCS in sync is a pain, both after a checkout and after an upstream merge.
So I tend to prefer a solution where the quilt part is generated out of the VCS. The main problem with the current solutions is that the branch with the patches applied is not the default branch that you get after checkout (usually it’s a throw away branch) and it’s only useful to apply upstream changes and not to change the other packaging files. Ideally you could do both in the same branch and somehow the tool would know what to do with each change. But that probably implies rewriting history… it’s not an easy problem to solve.