Using Git for Debian Packaging

Table of Contents

Introduction
Getting Started with Git
Working with Someone Else's Package
Publishing a Repository
Debian Packaging
Debian and Upstream Combined
Converting to Git

Introduction

This page duplicates a lot of other information out on the web, and I don't necessarily recommend it as a starting point. I maintain it largely for my own purposes, to remember the techniques that I've found that worked. However, it may be of interest if you are looking at moving from Subversion plus quilt to Git for maintaining Debian packages, since that's what I'm evaluating.

The Git version control system (VCS) is a distributed VCS originally written by Linus Torvalds for Linux kernel development after moving away from BitKeeper. "Distributed" means that it has strong support for branching, merging, and parallel lines of development and is designed for multiple people working on the same software in parallel and merging in complex ways between their separate trees.

Of the distributed version control systems, Git has the strongest following among free software developers at the moment and is increasingly popular in Debian. Before looking at Git, I'd used Arch (bazaar and tla), bazaar-ng (bzr), and svk before, but only briefly and mostly in the same way that I'd use Subversion. So I came to Git familiar with some of the distributed VCS basics but without a lot of practical experience.

When you have the opportunity, you should read the entire Git user manual.

Getting Started with Git

First, install the git package. If you're going to do Debian packaging, also install git-buildpackage and pristine-tar. You probably want the current unstable (or at least testing) versions of all of those; stable is rather old. You probably also want gitk (or one of the other Git repository browsers like giggle or tgit. I personally prefer gitk.

You should also tell Git your name and e-mail address with:

    git config --global user.name '<name>'
    git config --global user.email '<email>'

You can set these per-repository as well, once you have a repository, by running the command within that repository and omitting the --global flag.

The basic Git commands are very similar to the commands for Subversion; git log and git status do what you'd expect, for example. However, one thing to be aware of is the index, which you can think of as your pending next commit. By default, git commit only commits changes that have been added to the index with git add (unlike with other revision control systems where the add command is only used to add entirely new files). You can run git commit -a to add all modifications to the index and then commit them in one step, but it's worth getting in the habit of doing explicit git add commands to cut down on committing unintended changes.

To revert changes in your working copy, use git reset --hard. This is equivalent to svn revert. (git revert does something completely different, namely revert a specific change.)

git branch will show you a list of branches. git tag will show you a list of tags. To switch between branches (something that you do a lot of in Git), use git checkout <branch>. To create a new branch based on an existing one, use:

    git checkout -b <new-branch> <old-branch>

To tag the current branch with some tag name, use git tag <tag>.

One neat Git trick that isn't present in other revision control systems is that if you flub a commit, you can fix it after the fact. Add whatever additional modifications you need to make (if any) with git add and then run git commit --amend. You'll get the opportunity to re-edit the commit message as well. Note that you should not do this if you've already run git push.

Working with Someone Else's Package

My first experience with Git was working with logcheck and submitting patches back, following the guide available on logcheck.org. Briefly, the steps to get started with someone else's repository are:

    git clone <url> <directory>
    cd <directory>

where <url> is the upstream Git repository, and <directory> is your working directory. This gives you a checked out working copy. Before doing any work, refresh from upstream and then create a local branch for that work:

    git pull
    git checkout -b <branch>

Now, you can work in that branch and make commits as you go, using either git add and git commit or just git commit -a.

The later step of sending patches is simplified if you keep to one commit per separate patch, which may or may not be realistic depending on what sort of things you're working on. If you can't do that, don't worry a lot about it.

If upstream does additional work before you're ready to submit patches, you resynchronize with upstream by doing:

    git checkout master
    git pull
    git checkout <branch>
    git rebase master

git rebase essentially reworks your branch so that it looks as if you'd started with the current upstream master branch instead of an older version, thus eliminating merge noise. You should not use git rebase on public branches that you're publishing, but it's great for this sort of private working branch where you don't want to carry around the merges from new upstream work as additional commits in your branch. If for some reason you have published this branch, use git merge instead.

