Skip to content

Out-of-tree builds always report a "-dirty" git tag in sys.version #159440

Closed

Description

@sendaoYan

Bug report

sys.version embeds the output of git describe --all --always --dirty, which is compiled into the interpreter via -DGITTAG (Modules/getbuildinfo.o recipe in Makefile.pre.in). When CPython is built out-of-tree, that tag is always reported as -dirty, even when the source checkout has no local modifications, because configure.ac passes --git-dir without --work-tree.

Reproduction

$ git -C ~/git/cpython status --short    # clean checkout, no output
$ mkdir -p ~/build/cpython && cd ~/build/cpython
$ bash ~/git/cpython/configure --prefix=$HOME/opt/cpython > /dev/null
$ make -j && make install -j
$ ~/opt/cpython/bin/python3 -VV
Python 3.16.0a1+dev (heads/main-dirty:25883627946, Oct 14 2026, 22:17:06) [GCC 11.4.0]
                            ^^^^^

The -dirty suffix is bogus: the checkout is at 2588362 with an unmodified work tree.

Root cause

configure.ac defines the git commands used for the build stamp:

GITVERSION="git --git-dir \$(srcdir)/.git rev-parse --short HEAD"
GITTAG="git --git-dir \$(srcdir)/.git describe --all --always --dirty"
GITBRANCH="git --git-dir \$(srcdir)/.git name-rev --name-only HEAD"

--git-dir only says where the repository is; it does not set the work tree, which therefore defaults to the current directory. In an out-of-tree build, make runs in the build directory, so the internal diff-index HEAD that implements git describe --dirty resolves every tracked path against the build directory, where none of them exist. Every tracked file is treated as deleted, and the tree is reported as dirty.

Run from the build directory against a clean source tree:

$ cd ~/build/cpython
$ git --git-dir=$HOME/git/cpython/.git diff-index --name-only HEAD | wc -l
5490                                     # all tracked files appear deleted
$ git --git-dir=$HOME/git/cpython/.git describe --all --always --dirty
heads/main-dirty
$ git --git-dir=$HOME/git/cpython/.git --work-tree=$HOME/git/cpython describe --all --always --dirty
heads/main
$ strings ~/build/cpython/Modules/getbuildinfo.o | grep heads/
heads/main-dirty                         # the string that ends up in the binary

GITVERSION (rev-parse --short HEAD) and GITBRANCH (name-rev --name-only HEAD) are unaffected because they never touch the work tree — only the --dirty check is. In-tree builds are unaffected too, which is presumably why this went unnoticed.

Proposed fix

Pass the work tree explicitly (equivalently, run git with -C $(srcdir)):

GITVERSION="git --git-dir \$(srcdir)/.git --work-tree \$(srcdir) rev-parse --short HEAD"
GITTAG="git --git-dir \$(srcdir)/.git --work-tree \$(srcdir) describe --all --always --dirty"
GITBRANCH="git --git-dir \$(srcdir)/.git --work-tree \$(srcdir) name-rev --name-only HEAD"

The suffix keeps its intended meaning: local modifications to the source tree are still reported, while an out-of-tree build of a clean checkout now reports a clean tag. In-tree builds are byte-for-byte unaffected since $(srcdir) is ..

Workaround

Until this is fixed, an out-of-tree build can be nudged into reporting the right tag by overriding GITTAG and forcing Modules/getbuildinfo.o to be recompiled (it does not depend on Makefile, so reconfiguring alone will not rebuild it):

$ rm -f Modules/getbuildinfo.o
$ make -j GITTAG="git --git-dir=$PWD/../cpython/.git --work-tree=$PWD/../cpython describe --all --always --dirty"
$ make install

Affected versions

3.7 and later: --dirty was added by bpo-27593 (554626a, 2017-03-20) and first shipped in 3.7.0a1. Only out-of-tree builds are affected.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Activity

  1. added 3 commits that reference this issue on Oct 15, 2026
  2. added
    buildThe build process and cross-build
    on Oct 15, 2026
  3. added 3 commits that reference this issue on Oct 15, 2026
  4. sendaoYan commented on Oct 15, 2026

    @sendaoYan
    ContributorAuthor

    Fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    buildThe build process and cross-buildtype-bugAn unexpected behavior, bug, or error

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions