The big picture


For this package, "upstream" means, from a Debian packaging point-of-view, the state of our upstream branches. Let's not pretend we have not forked liveusb-creator, and admit we are now upstream for our own version. Thus, from version 4.x on, our fork has been renamed to tails-installer.

The master branch must always be the one that targets current Tails and possibly also earlier Debian releases. At the moment it supports Debian Stretch, Buster and Sid.

But that's not enough, since we also need to put releases out with code that works on current Debian testing/unstable. Thus, we maintain several upstream release branches in parallel, each with their own major version number:

  • for work and releases that target Stretch (and, as long as compatible, that target Debian testing/unstable as well):
    • branch = master
    • version = 5.*
    • tag = tails-installer_5.*

Once we can't support both Stretch and Debian testing/unstable with the same codebase anymore, we'll fork a new upstream release branch that targets Debian testing, it'll be called feature/$codename, use version 6.*, etc.


We're using DEP-14 conventions, except for our master branch which is used for upstream development targeted at current Tails, as said above. More specifically:

  • The pristine-tar branch contains the binary delta between DFSG-freed tarballs and the corresponding tag. It's automatically maintained by gbp import-orig.
  • The debian/sid branch is used to build the package that we upload to Debian unstable. The tags on this branch are called debian/$package_version, which is the default when creating them with gbp buildpackage --git-sign-tags --git-tag-only; in practice this is something like debian/5.3+dfsg-1.
  • The debian/$codename-backports branch is used to prepare packages that we upload to the official backports repository for Debian $codename. E.g. here we want to have debian/stretch-backports soon after the initially uploaded package reaches Debian testing. The tags on this branch are also called debian/$package_version. In practice this is something like debian/5.3+dfsg-1~bpo8+1.
  • The tails/master branch is used to prepare packages that we upload to the Tails APT repo for Tails stable releases, but not to Debian.
  • The tails/$codename branch is used to prepare packages that we upload to the Tails APT repo but for (non-stable) Tails based on Debian $codename. Again, these packages will not be uploaded to Debian.
  • Additionally, we use tails/$feature branches for other Tails-specific packaging branches.
  • The upstream/4.x+dfsg, upstream/5.x+dfsg, etc. branches are what we tell gbp to use as its "upstream" branch. Make sure to check them out when setting up the repository for the first time.
  • For Ubuntu, we want to support the current Ubuntu version, the upcoming version, and the current LTS: Ubuntu version history. We do not maintain any Git branches related to Ubuntu releases, as simply the changelog entries are modified.

Topic branches

In practice, it's expected that Tails contributors submit bugfix and feature branches forked off master, because they want them part of next Tails release. Hence, it will happen that code lands into master first, and in turn into a new 5.* upstream release, before it lands into e.g. feature/buster and in turn into a new 6.* upstream release.