When you're ready to submit the patches upstream, if each commit is a separate upstream patch, you can just do:

    git format-patch -M -s master

which will write the patches into the current directory for you to look over. You can submit them via whatever means upstream prefers. Often git send-mail is useful (try it with --to pointing to your own address first).

If you need to collapse your commits down further to generate patches, you can either do a git merge --squash to collapse all your changes into a single commit or do more complicated things with git rebase -i or git cherry-pick -n. You'll want to do this on a separate working branch. One work-flow option is to do all of your changes in a sloppy branch with repeated commits, then use one of those techniques to pull them onto a real feature branch and delete the sloppy branch.

To get a list of current branches, run git branch. You can delete branches with git branch -d (safe — only deletes merged branches) or git branch -D (will lose any work on that branch that hasn't been merged) so you don't have to carry your experiments around forever.

Publishing a Repository

To publish your Git repository, just follow the instructions in the Git manual. I usually use HTTP since it's nice and easy, but the native Git protocol offers significant improvements. The Git server is purely anonymous and doesn't allow writes, so you don't have to worry much about running it for repositories that are public anyway.

To set up the remote name, rather than using the instructions given in the manual, try:

    git remote add --mirror public <url>

I prefer mirror, since then all new branches are automatically pushed to the public repository and it's treated by Git as a copy of your local repository rather than a possibly independent repository with which you're merging. However, this only works if it's just for your personal use; if you're sharing with others, such as for Debian packaging, you don't want to use --mirror.

If you're setting up Git for Debian packaging, you probably want to put your repository on git.debian.org instead. This is done via Alioth. You can use the collab-maint project for individual packages or request a new group for a larger set of packages that needs its own infrastructure. Once you've decided, one way or the other, follow the instructions and the repository will show up on the web browser in six hours or so.

The Alioth instructions create a remote name of alioth. If I'm primarily going to be synchronizing with other work on Alioth, I prefer to use a remote name of origin since other Git commands use that as a default. When I create my own public repository, I use a remote name of public. If you're using a shared repository that's already set up, you can use git clone as described above, which will set up your repository with a remote name of origin.

After making changes that you want to publish, run:

    git push public <branch>

or alioth or origin instead of public as needed. <branch> is the name of the branch whose details you want to publish. You can use --all instead to push all branches. Once you do this, you shouldn't amend or rebase commits, so I usually only do this after I'm done with a chunk of work and have tested it. If you've cloned from a remote repository, or branched from a remote branch, that remote and branch will be the default push target if you just run git push.

Pushing branches will not push tags. To push tags to a remote repository, you have to explicitly pass --tags to the git push command and you can't push branches and tags at the same time for some reason.

One special note: if you delete a branch locally, that doesn't delete the branch on the remote repository. If you want to do that, you have to do it as as special git push command with a weird syntax:

    git push origin :<branch>

where origin is the name of your remote. The colon there is a literal colon. This will delete the branch named <branch> in the remote repository. Be warned that it will be difficult to recover that branch if you make a mistake and don't realize it immediately.

Also, branches deleted from remote repositories can still linger as tracking branches in your local repository. You can clean them up with:

    git remote prune origin

None of this is necessary if you use a mirror remote, since it will always force the remote repository to look exactly like your local repository and won't retain tracking branches. But mirror remotes only work when you're publishing your own personal repository and no one else will be pushing to the same repository.

Debian Packaging

Initial configuration

First, configure git-buildpackage to use pristine-tar. pristine-tar allows you to store the upstream tarball directly in Git in an extremely space-efficient way, which means that the Git repository is then all you need to build a Debian package. You don't have to separately keep track of the upstream tarball. I use the following ~/.gbp.conf:

    [DEFAULT]
    builder = git-pbuilder
    cleaner = fakeroot debian/rules clean
    pristine-tar = True

    [git-buildpackage]
    export-dir = ../build-area/
    tarball-dir = ../tarballs/

    [git-import-orig]
    dch = False

This uses the svn-buildpackage convention of a directory full of directories for each Debian package and a directory named build-area that holds the most recent builds. If you use pristine-tar, the tarball-dir key isn't used. The git-pbuilder script is the required wrapper to get git-buildpackage to use pbuilder (via cowbuilder). It comes with current versions of git-buildpackage, or you can get it from my miscellaneous scripts page.

Repository layout

For Debian packages, I use a layout similar to the git-buildpackage recommendation but with an (almost) pure feature branch setup. This means that every feature or bug that could be pushed upstream is developed on a separate branch for that particular feature or bug, and the main branch (by Git convention master) is a combination of a merge branch and the branch for Debian-specific changes like the debian directory.

The upstream source (after any necessary repackaging to remove non-DFSG-free files) is imported into the upstream branch and that branch, along with the others, is merged into the master branch.

All Debian packaging and any Debian-specific upstream modifications that aren't large enough to warrant a separate development branch and which can't be usefully sent upstream go directly on the master branch. This includes the entire debian/* directory, upstream modifications to remove references to non-DFSG-free material, minor path changes, and the like. (I previously tried making master a merge-only branch and developed Debian-specific changes on a separate debian branch that I merged into master like every other feature branch, but this ended up being too confusing without much practical purpose.)

Bug fixes to the upstream source go on branches named bug/<name> where <name> is some short term for the bug being fixed. New upstream features go on branches named feature/<name>. These patches should be sent upstream.

It's worth frequently doing a git diff between master and the upstream branch to be sure you know what changes you've made. Piping it through filterdiff -x '*/debian/*' will show you only the changes to the upstream sources. (filterdiff is an extremely useful program from the patchutils package.)

Importing a package

git-buildpackage can do most of the work of managing the upstream branch. To start a new Git repository from an existing package without caring about the history, just run:

    git-import-dsc /path/to/dsc

You'll get a subdirectory of your current directory named after the package and containing an initialized Git repository with an upstream and master branch and with (if you use the above configuration) a pristine-tar branch that holds the metadata used by pristine-tar. git-import-dsc will also create an upstream/* tag for the upstream version and a debian/* tag for the Debian version of the package.

If you're instead starting from scratch with packaging a new package, create an empty directory, cd into it, and run git init to create an empty repository. With older versions of git-buildpackage, such as the version in squeeze, you may have also to pre-create an empty upstream branch with:

    git init
    git commit --allow-empty -m 'Initial repository'
    git branch upstream

Then rename the upstream tarball to <package>_<version>.orig.tar.gz (don't repack it unless you have to, just rename it) and run:

    git-import-orig /path/to/upstream/tarball

This will create an upstream branch and load the upstream source and then merge that onto your master branch.

If you're importing an existing package that has upstream patches that should go on bug and feature branches mingled with Debian changes, you may need to shuffle things around a bit. I generally do that by saving off the upstream patches that should get their own branches, reverting all those changes on the master, creating new bug or feature branches based off upstream (not master), reapplying the relevant patch and committing it, and then merging that branch back into master.

Packaging workflow

Further Debian-specific work can then be done on the master branch by switching to it with git checkout, modifying and committing things.

New bug or feature branches should be based on upstream but are otherwise handled in the same way. When ready for a release (or even a test build), merge everything into master, switch to that branch if you aren't already, and then run git-buildpackage. If all goes well, the built packages will be in ../build-area/.

After uploading a release, tag the master branch with the release version. I use an annotated tag with the contents of the *.changes file as the tag message, an idea that I got from Sam Hartman. To avoid having multiple GPG signatures on the tag, I strip the signature off the *.changes file and then do:

    git checkout master
    git tag -s debian/<version>

In the editor, I put "Debian release <version>" as the first line, add a blank line, and then include the ../build-area/*.changes file. (The wildcard only works if you only have one built package in your ../build-area/ directory.) Don't forget to push to a remote repository, following the instructions above, if you're using one.

When there's a new upstream release, first checkout the master branch and then run:

    git-import-orig /path/to/upstream/tarball

You shouldn't have to rename the upstream tarball first to <package>_<version>.orig.tar.gz; git-import-orig will take care of that for you. git-import-orig will import and tag upstream and handle the pristine-tar work, and will then try to merge upstream onto master. If this works, great. If it doesn't and you have merge work to do, it's usually easier to run git reset --hard and then go find the bug or feature branch with the problems and merge upstream into that so that you can deal with one set of conflicts at once and you don't have to deal with the merge into that branch later. (git rerere is often useful here. See the man page.)

If upstream has incorporated the changes in a bug or feature branch, I merge upstream into that branch, merge the branch one last time into master, and then delete it with git branch -d. Using that procedure ensures that you really did get everything left on that branch.

If you have conflicts on multiple branches, merge upstream into each one and resolve the conflicts one-by-one. Then, create a tmp-merge branch cloned off of upstream, merge each feature and bug branch onto it (including debian), merge tmp-merge into master, and then delete tmp-merge. This serializes all the merges and avoids problems with merges conflicting with each other. (Alternately, you can use rebasing of your bug and feature branches, but I prefer the merge workflow to the rebase workflow most of the time, even when I'm not publishing repositories.)

Conflict resolution is similar to Subversion. Search for the <<<<< string for each conflict, figure out which version is correct (or some merger of both), delete the conflict markers, and repeat as necessary. When done with a file, use git add to mark it as resolved. Then run git commit to commit the merge with its conflicts. Usually you want to leave the commit message unchanged.

Handling repackaged upstream

If the upstream source has to be repackaged for DFSG reasons, you can just generate a new *.orig.tar.gz file outside of Git and then import it as described above. However, Git and git-buildpackage have some additional features that may make this easier if you're just excluding certain files from the upstream source.

You can import the upstream distribution selectively using:

    git-import-orig --filter='rfc*' /path/to/upstream/tarball

for example, adding --filter options for every file in the upstream source that you need to exclude. (These options can be recorded in debian/gbp.conf for others working on the package rather than giving them directly on the command line.) Then, you can generate the DFSG-free version of the upstream tarball with:

    git archive --prefix=<package>_<version>.orig/ upstream/<version> \
        | gzip -9 > <package>_<version>.orig.tar.gz
    pristine-tar commit <package>_<version>.orig.tar.gz
    rm <package>_<version>.orig.tar.gz

Whether to use this approach or the more traditional approach of generating the *.orig.tar.gz file separately and then using git-import-orig as always is up to you and depends on which approach you find simpler.

Source package version

For my Debian packages maintained in Git, I do use the 3.0 (quilt) source package version, but I don't attempt to maintain separate patches. I've experimented with some of the systems for extracting individual patches from Git, but they have all seemed clunky or involve too much make-work. Instead, I configure the Debian build system to create a single Debian patch with all divergences from upstream.

To do this, create debian/source/format with its normal contents of 3.0 (quilt) and then debian/source/options containing single-debian-patch. I then create debian/source/patch-header with contents like:

    Subject: Collected Debian patches for <package>
    Author: Russ Allbery <rra@debian.org>

    The <package> package is maintained in Git rather than maintaining
    patches as separate files, and separating the patches doesn't seem to
    be worth the effort.  They are therefore all included in this single
    Debian patch.

    For full commit history and separated commits, see the packaging Git
    repository.

For packages where I'm also upstream, I only cherry-pick changes into the debian branch and instead use a patch header of:

    Subject: Collected Debian patches for <package>
    Author: Russ Allbery <rra@debian.org>

    Since I am also upstream for this package, there will normally not be
    any patches to apply to the upstream source.  However, occasionally
    I'll pull up specific upstream commits prior to making an upstream
    release.  When this happens, this patch will collect all of those
    modifications.

    I use Git to maintain both the upstream source and the Debian
    packages, and generating individual patches rather than using git
    cherry-pick takes extra work for no gain.  Since I'm also upstream,
    there's no need to separate the patches for later upstream submission.
    Hence, I take this approach with a unified patch when it's necessary.

    For full commit history and separated commits, see the upstream Git
    repository.

Of course, if you use these as templates for your own packages, don't forget to change the Author line.

Eventually, I'll change this to use debian/source/local-options or something similar so that any NMU patches will end up as separate patches from my normal packaging patch.

Special cases and cautions

I still commit debian/changelog entries along with the corresponding change and just resolve the conflicts when I cherry-pick or merge. This doesn't really bother me, but it is some additional work. Some people instead leave the Debian changelog file alone until the release and then use git-dch or some similar tool to generate it and then edit it. At some point, I'd like to play with that idea.

debcommit's support for determining the commit message from my changelog entry doesn't do what I want, so I write the commit message separately. Your mileage may vary.

I don't commit changes to Autotools files (config.guess, regeneration of configure, regeneration of Automake makefiles, Libtool updates, etc.) to the repository. Instead, I build-depend on the appropriate packages and do this at build time, and then delete all modified files in the clean target of debian/rules. I think this is simpler. Be sure to delete all the modified files, though, or you can have trouble when building twice in a row or end up with spurious modifications in your diffs. You can check this by running debian/rules build and then fakeroot debian/rules clean and make sure that no added or modified files show up in the git status output, only deleted files. (Take a look at the dh-autoreconf package for a helper program to make this easier.)

gitk is incredibly useful for performing any sort of archaeology. I've gotten to the point where I often turn to it instead of git log. It's particularly useful if you forget to tag uploads and need to figure out what specific revision corresponded to a Debian package upload.

Backporting

Often backporting a package to stable is as simple as just adding a new changelog entry for the backport and then rebuilding it in a stable chroot instead of an unstable chroot. This document doesn't cover that case, since it can be done without any representation in the version control repository (and normally there's no point in committing such backports anywhere).

If backporting requires more work, such as changing build dependencies or adjusting the packaging for tools that aren't present in stable, the easiest way to do this using Git is to create a new branch off of master and make the necessary changes there. For example, for an squeeze backport:

    git checkout -b squeeze master
    # edit debian/control and other files as needed
    # edit debian/changelog to add backport log entry
    git-buildpackage --git-debian-branch=squeeze -v<last-version>
    git tag debian/<version>

The -v option should specify the last version of the package available in stable, if it was previously in stable, so that the *.changes file will include all changes since that date. The version of the backport should follow the conventions of whatever repository for which it is being prepared; for the backports.debian.org repository, see the documentation for contributing.

For later backports, you normally will be able to merge the new master branch into the backport branch with:

    git checkout squeeze
    git merge master

The debian/changelog file may have conflicts that have to be resolved, normally by removing the old backport log entry and adding a new one for the new backport.

Debian and Upstream Combined

For many of my packages, I'm both the Debian packager and the upstream maintainer. In those cases, I want a combined repository that I can use for both upstream maintenance and for Debian packaging.

Before using Git, I used to do this by maintaining the debian directory in with the upstream code like any other part of the code, on the main development branch, and just excluding it from releases. Then, to build Debian packages, I'd unpack the latest tarball, export the debian directory from the repository into the unpacked working tree, and build the result. I had a script that automated much of this process.

This works, but it has a few drawbacks:

After switching to Git, I wanted a more general solution without these limitations that could also leverage pristine-tar so that all the information required to build the package was within the repository.

The two things that make this tricky are that pristine-tar, to be space-efficient, requires a complete import of the upstream source in a branch in the repository, and the Debian packaging should be based off the source tarball as released. My main upstream maintenance branch of course doesn't include generated files such as configure or files that are installed by Automake such as config.sub, nor do I want to check those files into my working repository and have to keep updating them. However, I do want to check the tarball releases into the repository and base the Debian packaging off that.

I therefore keep the upstream maintenance and the Debian packaging on independent sets of branches without common ancestors. I work on the master branch and, when I'm ready to release, tag the released state of that branch with a release/<version> tag. Then, I use git-import-orig to import that released tarball, generally constructed with make dist or an equivalent thereof, into an upstream branch and merge it into a debian branch based off of that. This lets me still cherry-pick commits from upstream development if I need them in a Debian package before the next upstream release, but the Debian packaging is properly based on the released tarballs and there's a branch holding the full tarball contents for pristine-tar to work with.

If you use this configuration, you'll want to add a .git/gbp.conf file in the repository containing:

    [DEFAULT]
    debian-branch = debian

so that git-buildpackage and git-import-orig won't try to operate on the master branch.

Converting an existing repository that combines Debian packaging and the upstream development is a bit tricky, since you want to create a new debian branch that shares the history of the current master and an upstream branch that can be merged into debian and used by git-import-orig, but you also want to remove the debian/* directory from the master branch. The first time I tried this, I ended up merging the removal of the debian/* directory into my debian branch and having to back out of that.

After some experimentation, the following approach seems to work the best:

  1. Before removing debian/* from master, create the debian branch with git branch debian master.

  2. git rm -r debian on the master branch and commit it.

  3. git branch upstream master. Now you have an upstream branch with the right history and without the debian/* directory, although it doesn't match the upstream tarball release (it's missing generated files).

  4. Record in Git that the debian branch is already a correct reflection of the changes relative to the upstream branch by adding a merge commit. git checkout debian and then git merge -s ours upstream. The -s ours is the key trick; it records the merge commit without deleting debian/* as part of the merge.

  5. Now you can run git-import-orig on the current upstream release tarball, let it fix up the upstream branch to match the release tarball by adding all the generated files, and then merge them into the debian branch. You can do this now if you haven't made any changes since the previous release. If you have made changes, the easiest thing to do is to wait until you do another release and then have that be the first true imported release.

I don't bother to go back and try to reconstruct history and put previous releases in the upstream branch. It's a lot of work and doesn't seem worth the effort.

An even better approach than exporting a tarball and importing it with git-import-orig is to commit the upstream tarball release as a merge commit between the upstream release tag and the upstream branch used for the Debian packaging workflow. I'm currently doing this for the Debian openafs source package and will hopefully find time to write this up in more detail and convert my other packages to it. In the meantime, see the debian/README.source file in the openafs package for more details.

Converting to Git

Subversion to Git Migration

I have a bunch of old Debian packaging repositories in Subversion that I'm converting to Git. There are a lot of different ways to do this, but here's the one that works for me. This technique is heavily based on a blog entry from Martin Krafft.

First, install git-svn if it's not already installed.

My packages all use an svn-buildpackage layout, which means there's an upstream directory under branches that has the imports of the upstream source. I'm usually willing to throw away any other branches, so I start with:

    git svn clone --stdlayout --branches=branches/upstream --no-metadata \
        -A /path/to/authors/file <svn-url>

This will create a new subdirectory named after the last component of the <svn-url> with a new Git repository. This command treats all the upstream tags and current as branches and ignores the other branches; if you want to keep all the branches, svn mv the contents of branches/upstream into branches first and then point git svn at the whole branches directory.

Note the -A option; use that to specify the path to a mapping from usernames in the Subversion commits to full names and e-mail addresses for Git. Without this, your old commits will have ugly identification. See the git-svn man page for the details on the format.

--no-metadata means that we're doing a one-way conversion and git svn shouldn't keep the data required to support commits back to the Subversion repository.

git svn will leave your Subversion trunk and branches as remote branches in your repository and will create all of your tags as more remote branches. The first step is to clean that up. Get a full branch list with git branch -r. Then, create new local branches for the remote branches that are really branches; at the least, you'll probably want:

    git branch upstream branches/current
    git branch -r -d branches/current

Note the removal of the remote tracking branch using git branch -r -d; that's how you get rid of those. Next, convert each tag into a real tag. The revision to which the tag should apply will be the revision prior to the one recorded in the repository, so take advantage of Git's ^ shortcut for previous revision with commands like:

    git tag debian/<version> tags/<version>^
    git branch -r -d tags/<version>

Similarly for all the tags of the upstream imports, do:

    git tag upstream/<version> branches/<version>^
    git branch -r -d branches/<version>

Once you finish this, git branch -r should show no remote tracking branches and only your regular upstream and master branches.

If you used the svn-buildpackage mergeWithUpstream feature to not store the upstream source in your Git repository, the conversion has a few more steps. You need to import the upstream source into the repository to use Git the way that I outline in this document. Ideally, you should be able to do that by just importing the most recent upstream tarball from Debian with git-import-orig, but it currently cannot handle creating the upstream branch from scratch. Instead, be sure you have no uncommitted changes and then first create an empty upstream branch:

    git symbolic-ref HEAD refs/heads/upstream
    git rm --cached -r .
    git commit --allow-empty -m'Initial upstream branch'
    git checkout -f master

and then you can import the latest upstream source:

    git-import-orig /path/to/orig.tar.gz

This will commit and tag the upstream source and merge it into your master branch, fleshing out your repository. All of your old tags will still have only modified files, but normally that's not a serious problem.

If you had to do git-import-orig as described above, it will take care of committing the pristine-tar metadata. Otherwise, grab the last upstream orig.tar.gz (and make sure that it's named properly), put it somewhere not in the current directory, and run:

    pristine-tar commit /path/to/orig.tar.gz

to load it into the repository. If you want, you can also load older upstream tar.gz files, but I never bother.

You can now delete some additional junk left over from the git svn conversion process. Edit .git/config and remove the information about the remote tracking branches for the Subversion repository, and delete all of .git/svn.

If you're like me, you weren't very good about always tagging releases in Subversion. You can now much more easily fix this by browsing the repository using gitk and finding the release points for each Debian package. When you do, paste the hash (shown nicely in gitk for you) into a git tag command like:

    git tag debian/<version> <hash>

When you select a revision in gitk, it copies the hash of that revision into the X cut buffer for you, so you can paste it into a command without selecting it.

Finally, do the same things as noted above under setting up a Debian packaging repository (clone master to debian, move things to feature or bug branches, and so forth).

CVS to Git Migration

My old CVS repositories don't use branches or tags, so importing them was much easier and essentially follows the git-cvsimport man page.

First, install the git-cvs package if you haven't already.

Now, run git cvsimport. Since I'm doing one-way conversions and plan on discarding all the old CVS information afterwards, I use options like:

    git cvsimport -d <cvs-repository> -o master -k -A <authors-file> \
        -a -C <project> <module>

where <project> is the name of the new directory you want to create with the imported repository. As with Subversion, you'll need an authors file that maps the usernames stored in CVS commit messages to identities in the new Git repository.

If you're like me, you'll then want to go back through the history with gitk and tag all the past releases with git tag.

bzr to Git Migration

When I did a Google search on migrating a bzr repository to Git, most of the documentation said to use tailor. However, it didn't work; it got as far as a changeset that renamed ChangeLog to CHANGES.old and then bailed because it claimed the git add command on CHANGES.old failed. When I ran exactly the command that it claimed to have ran by hand, it worked fine, but I couldn't figure out how to convince tailor of that.

Thankfully, there's a better alternative, although it's not well-documented yet. Git and bzr both have support for the fast-import repository serialization format, although the bzr support is somewhat hidden away if you're using Debian. Here are the instructions that I used back when I did this; now, it looks like bzr-fastimport is a regular Debian package and installs a plugin, so I suspect that just installing it and using the commands it provides will work.

First, get the bzr-fastimport source tree from Launchpad:

    bzr branch lp:bzr-fastimport

Then, create a new directory and empty Git repository for your project:

    mkdir <project>
    cd <project>
    git init

Now, you can import your old bzr repository by serializing it using the bzr-fast-export.py script that comes with bzr-fastimport:

    /path/to/bzr-fastimport/exporters/bzr-fast-export.py \
        /path/to/bzr-repository | git fast-import
    git checkout master

This will even preserve tags in your bzr repository.

Last modified and spun 2013-12-06