checkoutmarker

package
v0.72.2 Latest Latest
Warning

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

Go to latest
Published: Sep 1, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package checkoutmarker writes one `.worktree.md` into every checkout, stating what that checkout is and whether it may be written to.

Why a marker in every checkout, not only in the ones that must stay clean

The obvious design is a warning file dropped into canonical clones. It does not work: a negative signal present only where writing is wrong means a MISSING file reads as "nothing here objects, go ahead", which is exactly the wrong default for the checkout WB has not reached yet. A marker in every checkout inverts that. An agent reads one file and learns where it is, and absence means "unknown, verify" rather than "safe".

It also degrades to readers the PreToolUse guard cannot reach: Codex, a human, and any tool that has not been written yet.

Why it stays untracked

Committing `.worktree.md` and adding it to `.gitignore` does not work either: `.gitignore` has no effect on an already-tracked file, so a committed marker that WB rewrites shows up as ` M .worktree.md` — a dirty canonical clone, the very condition this exists to prevent — and conflicts on any pull that touches it. `git update-index --skip-worktree` is per-clone index state that silently reverts, which is not something to hang a safety guarantee on.

So WB generates the file locally and never commits it, and pairs every write with an ignore rule so `git status` stays clean. Verified against real Git: one entry in the common directory's `info/exclude` covers the canonical clone and every linked worktree cut from it, because linked worktrees have no `info/exclude` of their own. WB's own hooks read `git status --porcelain`, which never lists an ignored path, so the marker cannot trip the policy it advertises.

Index

Constants

View Source
const ExcludePattern = "/" + FileName

ExcludePattern is the ignore rule that keeps the marker out of git status. It is anchored so it can only ever match the checkout root's own marker.

View Source
const FileName = ".worktree.md"

FileName is the marker's name in every checkout.

Variables

This section is empty.

Functions

func EnsureExclude

func EnsureExclude(excludePath string) (bool, error)

EnsureExclude appends the marker's ignore rule to a Git exclude file, and reports whether it had to. Every other line in that file is preserved: it is the user's, and WB only ever adds to it.

func Equivalent

func Equivalent(left, right string) bool

Equivalent compares two markers ignoring only their timestamps, so a refresh that would change nothing but the clock leaves the file alone. That is what makes repeated runs — on every sync, every create — free.

func Render

func Render(descriptor Descriptor) string

Render produces the marker's exact contents: a machine-readable YAML document first, so a reader never has to parse prose, then the instructions a human or an agent acts on.

Types

type DescribeOptions

type DescribeOptions struct {
	// ProjectsRoot is the directory holding {owner}/{repository} clones.
	ProjectsRoot string
	// BaseBranch is the protected branch a canonical clone must stay on.
	BaseBranch string
	// Version identifies the WB build that generated the marker.
	Version string
	// Now supplies the timestamp; nil means time.Now.
	Now func() time.Time
}

DescribeOptions configures Describe.

type Descriptor

type Descriptor struct {
	Kind          Kind
	Writable      bool
	Repository    string
	CheckoutPath  string
	CanonicalPath string
	Branch        string
	BaseBranch    string
	Task          string
	WorktreesRoot string
	GeneratedAt   time.Time
	GeneratedBy   string
}

Descriptor is everything the marker states. The field names are the schema agents key their decisions off, so they are part of the contract.

type Inspection

type Inspection struct {
	Descriptor  Descriptor
	ExcludePath string
}

Inspection is a described checkout together with the exclude file that keeps its marker out of git status.

func Describe

func Describe(path string, options DescribeOptions) (Inspection, error)

Describe resolves what a checkout is, using filesystem reads only.

No Git process is started. Everything the marker states is already on disk: the shape of `.git` says whether the checkout is primary or linked, the `gitdir:` pointer says which canonical clone a worktree belongs to, and HEAD says which branch it is on. Keeping it process-free is what lets `wb sync` and `wb worktree create` refresh markers across the whole fleet without paying for a fork per checkout.

type Kind

type Kind string

Kind is what a checkout is.

const (
	// KindCanonical is the shared clone at <projects-root>/<owner>/<repository>
	// that every worktree in the fleet is cut from. It must stay clean.
	KindCanonical Kind = "canonical"
	// KindWorktree is a linked worktree: an isolated checkout that exists to be
	// written to.
	KindWorktree Kind = "worktree"
)

type Result

type Result struct {
	// MarkerPath is where the marker lives.
	MarkerPath string
	// MarkerWritten is false when the marker was already exactly right.
	MarkerWritten bool
	// ExcludePath is the ignore file WB kept the rule in.
	ExcludePath string
	// ExcludeWritten is false when the rule was already present.
	ExcludeWritten bool
}

Result reports what one Apply call did.

func Apply

func Apply(descriptor Descriptor, excludePath string) (Result, error)

Apply writes the marker and its ignore rule, and is safe to run repeatedly.

The ignore rule goes first. A marker written before its rule exists is a dirty checkout for as long as the gap lasts, and WB's own pre-commit and pre-push hooks refuse a checkout with an untracked file — so the wrong order would, for that instant, break exactly the policy the marker describes.

func (Result) Changed

func (r Result) Changed() bool

Changed reports whether anything on disk moved.

Jump to

Keyboard shortcuts

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