worktree

package
v0.2.0-alpha.8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 6, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Index

Constants

View Source
const Dir = ".buildmax/worktrees"

Dir is the directory worktrees live in, relative to the repository root. It is excluded through .git/info/exclude rather than .gitignore, which is the user's tracked file. See docs/design/workspace-root-and-worktrees.md D1.

Variables

View Source
var (
	// ErrNotARepository is returned when the current root has no repository to
	// take a worktree from.
	ErrNotARepository = errors.New("not a git repository")
	// ErrOccupied is returned when a live session holds the target worktree.
	ErrOccupied = errors.New("worktree is in use by another session")
	// ErrNotAWorktree is returned when a path is not a worktree of this
	// repository, which is the containment rule in D3.
	ErrNotAWorktree = errors.New("not a worktree of this repository")
	// ErrHasWork is returned when removing would discard uncommitted files or
	// commits nothing else reaches.
	ErrHasWork = errors.New("worktree holds work that removal would discard")
)

Functions

This section is empty.

Types

type Created

type Created struct {
	Name   string
	Path   string
	Branch string
	Head   string
	// LeftBehind lists the uncommitted paths still in the tree the session
	// came from. Silence here is not acceptable: the conversation may describe
	// code the new tree cannot see (D6).
	LeftBehind []string
}

Created reports what a creation produced, including what did not come along.

type Held

type Held struct {
	Created
	// contains filtered or unexported fields
}

Held is a worktree this session made for something else to work in — a delegate — and holds open on its behalf. The session's own root does not move: the parent goes on working where it was, which is the whole point of delegating rather than switching.

func (*Held) Release

func (h *Held) Release() error

Release drops the occupancy lock. The worktree itself stays: nothing removes one automatically, delegate or not (D5).

type Info

type Info struct {
	Name     string
	Path     string
	Branch   string
	Current  bool
	Occupied bool
	// Holder names the session in the tree, when one is there.
	Holder string
	// Dirty counts uncommitted files and Unmerged counts commits no other ref
	// reaches: what removing the tree would discard, which is the signal D5 says
	// a listing owes the user in place of automatic cleanup. Both are
	// best-effort — a tree whose status cannot be read reports zero rather than
	// failing the whole list.
	Dirty    int
	Unmerged int
}

Info describes one worktree for a listing.

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager owns the worktree lifecycle for one session: it decides what may be entered, holds the occupancy lock while the session is inside, and is the only thing that moves the root.

One session is in at most one worktree at a time, so the held lock is a single field rather than a set.

func NewManager

func NewManager(root Root) *Manager

NewManager returns a manager over root, which must already be at the session's launch directory.

func (*Manager) Close

func (w *Manager) Close() error

Close releases the occupancy lock without moving the root, for a process that is shutting down. The worktree itself is left alone: removing it is the user's call, never a side effect of exiting (D5).

func (*Manager) Create

func (w *Manager) Create(ctx context.Context, name string) (Created, error)

Create makes a worktree, enters it, and reports what stayed behind.

The branch is created from the current HEAD so the new tree matches the conversation that asked for it. A colliding name fails rather than being silently suffixed: a model that meant to return to an existing tree would otherwise quietly get a second one (D9).

func (*Manager) CreateDetached

func (w *Manager) CreateDetached(ctx context.Context, name string) (*Held, error)

CreateDetached makes a worktree and holds it without entering it.

The lock is taken for the same reason a session entering one takes it: while a delegate is working there, nothing else may. It is released when the delegate finishes, not when the tree is removed.

func (*Manager) Current

func (w *Manager) Current() string

Current returns the worktree the session is in, empty when it is in its launch directory.

func (*Manager) Enter

func (w *Manager) Enter(ctx context.Context, path string) error

Enter moves the session's root into an existing worktree.

Two rules gate it. The target must be a worktree of this repository, which keeps the set of reachable roots closed (D3). And no live session may be in it: two sessions writing one tree is the race this feature exists to avoid, so it is excluded rather than reported.

func (*Manager) Leave

func (w *Manager) Leave(ctx context.Context) string

Leave returns the session to its launch directory and releases the lock. It is a no-op outside a worktree.

func (*Manager) List

func (w *Manager) List(ctx context.Context) ([]Info, error)

List reports every worktree of the repository, with occupancy.

func (*Manager) Remove

func (w *Manager) Remove(ctx context.Context, path string, discard bool) error

Remove deletes a worktree and its branch.

It refuses a tree holding uncommitted files or commits no other ref reaches unless discard is set, because that tree may hold the only copy of the work. Nothing removes a worktree on its own — not at session end, and not later for one a crashed session left (D5).

func (*Manager) Repo

func (w *Manager) Repo() (string, error)

Repo returns the repository the session launched in, or ErrNotARepository.

func (*Manager) WithHooks

func (w *Manager) WithHooks(r agent.HookRunner) *Manager

WithHooks returns a copy of m that announces what it does. The events are advisory: a hook cannot veto a move, because the tool call that asked for it already passed PreToolUse and a second gate over the same decision could only leave a worktree half-created.

type Root

type Root interface {
	Root() string
	Set(dir string)
}

Root is the session's workspace root: the value tools resolve against, and the one thing this package moves. An interface rather than a concrete type because agentapp owns that state and imports this package, not the reverse.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL