Documentation
¶
Overview ¶
Package canonicalrescue moves uncommitted work out of a canonical clone onto a branch, without discarding anything and without disturbing the clone.
Why preservation is the whole design ¶
On 2026-08-27 a complete, unlanded 42-line lesson sat untracked in a canonical clone. It survived by luck: the next routine `git checkout` would have taken it, and no copy existed anywhere else. That is the cost this package exists to avoid, and it is why nothing here discards by default and why the discarding step is separated from the preserving one by an explicit flag and a proved receipt.
How the content is captured without touching the clone ¶
The obvious approaches are all unsafe here. `git stash` writes to a repository-global stash stack that every linked worktree shares, so a rescue in one clone shows up as a surprise entry for whoever looks next. `git checkout -b` moves the clone's HEAD, which is the state WB's own guard requires to stay put. And `git stash create` does not capture untracked files, which is exactly what nearly went missing.
So the capture runs entirely through a temporary index. The clone's real index is copied to a scratch file, the working tree is staged into that copy, a tree is written from it, and a commit is created with `git commit-tree` parented on HEAD. The result is a real branch holding the exact content — modified, staged, and untracked alike — while the clone's HEAD, branch, index, and working tree are all still byte-for-byte what they were.
Index ¶
- Constants
- func PushAttestationFromEnvironment() (branch, commit string, present bool, err error)
- func VerifyAttestedPush(ctx context.Context, root, projectsRoot, branch, commit string, ...) error
- type Change
- type Options
- type Report
- func Capture(ctx context.Context, report Report) (Report, error)
- func Inspect(ctx context.Context, path string, options Options) (Report, error)
- func Push(ctx context.Context, report Report, remote string) (Report, error)
- func Restore(ctx context.Context, report Report, allowUnpushed bool) (Report, error)
Constants ¶
const ( // PushBranchEnv and PushCommitEnv attest that a pre-push invocation was // opened by WB's rescue transport. The hook still proves the exact ref, // commit parent, and full captured tree before accepting this route. PushBranchEnv = "WB_CANONICAL_RESCUE_BRANCH" PushCommitEnv = "WB_CANONICAL_RESCUE_COMMIT" )
Variables ¶
This section is empty.
Functions ¶
func PushAttestationFromEnvironment ¶ added in v0.66.0
func VerifyAttestedPush ¶ added in v0.66.0
func VerifyAttestedPush(ctx context.Context, root, projectsRoot, branch, commit string, input io.Reader) error
VerifyAttestedPush proves that a pre-push operation is publishing only the exact rescue commit which captures the canonical clone's complete dirty state. It is the rescue route through managed hooks, not a hook bypass.
Types ¶
type Change ¶
type Change struct {
// Status is the two-character porcelain code, "??" for untracked.
Status string
Path string
}
Change is one path the clone holds that HEAD does not.
type Options ¶
type Options struct {
ProjectsRoot string
// Branch is the rescue branch name; empty derives one from the clock.
Branch string
// Now supplies the derived branch's timestamp; nil means time.Now.
Now func() time.Time
}
Options configures Inspect and Rescue.
type Report ¶
type Report struct {
Path string `json:"path"`
Repository string `json:"repository,omitempty"`
Branch string `json:"branch,omitempty"`
Head string `json:"head,omitempty"`
// Changes excludes ignored paths, so a generated .worktree.md never reads
// as work needing rescue.
Changes []Change `json:"changes,omitempty"`
// UntrackedCount is called out separately because untracked content is the
// part no reflog, no stash, and no remote can bring back.
UntrackedCount int `json:"untracked_count"`
// RescueBranch is the branch a rescue would create or did create.
RescueBranch string `json:"rescue_branch,omitempty"`
// RescueCommit is set once the content has been captured.
RescueCommit string `json:"rescue_commit,omitempty"`
// Pushed is true once the rescue branch exists on origin.
Pushed bool `json:"pushed"`
// Restored is true once the clone was returned to a clean base.
Restored bool `json:"restored"`
}
Report is what a canonical clone currently holds.
func Capture ¶
Capture moves the clone's uncommitted content onto a branch and leaves the clone exactly as it found it.
The clone stays dirty afterwards on purpose. Preserving and discarding are two decisions, and collapsing them into one is how a rescue turns into the loss it was meant to prevent. Restore performs the second, separately.
func Inspect ¶
Inspect reports what a canonical clone holds, and refuses any other path.
Refusing a linked worktree is deliberate. A worktree with uncommitted work is simply work in progress; there is nothing to rescue and nothing at risk.
func Push ¶
Push publishes the rescue branch, which is what turns a local capture into something a lost machine cannot take with it.
func Restore ¶
Restore returns the clone to a clean checkout of its own HEAD, and refuses to unless the content is provably somewhere else first.
`git clean` runs WITHOUT -x. Ignored paths — WB's own generated marker among them — are left alone; only the content the rescue commit now holds is removed.