Skip to content

feat(pool)!: key pool identity by repository and support bare repos#41

Open
baruch wants to merge 1 commit into
kunchenguid:mainfrom
baruch:feat/repo-keyed-pool-bare-support
Open

feat(pool)!: key pool identity by repository and support bare repos#41
baruch wants to merge 1 commit into
kunchenguid:mainfrom
baruch:feat/repo-keyed-pool-bare-support

Conversation

@baruch

@baruch baruch commented Jun 26, 2026

Copy link
Copy Markdown

Summary

Pool identity was derived from git rev-parse --show-toplevel, so:

  • every checkout of a repo produced its own pool (<worktree-basename>-<hash>), and
  • get/status/prune refused to run from a bare repo (--show-toplevel has no work tree).

As a result, sibling worktrees off one repository — e.g. a bare-repo + .bare layout, or several git worktree checkouts — could never share a single pool, and the pool you got depended on which checkout you happened to be standing in.

This PR keys pool identity off the repository's common git dir (shared by every linked worktree and the bare repo itself) and lets the read/acquire commands run from a bare repo.

What changed

  • Repo-keyed pool identity. config.ResolvePoolDir now resolves the common git dir from whatever directory it is handed, so get/status/prune/return/destroy all converge on one pool per repository regardless of which worktree (or the bare repo) they run in. The pool name is <repoName>-<hash>:
    • repoName comes from git.RepoNameFromCommonDir (a .git/.bare marker yields its parent dir's name; a standalone bare dir yields its own basename minus a .git suffix);
    • hash is the origin remote URL when present, falling back to the main repo root (git.MainRootFromCommonDir, stable across worktrees) for local-only repos.
    • The pool root (parent dir) is still anchored on the passed-in dir, so relative root config stays repo-context dependent.
  • Bare-repo support. get/status/prune resolve their working directory via the new git.ResolveWorkDir (the working-tree root when one exists, otherwise the common git dir), so they run from a bare repo or a gitdir-file parent (e.g. the .bare layout), not only from a checkout. Worktree-creating git ops (AddWorktree, GetDefaultBranch, Fetch) already work fine from a bare dir. init still requires a working tree.
  • New internal/git helpers: CommonGitDir, ResolveWorkDir, RepoNameFromCommonDir, MainRootFromCommonDir, RepoName (Windows-safe path handling via filepath.FromSlash).

Tests

  • internal/git: RepoNameFromCommonDir, MainRootFromCommonDir, CommonGitDirStableAcrossBareLayout, ResolveWorkDirWorktreeAndBare.
  • internal/config: ResolvePoolDir_SharedAcrossWorktreesAndBare, ResolvePoolDir_LocalOnlySharedAcrossWorktrees (plus existing single-checkout tests, which still pass unchanged → backward compatible).
  • internal/pool: Acquire_SharedPoolAcrossWorktreesAndBare — end-to-end get flow (ResolveWorkDirResolvePoolDirAcquire) from two sibling worktrees and the bare dir all land in one shared pool, and the bare-driven acquire yields a detached checkout on the default branch.
  • go test ./..., GOOS=windows go build ./..., go vet ./..., and gofmt all clean.

BREAKING CHANGE

Pool identity changed from the old per-worktree-basename scheme.

  • Single-checkout repos are unaffected and keep their existing pool — remote repos because the hash is still the remote URL; local-only repos because the main-root hash reproduces the old worktree-toplevel value.
  • Repos used from multiple differently-named checkouts orphan their old per-checkout pools (the worktrees stay on disk, just unreferenced under the new shared pool name). Clean up the stale pools with treehouse prune / treehouse destroy.

🤖 Generated with Claude Code

Pool identity was derived from `git rev-parse --show-toplevel`, so every
checkout produced its own pool (`<worktree-basename>-<hash>`) and
`get`/`status`/`prune` refused to run from a bare repo. Sibling worktrees off
one repo could never share a pool.

Key pool identity off the repository's common git dir instead, resolved inside
`config.ResolvePoolDir` from whatever directory it is handed, so
`get`/`status`/`prune`/`return`/`destroy` all converge on one pool per repo
regardless of which worktree (or the bare repo) they run from. The pool name is
`<repoName>-<hash>`; the hash is the origin remote URL, falling back to the main
repo root (stable across worktrees, and identical to the old value for a classic
single checkout) for local-only repos.

`get`/`status`/`prune` now resolve their working directory via
`git.ResolveWorkDir` (working-tree root, else the common git dir), so they run
from a bare repo or a `.bare` gitdir-file parent, not only a checkout.

BREAKING CHANGE: pool identity changed from the per-worktree-basename scheme.
Repos used from multiple differently-named checkouts orphan their old
per-checkout pools (clean up with `prune`/`destroy`). Single-checkout repos are
unaffected and keep their existing pool.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

1 participant