Repository navigation
Store worktree mount and enlistment ids outside the shared git config - #2129
Draft
Tyrie Vella (tyrielv) wants to merge 1 commit into
Draft
Tyrie Vella (tyrielv) wants to merge 1 commit into
Tyrie Vella (tyrielv) wants to merge 1 commit into
Conversation
A linked worktree mount wrote gvfs.mount-id and gvfs.enlistment-id with git config --local. Git resolves --local config for a linked worktree to the shared config, so each worktree mount overwrote the primary enlistment's ids. That corrupted telemetry correlation, because the mount id must be unique per mount of a given enlistment. It also added two unconditional writes of the shared .git/config to every worktree mount. A worktree now keeps its ids in its own repo metadata (.git/worktrees/<name>/.gvfs/databases/RepoMetadata.dat) and writes no git config for them: - SaveWorktreeMetadata replaces SaveCloneMetadata on the worktree mount path. It keeps an existing enlistment id, so the worktree enlistment id is stable across mounts. Before, every worktree mount generated a new one, and heartbeat and lock telemetry reported it. - The mount id is written to the new MountId key on each mount. - GVFSEnlistment.GetEnlistmentId and GetMountId read the worktree repo metadata without initializing RepoMetadata.Instance. - The mount process creates the worktree enlistment id before it creates its tracer, so the first mount of a new worktree has an enlistment id in its telemetry. The primary enlistment behavior does not change. Assisted-by: Claude Opus 4.8 Signed-off-by: Tyrie Vella <tyrielv@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tyrie Vella (tyrielv)
force-pushed
the
tyrielv/worktree-mount-ids
branch
from
October 12, 2026 21:10
ff59aec to
1009e08
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem and Context
A linked git worktree runs its own
GVFS.Mount.exe. During mount, the code wrotegvfs.mount-idandgvfs.enlistment-idwithgit config --local.Git resolves
--localconfig for a linked worktree to the shared.git/config. So a worktree mount overwrote the ids of the primary enlistment. The mount id must be unique for each mount of an enlistment, so this corrupted telemetry correlation. The two writes also added unconditional writes of the shared config to every worktree mount. On Windows, git writes config throughconfig.lockand a rename, and a concurrent reader can fail withPermission denied.The worktree identity was also not stable. Every worktree mount called
RepoMetadata.SaveCloneMetadata, which generated a newEnlistmentIdin the worktree metadata. Heartbeat and lock telemetry report that value.Changes
.git/worktrees/<name>/.gvfs/databases/RepoMetadata.dat). The worktree mount writes no git config for the ids.RepoMetadata.SaveWorktreeMetadatareplacesSaveCloneMetadataon the worktree mount path. It keeps an existing enlistment id, so each worktree has one stable enlistment id across mounts. That id is separate from the primary enlistment id.RepoMetadataadds aMountIdkey. The worktree mount writes a new mount id to it on each mount.RepoMetadata.TryReadIdsandTryEnsureEnlistmentIdread and create the ids without initializingRepoMetadata.Instance. For a worktree,GVFSEnlistment.GetEnlistmentIdandGetMountIduseTryReadIds.InProcessMountVerbcreates the worktree enlistment id before it creates the tracer. This gives the first mount of a new worktree an enlistment id in its telemetry.InProcessMount.LogEnlistmentInfoAndSetConfigValuesemits the sameEnlistmentInfoevent for both enlistment types. For a worktree, it writes the mount id to repo metadata instead of git config.WorktreeEnlistmentTestschecks that worktree ids come from the worktree repo metadata and not from the shared config. It also checks that a read does not create metadata, that a locked metadata file gives empty ids, and that the enlistment id is created only once.WorktreeTests.WorktreeMountKeepsPrimaryIdsAndHasStableWorktreeEnlistmentIdmounts and remounts a real worktree. It checks that the config ids of the primary do not change, that the worktree enlistment id stays the same, and that the worktree mount id changes.The primary enlistment behavior does not change.
Why not
extensions.worktreeConfiggit config --worktreecan store per-worktree values in git config, but it has three costs here:--localfrom a worktree still writes the shared config, so every worktree write site must change to--worktree.git worktree addrun from a linked worktree copies theconfig.worktreeof that worktree into the new worktree. A new worktree would start with the ids of its sibling.Repo metadata has none of these problems, and only the mount process reads the ids.
Known gaps and deliberate decisions
status.deserializePathstill writes the shared config from every worktree mount —RequiredGitConfigbuilds this value from the per-worktree.gvfspath.TrySetRequiredGitConfigSettingswrites it with--localwhen the value differs, so each worktree mount rewrites the shared value. Parallel worktree mounts can still race onconfig.lock. Deferred because a correct fix needs per-worktree git config. A follow-up PR will address it.InitializeWorktreeMetadatasaves repo metadata before it takes the per-worktree mount lock. A second concurrent mount of the same worktree can retry the metadata replace indefinitely, instead of reporting that a mount is already running. This behavior is pre-existing and this PR does not change it. No follow-up planned.EnlistmentInfodoes not include the id of the primary. Deferred because separate identity is the intended design. No follow-up planned.