For how to package topic branches (bugfix/* and feature/*), see the dedicated page.


Release a new upstream version

Prepare the environment

The new upstream version should be something like 5.3, based on the upstream branch you are building the Debian package for. Adjust and export:

export NEW_UPSTREAM_VERSION=5.replace_me
export PKG_NAME=tails-installer

Tag the new version

git checkout "$UPSTREAM_DEV_BRANCH" && \
./ build && \
   (cd po && \
       for po in *.po ; do msgmerge --update "$po" \
       "$PKG_NAME.pot" ; done \
   ) && \
   git commit po -m 'Update POT and PO files.' && \
git tag \
   -m "Releasing Tails Installer $NEW_UPSTREAM_VERSION" && \
git push --tags origin "$UPSTREAM_DEV_BRANCH"

Generate a new upstream tarball

mkdir -p ../tarballs && \
git archive \
   --prefix="${PKG_NAME}-${NEW_UPSTREAM_VERSION}/" \
   --output="../tarballs/${PKG_NAME}_${NEW_UPSTREAM_VERSION}.tar.gz" \

Update the Debian package for Tails

Checkout the packaging branch, e.g.:

export PKG_NAME=tails-installer
export PACKAGING_BRANCH=tails/master
git checkout "$PACKAGING_BRANCH"

Here we assumed that tails/master still supports Debian Sid, otherwise PACKAGING_BRANCH should be tails/${codename}.

Merge Debian packaging changes:

git fetch debian && \
codename="${PACKAGING_BRANCH/*\//}" && \
if [ "${codename}" = "master" ]; then
fi && \
git merge "debian/debian/${codename}"

Verify that debian/gbp.conf references the correct upstream and Debian (packaging) branches, and that pristine-tar usage is enabled, e.g.:

upstream-branch = upstream/5.x+dfsg
debian-branch = tails/${codename}
debian-tag = tails/%(version)s
pristine-tar = True

Extract the upstream and packaging branch from gbp.conf:

export UPSTREAM_BRANCH=$(gbp config buildpackage.upstream-branch \
                         | sed -r -e 's,.*=,,')

Create a DFSG-compatible tarball from the previously created Git archive and reimport it into the source tree. This merges, into the debian-branch specified in gbp.conf, not only the commit that imported the current DFSG-free upstream tarball into the upstream-branch, but also the corresponding upstream Git history:

mk-origtargz \
   -C ../tarballs \
   --version "$NEW_UPSTREAM_VERSION+dfsg" \
   --copy \
   ../tarballs/${PKG_NAME}_${NEW_UPSTREAM_VERSION}.tar.gz && \
gbp import-orig \
   --upstream-vcs-tag="${PKG_NAME}_$NEW_UPSTREAM_VERSION" \

Update debian/changelog:

gbp dch && dch -e

The raw data compiled by gbp dch must be edited to convey information that's relevant and self-contained for a Debian audience (clearly our upstream commit messages are not written with this audience in mind). For example, the 5.0.4+dfsg-0tails1 changelog entry is pretty good, but things like "Apply awful hack to fix Tails#14755" are meaningless for a Debian audience.


  • Set the appropriate version number, such as 5.3+dfsg-0tails1; in particular, note that the Debian revision starts with -0 for any package meant for the Tails APT repository, while the first package that will be uploaded to Debian will have -1;
  • Set the appropriate target release name.
  • Make sure every Tails ticket ID is of the form Tails#NNNNN, not #NNNNN and definitely not Closes: #NNNNN.

Commit the changelog:

git commit debian/changelog \
    -m "$(dpkg-parsechangelog -SSource) ($(dpkg-parsechangelog -SVersion))

Git-Dch: Ignore

Make sure that the working environment is clean:

git clean -fdx

Build a new Tails package (use a amd64 chroot that matches the target distribution):

gbp buildpackage

Add a signed tag to the Git repository and push the changes:

gbp buildpackage --git-tag-only --git-sign-tags && \
git push --tags origin "$UPSTREAM_BRANCH" \
                "$PACKAGING_BRANCH" \

If you are a member of the Debian pkg-privacy team

Add the remote:

git remote add debian

Then push:

git push --tags debian "$UPSTREAM_BRANCH" \
                "$PACKAGING_BRANCH" \

Never force push! If git push fails you may have to merge back in e.g. debian/pristine-tar into your local pristine-tar and push again. Also push it to origin, in that case.

Add the Debian package to Tails

Sign the package:



dupload --to tails $CHANGES_FILE

Update the Debian package

This assumes that the latest upstream release has been imported into the tails/master branch already.

And then, a maintainer of tails-installer in Debian updates the package in sid accordingly, for example:

  • check out the debian/sid branch
  • merge the tails/master branch
  • bump version to 5.3+dfsg-1
  • build, test and upload to sid
  • have gbp create a debian/5.3+dfsg-1 tag
  • push the Debian packaging branch (debian/sid) and the new tag

Example for a backport to Stretch:

  • check out the debian/stretch-backports branch
  • merge the debian/sid branch
  • dch --bpo to bump version to 5.3+dfsg-1~bpo9+1
  • build, test and upload to stretch-backports
  • have gbp create a debian/5.3+dfsg-1_bpo9+1 tag
  • push the Debian packaging branch (debian/stretch-backports) and the new tag

Upload a package to our Ubuntu PPA

Team members are allowed to upload a package to our Ubuntu PPA:

You'll need to configure the dput tool to upload to the PPA and put into $HOME/ (adjust to use your Launchpad ID):

fqdn =
method = ftp
incoming = ~tails-team/ubuntu/tails-installer/
login = your_launchpad_id
allow_unsigned_uploads = 0
  • checkout the debian/sid branch to build a package for the next Ubuntu release or checkout the debian/stretch-backports branch to build a package for the current Ubuntu version or current LTS.
  • bump version to 5.3+dfsg-0ubuntu1~$codename using dch -i where $codename is the name of the target Ubuntu distribution.
  • if it does not exist, rebuild the .orig.tar.gz of the latest version from pristine-tar (use the latest git log entry to find the version): pristine-tar checkout ../tails-installer_5.3+dfsg.orig.tar.gz
  • build a source only package using debuild -i -uc -us -sa -S Once the package has been built, a .changes file will be created in pbuilder's configured destination directory.
  • test the package (piuparts, Lintian, etc.)
  • sign the corresponding source.changes file debsign ../tails-installer_$NEW_UPSTREAM_RELEASE-xxx_source.changes Replace "xxx" with the correct version information. The signature should be made with a key which is registered at Launchpad as being part of the Tails team.
  • Upload to the PPA: dput ppa-tails-installer ../tails-installer_$NEW_UPSTREAM_RELEASE+xxx_source.changes

You will receive an email informing you if the upload was really successful or if it contained any errors. On success, you should now revert your changes on the Debian branch using git reset HEAD --hard.

Quality assurance for Debian and Ubuntu packages

Scenario: Installing Tails to a pristine USB drive
  Given I have started Debian
  And I have a Tails ISO image
  When I install the tails-installer package
  And I plug USB drive "install"
  And I ask Tails Installer to install my Tails ISO image to USB drive "install"
  Then my Tails ISO image is installed on USB drive "install"

Scenario: Upgrading an old Tails USB installation from an ISO image
  Given I have started Debian
  And I have a Tails ISO image
  When I install the tails-installer package
  And I plug USB drive "upgrade" that has an old Tails installed
  And I ask Tails installer to upgrade USB drive "upgrade" with my Tails ISO image
  Then my Tails ISO image is installed on USB drive "upgrade"