1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// SPDX-License-Identifier: MIT
//! [`WorktreeHandle`] — a live record of a managed git worktree.
use ;
/// Sentinel used for [`WorktreeHandle::branch_name`] when a worktree discovered
/// via [`WorktreeManager::reconcile`][crate::WorktreeManager::reconcile] is on a
/// detached `HEAD` rather than a branch (`git worktree list --porcelain` emits a
/// `detached` line instead of `branch refs/heads/<name>` for these entries).
///
/// The embedded space makes this an invalid git ref name: `git
/// check-ref-format` rejects any ref component containing a space (see
/// `git help check-ref-format` — disallowed characters include space, `~`,
/// `^`, `:`, `?`, `*`, `[`, `\`). `reconcile()` only ever populates
/// `branch_name` from a `branch refs/heads/<name>` porcelain line, and git
/// itself refuses to create a ref containing a space in the first place — so
/// no real branch, including one on a worktree foreign to zeph (i.e. not
/// created via [`WorktreeManager::create`][crate::WorktreeManager::create],
/// which further restricts the subagent-id component to
/// `^[A-Za-z0-9._-]+$`), can ever equal this sentinel. An earlier version of
/// this constant, `"(detached)"`, lacked this property: parentheses are
/// valid in git ref names, so a real branch literally named `(detached)`
/// would have been indistinguishable from a detached-HEAD worktree, causing
/// [`WorktreeManager::remove`][crate::WorktreeManager::remove] to silently
/// skip pruning it (#5936 review finding).
pub const DETACHED_BRANCH_SENTINEL: &str = "(detached HEAD)";
/// Sentinel used for [`WorktreeHandle::branch_name`] when a worktree discovered
/// via [`WorktreeManager::reconcile`][crate::WorktreeManager::reconcile] is the
/// main worktree of a bare repository (`git worktree list --porcelain` emits a
/// `bare` line, with no `HEAD` or `branch`/`detached` line at all, for these
/// entries).
///
/// Distinct from [`DETACHED_BRANCH_SENTINEL`] so operators and logs can tell
/// "no branch because this is a bare repo" apart from "no branch because HEAD
/// is detached" (#6052). Like [`DETACHED_BRANCH_SENTINEL`], the embedded space
/// makes this an invalid git ref name, so it can never collide with a real
/// branch.
pub const BARE_WORKTREE_SENTINEL: &str = "(bare repository)";
/// A live record of a git worktree that [`WorktreeManager`][crate::WorktreeManager]
/// has created for a subagent.
///
/// Handles are stored in-memory for the duration of the session. They are not
/// persisted to disk; on restart, [`WorktreeManager::reconcile`][crate::WorktreeManager::reconcile]
/// re-discovers handles from the git worktree registry.
/// A worktree discovered by [`WorktreeManager::reconcile`][crate::WorktreeManager::reconcile]
/// that is not present in the current process's own in-memory session state.
///
/// `prunable_reason` is git's own verdict from `git worktree list --porcelain`,
/// which git derives by checking whether the worktree's directory and `.git`
/// gitdir-link still exist and are valid — not by asking whether *this*
/// process happens to recognise the path. This is the only staleness signal
/// safe to force-remove on: a worktree created by a *different*, concurrently
/// running zeph session updates the same on-disk git worktree registry that
/// `reconcile` reads, so it is invisible to this process's `self.handles`
/// (documented as session-local, in-RAM-only) yet fully intact on disk, and
/// git will never mark it `prunable` while that's true.