feat(doctor,why,use): detect local .git/config shadowing a binding#37
Merged
Conversation
A repo's local .git/config wins over the includeIf gitswitch writes (git precedence: local > global). When user.name/email/signingkey or core.sshCommand are set locally, they silently defeat a gitswitch binding — commits/pushes go out under the local identity while `why` happily reports the binding is active (the effective email matches only by coincidence). This is the #1 adoption trap: people who set per-repo identities the old way before adopting gitswitch. gitswitch now keeps control of the identity layer (still via includeIf) but makes the conflict visible and resolvable: - git: add LocalOverrides(dir) / UnsetLocal(dir, key) to detect and clear identity keys set in a repo's local .git/config. - why: replace the false "matches binding ✓" with a clear "⚠ binding shadowed by local .git/config" warning that lists the offending keys and the take-over command. - doctor: fold the same detection into the summary so it can no longer print "✓ all layers agree" while a binding is shadowed. - use: after binding, detect shadowing local config and prompt (y/N) to remove it so the binding actually takes effect; on decline or no-TTY it keeps them and prints the manual unset commands, and the closing message no longer promises automatic switching when overrides remain. - tests: cover LocalOverrides + UnsetLocal.
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.
What
A repo's local
.git/configwins over theincludeIfgitswitch writes (git precedence:local > global). So whenuser.name/user.email/user.signingkey/core.sshCommandare set in a repo's.git/config, they silently defeat a gitswitch binding — commits and pushes go out under the local identity, whilegitswitch whyhappily reports the binding is active (the effective email matches only by coincidence).This is the #1 adoption trap: anyone who set per-repo identities the old way (
git config user.email …) before adopting gitswitch hits it, and the tool gives them false confidence instead of a warning.gitswitch keeps control at the identity layer (still
includeIf, which is its whole value — one binding covers a tree, including repos cloned later) but now makes the conflict visible and resolvable.Changes
git:LocalOverrides(dir)detects identity keys set in a repo's local.git/config;UnsetLocal(dir, key)clears them.why: replaces the misleading(matches binding ✓)with⚠ binding shadowed by local .git/config, lists the offending keys, and shows the take-over command.doctor: folds the same detection into the final summary, so it can no longer print✓ all layers agreewhile a binding is silently shadowed.use: after binding, detects shadowing local config and prompts (y/N) to remove it so the binding actually takes effect. On decline or no-TTY it keeps the keys and prints the exact manualgit config --local --unsetcommands; the closing message no longer promises automatic switching when overrides remain.LocalOverrides+UnsetLocal(detect, no-op on clean repo, clear, idempotent re-unset).Before / after —
whyin a shadowed repoDesign note (non-goal)
gitswitch does not take over auth/credential management (gh account, HTTPS credential helper) — that's machine-wide, gh/keychain-owned state. This PR is detection + opt-in cleanup of git config shadowing only, consistent with
why/doctor's "tell me when my identity layers disagree" mission.Test plan
go build ./...,go vet ./...— cleango test ./internal/...— git package tests pass (incl. new ones)why/doctor/useagainst a real shadowed repo: shadowing is detected;useprompts and (on confirm) clears it; a non-shadowed repo shows no warning (no false positives).