storage: filesystem, Add support for worktreeConfig extension#1877
Merged
storage: filesystem, Add support for worktreeConfig extension#1877
worktreeConfig extension#1877Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
Adds extensions.worktreeConfig support to the filesystem-backed storage so linked worktrees can read and overlay per-worktree config.worktree onto the common .git/config, aligning behavior with upstream Git worktree configuration.
Changes:
- Overlay
.git/worktrees/<name>/config.worktreeonto the base repo config whenextensions.worktreeConfig=true(filesystem storage only). - Fix
config.Mergebehavior for map fields sonil/empty maps don’t wipe previously-merged entries. - Remove
PlainOpenOptions.EnableDotGitCommonDirand makecommondirdetection unconditional.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
storage/filesystem/config.go |
Reads config.worktree (when enabled) and merges it into the returned config. |
config/config.go |
Adds Extensions.WorktreeConfig, improves map merge semantics, and marshals/unmarshals the new extension key. |
storage/filesystem/storage.go |
Declares filesystem storage support for worktreeconfig extension. |
storage/filesystem/dotgit/dotgit.go |
Adds helpers to open/create config.worktree. |
repository.go |
Makes commondir detection unconditional; improves nil options handling and not-exist checks. |
options.go |
Removes EnableDotGitCommonDir from PlainOpenOptions. |
repository_extensions.go |
Normalizes v0-valid extension keys to lowercase and documents the requirement. |
config/config_test.go |
Expands merge tests to cover map merge behavior and new extension field. |
x/plumbing/worktree/worktree_test.go |
Adds coverage for reading overlaid config.worktree in linked worktrees. |
worktree_test.go |
Updates linked-worktree open tests to reflect new PlainOpen behavior. |
COMPATIBILITY.md |
Documents worktreeConfig and config --worktree behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
1 task
The extension matching is case insensitive, so keep references to them in lower case format, as that is what is used during the matching process. Signed-off-by: Paulo Gomes <pjbgf@linux.com>
EnableDotGitCommonDir was an opt-in flag to detect and honor the commondir mechanism used by Git linked worktrees. Requiring callers to explicitly enable this behavior is both surprising and error-prone. Consumers of PlainOpen should not need to know whether a repository is a primary working tree or a linked worktree, nor whether it relies on a shared common directory. This distinction directly impacts core repository semantics, including object resolution and configuration lookup. Leaving it opt-in can lead to subtle and inconsistent behavior. Making commondir detection unconditional, abstracting this complexity away from callers, ensures a consistent and predictable repository handling which aligns with upstream Git. Signed-off-by: Paulo Gomes <pjbgf@linux.com>
Signed-off-by: Paulo Gomes <pjbgf@linux.com>
Previous to #1850, go-git was oblivious to Git extensions, which meant that at times it would try to handle repositories where the underlying feature was not fully supported. An example of that being worktreeConfig, meaning that any worktree specific config were being ignored. This commit adds that support to storage/filesystem, resulting into worktree configs being overlayed the local config, providing upstream parity with upstream Git. References: - https://git-scm.com/docs/git-worktree#_configuration_file Signed-off-by: Paulo Gomes <pjbgf@linux.com>
The internal merge helper had no case for reflect.Map, so map-typed fields (Remotes, Branches, Submodules, URLs) fell through to the default branch which called df.Set(sf), replacing the destination map wholesale. This caused two bugs: * An empty but non-nil source map (as produced by NewConfig) would overwrite a populated destination map, silently discarding all accumulated entries. * A non-empty source map would replace the destination map entirely, dropping any destination keys absent from the source instead of merging them together. Add a reflect.Map case that skips empty source maps unchanged and otherwise copies entries one-by-one, so destination keys not present in the source are preserved and source entries override same-key destination entries. Add table-driven tests covering nil source map, empty source map, disjoint key sets, and same-key override. Signed-off-by: Paulo Gomes <paulo@entire.io>
Signed-off-by: Paulo Gomes <pjbgf@linux.com>
When the worktreeConfig extension is active and a config.worktree file already exists, only the delta — options whose values are absent from or differ from the base config — is written to config.worktree. The base config is left untouched in that case. This mirrors the behaviour of 'git config --worktree' to some extend, and enable the use case whereby worktree-specific overrides live in config.worktree while shared settings remain in the common config. Signed-off-by: Paulo Gomes <paulo@entire.io>
charithe
added a commit
to charithe/cerbos
that referenced
this pull request
Mar 9, 2026
v5.17.0 includes strict extension checks (go-git/go-git#1861) but it causes problems for `worktreeconfig` because it wasn't added to the supported extension list until go-git/go-git#1877. Until it's released, we need to keep the version back. Signed-off-by: Charith Ellawala <charith@cerbos.dev>
charithe
added a commit
to cerbos/cerbos
that referenced
this pull request
Mar 9, 2026
v5.17.0 includes strict extension checks (go-git/go-git#1861) but it causes problems for `worktreeconfig` because it wasn't added to the supported extension list until go-git/go-git#1877. Until it's released, we need to keep the version back. Signed-off-by: Charith Ellawala <charith@cerbos.dev> Signed-off-by: Charith Ellawala <charith@cerbos.dev>
haines
pushed a commit
to haines/cerbos
that referenced
this pull request
Mar 16, 2026
v5.17.0 includes strict extension checks (go-git/go-git#1861) but it causes problems for `worktreeconfig` because it wasn't added to the supported extension list until go-git/go-git#1877. Until it's released, we need to keep the version back. Signed-off-by: Charith Ellawala <charith@cerbos.dev>
cgrdavies
added a commit
to cgrdavies/go-git
that referenced
this pull request
Apr 12, 2026
extensions() normalises all extension names with strings.ToLower, but the extensionsValidForV0 map keys were stored in camelCase. Because Go map lookups are case-sensitive, this caused every repository with extensions.worktreeConfig = true (set automatically by modern git when running `git sparse-checkout set` or `disable`) to fail to open with: core.repositoryformatversion does not support extension: worktreeconfig This regression was introduced in v5.17.0 by go-git#1861 and reported in go-git#1939 and go-git#1943. The fix has landed in main (v6) via go-git#1877 but was not backported to v5. This patch lowercases the three affected map keys to match the normalised input, resolving the regression without changing any other behaviour.
cgrdavies
added a commit
to cgrdavies/go-git
that referenced
this pull request
Apr 12, 2026
This patch makes go-git open repositories that have `extensions.worktreeConfig = true` set in their config — a common situation for modern git clients, since `git sparse-checkout set` and `git sparse-checkout disable` enable the extension automatically. There are two separate bugs in v5.17.x that must be fixed together: 1. extensions() normalises extension names with strings.ToLower, but the extensionsValidForV0 map keys were stored in camelCase. Go map lookups are case-sensitive, so the lookup for the normalised key "worktreeconfig" never matched the map key "worktreeConfig", and the V0 validation unconditionally rejected the extension. 2. After passing the V0 gate, verifyExtensions then checks every extension against builtinExtensions. worktreeConfig was missing from that map, so v5 still rejected it with "unknown extension: worktreeconfig". The first bug was introduced in v5.17.0 (go-git#1861). Both are fixed in main (go-git#1877) which is only available in v6-alpha. This patch applies the minimum viable backport for v5: lowercase the V0 map keys and add worktreeconfig to builtinExtensions. Per-worktree config files (.git/config.worktree) are not read, which matches behaviour prior to v5.17.0 — the shared repository config continues to work unchanged. Refs: go-git#1939, go-git#1943, go-git#1877
cgrdavies
added a commit
to cgrdavies/go-git
that referenced
this pull request
Apr 12, 2026
This patch makes go-git open repositories that have `extensions.worktreeConfig = true` set in their config — a common situation for modern git clients, since `git sparse-checkout set` and `git sparse-checkout disable` enable the extension automatically. There are two separate bugs in v5.17.x that must be fixed together: 1. extensions() normalises extension names with strings.ToLower, but the extensionsValidForV0 map keys were stored in camelCase. Go map lookups are case-sensitive, so the lookup for the normalised key "worktreeconfig" never matched the map key "worktreeConfig", and the V0 validation unconditionally rejected the extension. 2. After passing the V0 gate, verifyExtensions then checks every extension against builtinExtensions. worktreeConfig was missing from that map, so v5 still rejected it with "unknown extension: worktreeconfig". The first bug was introduced in v5.17.0 (go-git#1861). Both are fixed in main (go-git#1877) which is only available in v6-alpha. This patch applies the minimum viable backport for v5: lowercase the V0 map keys and add worktreeconfig to builtinExtensions. Per-worktree config files (.git/config.worktree) are not read, which matches behaviour prior to v5.17.0 — the shared repository config continues to work unchanged. Refs: go-git#1939, go-git#1943, go-git#1877
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.
Previous to #1850, go-git was oblivious to Git extensions, which meant that at times it would try to handle repositories where the underlying feature was not fully supported.
An example of that being worktreeConfig, meaning that any worktree-specific config were being ignored.
This PR adds that support to
storage/filesystem, resulting into worktree configs being overlayed over the local config, providing parity with upstream Git.Other changes were required in order to support this feature properly:
config.Mergebug whereby aniloremptymap resulted in incorrect merge. For example, iflocalconfig had remotes andworktreedidn't, the resulting merge would not contain any remotes.PlainOpenOptions.EnableDotGitCommonDir, makingcommondirdetection unconditional, abstracting this complexity away from callers.SetConfigso that it can distinguish delta changes and save them to the worktree-specific config only.Follow-up from #1850 and #1808.
Relates to #1812.