Build branch switching and the popover git surface
GitBranchSwitcher holds 06's sequence as one object: settle editors
explicitly (SessionSettleGate — Save All applies raw buffers with
validation and a refused buffer cancels the whole switch; Discard
reverts buffers AND reconciles the session folders against HEAD;
never silent), flush the pending auto-commit, stamp intent in the
per-board registry, bracketed safe checkout (git_checkout_tree
GIT_CHECKOUT_SAFE + set_head — no path passes FORCE, abort
included), one reload via the async wholesale bracket (failed final
reload engages the existing read-only lock), reseed undo/redo from
the new HEAD with redo empty, clear the stamp. Create-and-switch
keeps the full sequence — the tree-cannot-change proof fails under
concurrent writers. Lock contention shows the 02 in-progress row's
waiting state ("waiting for another writer's git lock"), bounded at
30s then failing cleanly naming the lock path.
GitOperationStamp + GitOperationRecovery: the own-leftovers rule as
a pure conjunction — pause state AND matching stamp = the app's own
interrupted operation, aborted to the pre-operation state with a
banner, stamp cleared on success only; either alone defers to the
pause-and-defer stance. Checked where the committer starts.
BoardGitControls replaces the read-only branch line: branch picker,
inline create-and-switch, the abnormal-state pause note in 06's own
words with controls dimmed, and commit-identity fields that read and
write repo-local .git/config (derived default as placeholder, never
value; unfocused resync, focused keystrokes kept; 2s poll while
visible — .git is watcher-filtered by design).
Also fixes a shipped bug from the undo card: plan(reconciling:)
matched card ids as path prefixes, so the reconcile branch was inert
on every board (<lane>/<card> never matches a bare id) — a session
file the restore diff couldn't name (attachment, comment, draft)
survived Discard and landed in the next flush's commit. One shared
component-exact folder-name resolver now serves both Discard paths;
noteDiscarded takes cardFolderName; regression test verified failing
against the pre-fix code.
41 branch tests + the regression; 2374 tests / 409 suites green;
InertGitTests untouched.
Claude-Session: https://claude.ai/code/session_01SR4XGjmBE16ZUYWpfFHXwY
This commit is contained in:
@@ -334,6 +334,27 @@ public final class GitAutoCommitter {
|
||||
arm()
|
||||
}
|
||||
|
||||
// MARK: - The pause, asked for
|
||||
|
||||
/// **Re-reads the repository's state without attempting anything** — what the popover's git
|
||||
/// section calls when it appears (06 ▸ Rules ▸ Abnormal repo states: "the popover's git section
|
||||
/// names the state plainly").
|
||||
///
|
||||
/// The engine learns about a pause by *trying to commit* and being held, which is the right
|
||||
/// cadence for committing and the wrong one for a surface: a board opened into a detached HEAD
|
||||
/// would show live branch controls for as long as the debounce takes to fire. This is the same
|
||||
/// read the flush takes (`GitCommitOperation.reading`), asked by a surface instead of by a write,
|
||||
/// and it changes nothing else — no arming, no retry, no commit.
|
||||
///
|
||||
/// A flush landing while this is in flight wins, which is correct: it read the repository later
|
||||
/// and it read it in order to write.
|
||||
public func refreshPause() async {
|
||||
let root = boardRoot
|
||||
pause = await Task.detached(priority: .userInitiated) {
|
||||
GitCommitOperation.reading(at: root).pause
|
||||
}.value
|
||||
}
|
||||
|
||||
/// Whether a card window's folder is currently staged around — the stage-around rule, made
|
||||
/// assertable without reaching into private state.
|
||||
public var stagedAroundFolders: [URL] {
|
||||
|
||||
Reference in New Issue
Block a user