feat(config): local-context-first config via git local config#23
Open
bezhermoso wants to merge 6 commits intoblock:mainfrom
Open
feat(config): local-context-first config via git local config#23bezhermoso wants to merge 6 commits intoblock:mainfrom
bezhermoso wants to merge 6 commits intoblock:mainfrom
Conversation
…mantics
Add wt_read_git_config() to lib/wt-common, enabling repos to carry their
own wt configuration via standard `git config --local wt.*` keys. This
removes the hard dependency on ~/.wt/repos/<name>.conf for repos that
prefer self-contained configuration.
New four-tier config precedence (highest to lowest):
1. Git local config (wt.* keys in .git/config)
2. Environment variables
3. Context .conf file (~/.wt/repos/<name>.conf)
4. Hardcoded defaults
The function reads wt.* keys atomically: all four required keys
(wt.mainRepoRoot, wt.worktreesBase, wt.ideaFilesBase, wt.baseBranch)
must be present or the entire git config source is ignored with a
diagnostic warning. This prevents confusing partial-config states.
Key design choices:
- All-or-nothing validation prevents half-configured repos
- Works transparently from worktrees (git config --local reads from
the main repo's .git/config automatically)
- Case-insensitive key matching per git convention
- Bash 3.2 compatible (uses tr instead of ${key,,})
- Read-only: wt never writes to git config
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
wt.mainRepoRoot is redundant when using git local config — the main repo root is always derivable via `git rev-parse --git-common-dir` (its parent directory), which works correctly from both the main repo and any worktree. Reduce required git config keys from 4 to 3: - wt.worktreesBase (required) - wt.ideaFilesBase (required) - wt.baseBranch (required) - wt.mainRepoRoot (optional override, auto-derived if absent) This means the minimal setup is now: git config --local wt.worktreesBase ~/src/repo-worktrees git config --local wt.ideaFilesBase ~/src/repo-idea git config --local wt.baseBranch main Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mainRepoRoot is always derivable from git — there's no reason to let users set it, and doing so just creates a point of conflict between what git says and what the config says. Now always derived via git-common-dir; the key is no longer recognized even if present in .git/config (silently ignored). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
In zsh, `local var` on an already-declared variable prints its current value to stdout. Declaring `lkey` inside the while loop caused it to print on every iteration after the first. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
wt_show_help() force-reloads config from .conf to pick up context changes, but this clears the git local config values. Add wt_read_git_config after the reload so help displays the actual effective values. Only wt-help gets this treatment — context switching and completions intentionally reload from .conf only, since they serve the context system (not the local repo). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add an explicit opt-in gate so repos don't accidentally pick up local config. Users must set `git config --local wt.enabled true` before any other wt.* keys take effect. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
guodong-sq
reviewed
Feb 26, 2026
Collaborator
guodong-sq
left a comment
There was a problem hiding this comment.
do the values set in wt_read_git_config need to go through _wt_expand_path()?
| # are present. | ||
| # | ||
| # Sets variables unconditionally — git local config has highest priority. | ||
| wt_read_git_config() { |
Collaborator
There was a problem hiding this comment.
should this be called by wt_load_context_config?
Contributor
Author
There was a problem hiding this comment.
It seem to me that wt_load_context_config's purpose is to load config from a context's *.conf files. I think it's wrong to override that with git local configs. I see these two as the two possible sources to pick from.
Perhaps what we need is a wt_load_config --from=(git|context|ordered)?
--from gitload from local git config only--from contextload from current context only--from orderedtry loading fromgitfirst, thencontextfallback (the default behavior to achieve local-context-first)
| } | ||
|
|
||
| # Parse config file into shell variables (no sourcing) | ||
| # Only sets variables that aren't already set in the environment |
Collaborator
There was a problem hiding this comment.
This is no longer true with the added wt_read_git_config
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.
Summary
Adds support for reading wt configuration directly from a repo's
.git/config, enabling local-context-first semantics: a repo can carry its own wt configuration without requiring~/.wt/repos/<name>.conforwt context addsetup.This means a user can configure a repo once:
...and all
wtcommands Just Work from inside that repo or any of its worktrees, with no global context setup needed.How it works
A new
wt_read_git_config()function inlib/wt-commonis called at source-time, before the existingwt_read_config(). It checks for thewt.enabled=truegate, readswt.*keys from the repo's local git config viagit config --local --get-regexp '^wt\.', validates them, and sets the correspondingWT_*shell variables.Config precedence (highest to lowest)
wt.*in.git/config)wt.enabled=trueand all required keyswt-commonsourced.conffile~/.wt/repos/<name>.confhas the valueGit config keys
wt.enabledtrue)wt.worktreesBaseWT_WORKTREES_BASEwt.ideaFilesBaseWT_IDEA_FILES_BASEwt.baseBranchWT_BASE_BRANCHwt.activeWorktreeWT_ACTIVE_WORKTREEwt.metadataPatternsWT_METADATA_PATTERNSWT_MAIN_REPO_ROOTis always auto-derived fromgit rev-parse --git-common-dirand is not a configurable key. This eliminates a potential source of conflict between what git says the repo root is and what the user configured.All-or-nothing validation
All three required keys must be present and non-empty. If any is missing, no git config values are applied and a diagnostic warning is printed to stderr naming the missing keys.
Key design choices
wt.enabled=truemust be set — repos don't accidentally pick up local configgit config --localin a worktree reads from the main repo's.git/configautomatically, so config set once in the main repo is visible from all worktreesgit-common-dirto avoid stale/conflicting valuesgit configcommandstrfor case-insensitive key matching (macOS ships bash 3.2)wt.enabled=trueare silently skipped; the context system and env vars continue to work exactly as beforewt helpcallswt_read_git_configafter a force-reload — context switching and completions intentionally reload from.confonlyWhat's NOT changing
wt configsubcommand (users usegit configdirectly)wt context add/install.shsetup flows.conffile format or context systemTest plan
wt-remove --mergedis unrelated)git config --local wt.enabled true+ set 3 required keys,wt helpshows valuescdinto a worktree of that repo — same resultwt.enabled false, runwt help— falls back to.conf/defaultswt.baseBranch(incomplete), runwt help— warning on stderrwt helpshows.conf/default values, no warning🤖 Generated with Claude Code