This document lists changes to the pkg-go workflow which the pkg-go team has agreed on.

2026-03 changes

The primary goals of these changes are:

  • Clarify ambiguity.

  • Ensure support for multiple major versions of a library.

  • Lay some initial groundwork for migrating from the old and quasi-deprecated GOPATH mode to the new module-aware mode (added in Go v1.11 and made default in Go v1.16) when building programs. Currently (as of v1.63), dh-golang forces GOPATH mode.

These goals are accomplished by indirectly encouraging Debian package maintainers to treat modules with different module paths as unrelated, and to use the module’s complete module path as the canonical identity of the packaged Go code.

Note
Go forces different major versions of a library to have distinct module paths. Go treats modules with different module paths as unrelated, even if the paths differ only by their major version suffix. In particular, it is possible to simultaneously depend on multiple major versions of the same library. For a real example, see tailscale.com@v1.94.1 which requires both github.com/santhosh-tekuri/jsonschema/v5 and /v6. Because Go treats different major versions as unrelated, Debian should too. Packaging only one of the required major versions is not always sufficient.

See https://lists.debian.org/debian-go/2025/10/msg00013.html for discussion. Related merge requests:

The following subsections summarize the changes; see Debian Go Packaging for the complete text.

New packaging best practices

The following new best practices (when packaging a Go module for use as a library) were added:

Clarified Naming Conventions

The Naming Conventions best practice was clarified and rationale was added. The most important clarification is that Debian package names should include a major version string (e.g., golang-*-v2-dev) when the Go module’s module path has a major version suffix (e.g., */v2).

Clarified File Locations

The File Locations convention was clarified to explicitly state that all module files—including go.mod and go.sum—should be installed to a subdirectory matching the full module path. Any major version suffix (e.g., /v2) should be included in the subdirectory.

2017-11 changes

“upstream” branch should contain upstream git history

TODO: describe the rationale and workflow, and how to deal with nonfree and vendored files

Migration

  1. Add upstream repository as a new remote. Then fetch its history.

    git remote add up https://github.com/paultag/go-topsort
    git fetch up
  2. Delete/Rename the old upstream branch, and checkout a new upstream branch.

    git branch -m upstream old/upstream
    git checkout -b upstream up/master
  3. Merge upstream history into the packaging branch, at the same point where the previous upstream was, usually based on release tags if upstream does releases; otherwise, the Debian release number will contain the commit ID.

    git diff <upstream_commit_id> old/upstream  # should be no differences
    git checkout master
    git merge --allow-unrelated-histories <upstream_commit_id>

Packaging new upstream release

When packaging new upstream release, you can fetch upstream remote and merge it into upstream branch.

If upstream does tag release, you can merge the new tag into upstream branch, and create a new tag with upstream/<version> format, which will be used by gbp.

git fetch up
git checkout upstream
git merge <upstream_tag>
git tag -a upstream/<version>
git checkout master
git merge upstream/<version>

If upstream doesn’t have tags, you can merge the latest commit into upstream branch, and create the upstream/<version> tag by commit date and id.

git fetch up
git checkout upstream
git merge up/master
TAG=$(git log --date=format:%Y%m%d --pretty=upstream/0.0_git%cd.%h -1)
git tag -a "$TAG"
git checkout master
git merge "$TAG"

Drop pristine-tar branches

Rationale

The appeal of using pristine-tar was that a byte-for-byte equal orig tarball could be easily (and automatically) generated, preventing rejected uploads and aiding future historians with reproducibly rebuilding older versions. Further, using pristine-tar results in a self-contained git repository which makes for a simple mental model (as opposed to the git repository + orig tarball in parent directory model).

In reality, pristine-tar branches weren’t consistently updated across our repositories for a number of reasons, resulting in despised additional maintenance effort for little benefit (uploads may or may not be rejected, depending on the repository state).

Hence, even though the new gbp push command and a consistent setting of pristine-tar=True in debian/gbp.conf might help improve consistency, we decided to abandon pristine-tar altogether.

Old workflow

  • Obtain a byte-for-byte equal orig .tar.gz file: pristine-tar list and pristine-tar checkout

  • Build against a byte-for-byte equal orig .tar.gz file: enable gbp buildpackage’s pristine-tar option, e.g. via --git-pristine-tar or pristine-tar=True in debian/gbp.conf.

New workflow

  • Obtain a byte-for-byte equal orig .tar.gz file: origtargz(1)

  • Build against a byte-for-byte equal orig .tar.gz file: use origtargz before building

Note
Using --git-upstream-tree=TAG (the default) is not sufficient to obtain a byte-for-byte equal orig .tar.gz file. In stapelberg’s tests, only 5% of pkg-go’s git repositories would match the orig .tar.gz in the archive.
Tip

Configure gbp-clone(1) to automatically run origtargz(1) by adding the following to ~/.gbp.conf:

[clone]
postclone=origtargz

Migration

  1. Remove any pristine-tar-related settings from this repository’s gbp config files, defaulting to pristine-tar=False:

    for f in .gbp.conf debian/gbp.conf .git/gbp.conf
    do
        [ -e "$f" ] && sed -i '/^pristine-tar/d' "$f"
    done
  2. Delete the pristine-tar branch: git push origin :pristine-tar

TODO: verify step 2 works

Auto-format debian/control

Rationale

Common formatting increases consistency between packages maintained by pkg-go and auto-formatting frees up time previously spent on manual formatting.

Old workflow

Manually format control files such as debian/control.

New workflow

Use wrap-and-sort(1) from the devscripts package in the root of the Debian package directory:

wrap-and-sort --wrap-always --trailing-comma

The command line arguments result in a format which produces minimal diffs whenever new values are added or old values are removed.

TODO: is there any editor integration for wrap-and-sort yet?

Tip

To auto-format before committing, create the following hook at .git/hooks/pre-commit:

#!/bin/sh
wrap-and-sort --wrap-always --trailing-comma

Migration

  1. Run wrap-and-sort --wrap-always --trailing-comma

Adopt DEP-14 branch naming

Rationale

Consistency in our branch naming makes it easier for team-internal and team-external contributors to understand/interact with our packaging repositories.

Old workflow

The default branch of a package was named master.

New workflow

See DEP-14 for the full text. In a nutshell:

  • The default branch of a package should be named debian/sid.

  • git HEAD should point to debian/sid.

  • The upstream git history should live in a branch named upstream.

    TODO: wait until discussion in #812721 came to an agreement

  • Packages which release into stable releases should use the codename of the target distribution, e.g. debian/bookworm.

Migration

  1. TODO: describe the branch rename.

  2. git symbolic-ref HEAD refs/heads/debian/sid

Derive debian/changelog from git history

Rationale

Some pkg-go repositories used the old workflow, some used the new workflow — this was just a personal preference of whoever last touched the repository.

Unifying this difference eases contributions to any pkg-go repository.

Old workflow

  • Document your changes in a pending debian/changelog entry with the special suite name UNRELEASED.

  • Document your changes in your git commit(s).

New workflow

  • Document your changes in your git commit(s).

  • Before uploading the package to Debian, use gbp dch -R --commit.

TODO(stapelberg): install https://paste.debian.net/hidden/c3a81ddf/ (git update hook which declines old-workflow d/changelog updates) in all pkg-go repositories

Migration

TODO: remove pending d/changelog entries from existing packages.