Skip to content

RequiredGitConfig force-writes core.repositoryformatversion=0, bricking any repo-format-v1 enlistment (reftable, sha256) #2119

Description

Summary

RequiredGitConfig unconditionally force-writes core.repositoryformatversion = 0 into the enlistment's local config. That value is re-asserted on clone, on every mount, and on repair. Any repository that legitimately uses a git repo-format-v1 extension is therefore bricked — every git command fails — and because mount re-applies the setting, a user cannot repair it by hand.

Today this is reachable via a global git config, and it becomes the default path as git moves toward reftable.

Where

GVFS/GVFS.Common/Git/RequiredGitConfig.cs:96

// This is to match what git init does.
{ "core.repositoryformatversion", "0" },

GetRequiredSettings is documented as returning settings that "override any existing local configuration values," and is applied at:

  • GVFS/GVFS/CommandLine/CloneVerb.cs:696 — TrySetRequiredGitConfigSettings
  • GVFS/GVFS.Mount/InProcessMount.cs:290 — TrySetRequiredGitConfigSettings, i.e. every mount
  • GVFS/GVFS/RepairJobs/GitConfigRepairJob.cs:87 — repair

The write is not "set if absent." In GVFSVerb.TrySetConfig (GVFS/GVFS/CommandLine/GVFSVerb.cs:680-683), isRequired: true means an existing value that differs is overwritten:

if (!existingConfigSettings.TryGetValue(setting.Key, out existingSetting) ||
    (isRequired && !existingSetting.HasValue(setting.Value)))
{
    GitProcess.Result setConfigResult = git.SetInLocalConfig(setting.Key, setting.Value);

So an existing repositoryformatversion = 1 is actively downgraded to 0, while the extensions.* key that required v1 is left in place.

Reproduction

Any v1 extension triggers it. Ref storage is the most relevant one, and init.defaultRefFormat is honored by git today:

$ git -c init.defaultRefFormat=reftable init /tmp/r
$ grep -E 'repositoryformatversion|refstorage' /tmp/r/.git/config
        refstorage = reftable
        repositoryformatversion = 1

# what GVFS force-writes on clone, on every mount, and on repair:
$ git -C /tmp/r config core.repositoryformatversion 0

$ git -C /tmp/r status
fatal: repo version is 0, but v1-only extension found:
        refstorage

Object format behaves identically:

$ git init --object-format=sha256 /tmp/s
$ git -C /tmp/s config core.repositoryformatversion 0
$ git -C /tmp/s status
fatal: repo version is 0, but v1-only extension found:
        objectformat

Verified with git 2.55.0.vfs.0.8.

Why it matters now

  • init.defaultRefFormat=reftable and init.defaultObjectFormat=sha256 are honored by current git. A user who has set either globally gets a broken enlistment from gvfs clone today.
  • Reftable is the direction git is moving for default ref storage, so this shifts from "user opted in" to "happens by default" without any change on the VFS for Git side.
  • The failure is not a clean error. The enlistment is unusable, the message points at git internals rather than at VFS for Git, and mount re-applies the bad value — so hand-editing .git/config back to 1 is undone on the next mount. That makes it hard to diagnose and effectively unrecoverable without knowing to look here.

Note that #2115 pins git init --object-format=sha1 during clone, which closes the sha256 axis for newly cloned enlistments. It does not address ref format, and it does not address a repo that reaches v1 by any other route, because the root cause is this force-write rather than the init defaults.

Suggested fix

Preferred: stop writing core.repositoryformatversion at all. The comment says the intent is "to match what git init does" — but git init already sets it correctly, so re-asserting it gains nothing and re-asserting it is exactly what does the damage. Dropping the key from the required set makes GVFS inherit whatever git chose, which is the correct value by construction.

Alternative, if an explicit guard is wanted: validate instead of write. If the repository is not a shape VFS for Git supports, fail the clone/mount with a clear message (for example "VFS for Git requires a sha1 repository with files ref storage") rather than writing a config value that breaks git. A git rev-parse --show-object-format / --show-ref-format check is cheap and gives a diagnosable error.

Either way it's worth auditing the rest of the required set for other settings that assert a value git is already responsible for — core.bare and core.logallrefupdates carry the same "for consistency with git init" comment and the same latent shape.

Related: #1033 (fast-fail via config extensions when using an incorrect git binary) is adjacent — both are about GVFS and git disagreeing on repository format expectations.

Activity

  1. tyrielv commented on Sep 25, 2026

    @tyrielv
    Contributor

    Note (machine-drafted, author-reviewed): pre-check replication across #2116 / #2121

    Note

    🤖 Machine-drafted, reviewed and approved by Tyrie Vella (@tyrielv) before posting.

    The pre-check pattern that guards the core.repositoryformatversion = 0
    force-write is now at four call sites — FastFetch, clone (TryInitRepo), mount
    (before TrySetRequiredGitConfigSettings), and repair (GitConfigRepairJob) —
    in each of #2116 (sha256 / ObjectFormat) and #2121 (reftable /
    RefStorage). That is eight guards total once both land.

    Neither PR removes the force-write itself — that root-cause removal is what this
    issue tracks. When it lands, those eight pre-checks can be unwound (the guard
    becomes unnecessary once RequiredGitConfig no longer downgrades
    core.repositoryformatversion beneath a v1-only extension). Filing this here so
    that cleanup is not forgotten.

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions