Skip to content

Add directory-tree identity bindings - #14922

Draft
williammartin wants to merge 2 commits into
williammartin-multiaccount-draft-02-repositoryfrom
williammartin-multiaccount-draft-03-directories
Draft

williammartin wants to merge 2 commits into
williammartin-multiaccount-draft-02-repositoryfrom
williammartin-multiaccount-draft-03-directories

Conversation

@williammartin

@williammartin williammartin commented Nov 3, 2026 •

Copy link
Copy Markdown
Member

Prototype overview and documentation

DO NOT MERGE. This stack is almost entirely vibe coded. These drafts are for handy review and prototyping, not merging as-is.

Expect the code to be really bad in places: highly coupled, handling edge cases that do not really matter, or doing suspiciously fragile things like parsing GraphQL request bodies.

I suspect some of the suspicious code also exposes the complexity of this feature set, because account selection, Git configuration, scope precedence, worktrees, SSH and API requests all interact.

The prototype experience is the purpose, not the code. I want to find out whether the experience is useful, not defend this implementation or treat it as a design to preserve.

Description

Follow on from #14921

Developers often organise repositories under work and personal directory trees, so selecting each repository repeats the same decision. This PR adds recursive directory bindings with more specific choices taking precedence.

Layer 3 of an eight-part prototype review stack. This is a way to review the design and implementation in smaller pieces, not a proposal to merge the current stack as-is.

How did you test this change?

I inspected the actual directory binding file, checked selection inside the tree, and exercised nested and repository overrides. I also checked that an external worktree inherits from the main checkout rather than its visible directory.

$ cd ~/projects/demo && gh api /user --jq .login
wilmartin_microsoft

A directory binding generates recursive gitdir rules

multiaccount-layer-3-01-Wiring---Layer-3---Directory-binding-file.mp4

A work-folder choice reaches existing and future repositories without changing the default account

multiaccount-layer-3-02-A-work-folder-choice-reaches-existing-and-future-repositories-without-changing-the-default-account.mp4

An external worktree inherits from the main checkout location, not its own folder

multiaccount-layer-3-03-An-external-worktree-inherits-from-the-main-checkout-location-not-its-own-folder.mp4

The deepest directory wins; a repository choice wins over directories; removing it restores the deeper fallback

multiaccount-layer-3-04-The-deepest-directory-wins-a-repository-choice-wins-over-directories-removing-it-restores-the-deeper-fallback.mp4

Key points

The managed file stores the directory scope and uses recursive includeIf conditions for .git and .git/worktrees/*. An explicit repository binding still wins, followed by the deepest matching directory.

The main repository location determines directory inheritance for linked worktrees. Moving a worktree outside the tree does not give it a different account.

Notes for reviewers

Compare the generated directory patterns with the repository-specific patterns in the previous layer. Removing a more specific choice should expose the remaining fallback rather than alter the saved active account.

The recordings use the product code at this layer, not a later stack endpoint. The included offline replay scripts are supplementary and do not reproduce the live-account recordings.

Offline replay on macOS

Build this layer, then run its synthetic scenario with an absolute executable path. This is a replay instruction, not a claim that the command below was used to make the videos.

make
env -i HOME="$HOME" PATH=/usr/bin:/bin:/opt/homebrew/bin \
  /bin/bash script/multiaccount-review/03-directories.sh --gh "$PWD/bin/gh"

Authorship and follow-up

Who wrote this:

  • A human wrote it.
  • An agent wrote it under close human direction.
  • An agent wrote it independently, and no human has guided the implementation beyond the initial prompt.

Who answers review comments:

  • @username will read and reply directly. Name the account.
  • An agent will draft replies and @username will read them before they are posted.
  • Nobody has explicitly committed to replying.

Acceptance Criteria

Prototype behaviour under review:

Given an identity is bound to a directory tree.

When I use an existing or newly created repository beneath that tree.

Then it inherits that identity unless a more specific binding applies.

DO NOT MERGE

williammartin and others added 2 commits November 3, 2026 22:10
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 965836ef-19ac-4473-ba1f-e326ce0f106b
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 965836ef-19ac-4473-ba1f-e326ce0f106b
Copilot AI balanced review requested due to automatic review settings November 3, 2026 21:10
@williammartin williammartin mentioned this pull request Nov 3, 2026
2 of 6 tasks

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Directory identity bindings lack validation for affected checkouts with local SSH overrides and incorrectly allow inherited identity selection in bare repositories.

2 open issues
What changed in this PR

This draft prototype extends repository-family identities with recursive directory bindings. It builds on #14921 so existing and future repositories can inherit an identity without changing the saved active account.

Changes:

  • Adds directory binding storage, recursive Git includes, and precedence: repository choices override the deepest matching directory.
  • Preserves linked-worktree inheritance from the main checkout and updates command help and cleanup output.
  • Adds inheritance, fallback, and cleanup tests plus isolated macOS replay scripts.
File Description
script/​multiaccount-review/​fixture.sh Adds shared, isolated offline replay support.
script/​multiaccount-review/​03-directories.sh Demonstrates nested directory and external-worktree inheritance.
pkg/​cmd/​root/​reset_experiment_test.go Exercises reset with a directory binding.
pkg/​cmd/​auth/​use/​worktrees_test.go Tests main-checkout inheritance and repository overrides.
pkg/​cmd/​auth/​use/​use.go Documents directory selection and precedence.
pkg/​cmd/​auth/​use/​use_test.go Adds future-descendant inheritance and unset coverage.
pkg/​cmd/​auth/​identity/​delete.go Includes directory bindings in cleanup descriptions.
pkg/​cmd/​auth/​gitcredential/​gist_production_test.go Uses directory identities in production-config credential tests.
pkg/​cmd/​auth/​gitcredential/​gist_identity_test.go Uses a directory identity for canonical-host credential coverage.
internal/​identity/​store.go Implements directory persistence, recursive includes, and resolution.
internal/​identity/​store_test.go Tests binding precedence, fallback, and explicit Git-directory selection.
internal/​identity/​hardening_test.go Tests removal of stale directory bindings without disturbing others.

Review effort: Balanced

Comment on lines +599 to +601
pattern := strings.TrimSuffix(filepath.ToSlash(binding.Directory), "/") + "/**/.git"
fmt.Fprintf(&config, "[includeIf %s]\n\tpath = %s\n", gitQuote("gitdir:"+pattern), gitQuote(path))
fmt.Fprintf(&config, "[includeIf %s]\n\tpath = %s\n", gitQuote("gitdir:"+pattern+"/worktrees/*"), gitQuote(path))
Comment on lines +741 to +742
if under(scopeDir, b.Directory) {
result.Matches = append(result.Matches, *b)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants