fetchgit: disable git maintenance

By default, Git commands will trigger background processes to perform
repository maintenance.  As of Git v2.54.0, and in particular as of
452b12c2e0 (builtin/maintenance: use "geometric" strategy by default,
2026-02-24), Git has changed the strategy it uses to decide whether
maintenance needs performing, and as a result will kick off background
maintenance processes much more often.

These background processes will potentially change the contents of the
`.git` directory while `nix-prefetch-git` is deleting it.  This results in
effectively random failures, when files are added to the `.git`
directory during the `rm -rf` operation (causing it to fail) or after
the operation has completed (causing the `.git` directory to be
recreated and resulting in a FOD hash mismatch).

This also causes problems for the determinism of Git's own tests.
They've resolved this in 09505b1115 (t: fix races caused by background
maintenance, 2026-02-24) by having the maintenance processes run in the
foreground.  The discussion in that commit explains they considered just
disabling maintenance entirely, but opted for the foreground option
because disabling maintenance would mean the tests looked even less like
how most Git users work with Git.

`nix-prefetch-git` is nothing like most Git users.  In almost every
case, the `.git` directory will be deleted during or immediately after
the script is called.  The repositories certainly don't benefit from
ongoing maintenance.  To avoid the non-determinism created by the
background maintenance processes, just disable maintenance entirely.

This is done with `git config` after initialising the repository, rather
than `git config --global` earlier in the script, as `git config
--global` will fail if `fetchgit` was called with a `gitConfig`
argument.

It would be possible to set this option with
`GIT_CONFIG_[COUNT|KEY_<n>|VALUE_<n>]` environment variables; I've opted
against that because (a) they're less familiar to most people who might
want to come to edit this script in future and (b) because if someone is
using those values themselves via `impureEnvVars` or similar, making our
configuration play nicely with someone else's would require some fairly
complex logic.

I haven't made this a configurable option: any use of `nix-prefetch-git`
will run with maintenance disabled, as I cannot think of a use case
where it would be useful.  If there is such a use case, it would be
straightforward to extend `nix-prefetch-git` and `fetchgit` to allow
users to change the behaviour.

Fixes #524215.
This commit is contained in:
Adam Dinwoodie
2026-05-26 13:28:16 +01:00
parent f9d8b65950
commit 011471c7f2

View File

@@ -123,6 +123,10 @@ fi
init_remote(){
local url=$1
clean_git init --initial-branch=master
# Disable maintenance: it's not useful for a short-lived clone, and
# background maintenance causes non-deterministic builds.
# https://github.com/NixOS/nixpkgs/issues/524215
clean_git config maintenance.auto false
clean_git remote add origin "$url"
if [ -n "$sparseCheckout" ]; then
git config remote.origin.partialclonefilter "blob:none"