Commit result recovery and the next draft
Closing owner handoffs — October 23, 2026
A closed Commit remains cached while its real workers and children drain. It now rejects reopening and new command presets during that retirement instead of presenting an inert window or replacing its completion callback. The repository and access remain owned until actual cleanup finishes; a later fresh Commit can open after the cache removes that owner.
Late progress, partial-patch, Log-picker and identity-Settings handoffs cannot reopen children or alter the draft after retirement or during a Quit question. Configurable child handoffs install their completion ownership first and recheck the accepted owner before presentation. The existing automatic saved patch view and live-dialog refresh behavior remain available.
The connected workflow evidence records actual checks and limits. Native owner retirement is a macOS lifetime adaptation, not a new upstream control or full dialog certification.
Pinned TortoiseGit: 7338078f8ddd924b8cddee35f512f2286072136d.
Complete the committed working state before the result
CommitDlg.cpp:967 invokes RestoreFiles before client PostCommit at
lines 975–990. The source then prunes committed changelists before returning. Mark for restoration captures the original working bytes; the
user can temporarily reduce those bytes for a commit. A successful commit must
restore the captured full working file while HEAD/index retain the selected
committed contents. The client post-commit hook must observe that restored
working file. The existing native workflow previously delayed restoration until
after the result's post-action acknowledgement, so the hook observed the reduced
file instead.
The connected completion workflow keeps actual Git success separate from later restoration, client-hook and changelist errors. A completion error must retain its recovery state and report that Git already committed. It must not silently retry Git or present a failed commit as though HEAD had not changed. Restoration retains the captured repository/access and replaces only the explicitly marked working paths. Source PostCommit runs only after successful Git; a rejected pre-commit hook remains a failed attempt. Original index/working-copy semantics and the existing failed-attempt Restore/Keep choice remain explicit.
Native restoration checks actual replacement errors and retains the remaining copies; the source CopyFile loop does not inspect individual failures. Native completion skips the client PostCommit hook when restoration failed and offers no post-action handoff until recovery is addressed. Cancelling remaining restoration/hook work cannot undo the Git commit that already succeeded. These are explicit native recovery adaptations, not Windows failure-path equivalence.
Git itself can create a commit and still return nonzero afterward. An actual
post-commit hook replacing a checked file with a directory reproduced a Git
mmap failed error after HEAD changed. Native progress retains that command
failure, compares captured before/after HEAD and warns that a commit may already
exist. The warning asks the user to inspect Log before retrying; it does not
claim ownership or success from a HEAD change that could be concurrent. Failure
history and Restore/Keep choices retain their ordinary acknowledgement order.
A separate actual replacement error after Git returns successfully exercises
native completion recovery without conflating these phases.
Retain attempted messages after failure
CommitDlg.cpp:1068–1081 reloads and saves nonempty attempted messages and the
relevant non-Amend backup even after Git failure. The native failure path
previously skipped history persistence. Attempt state belongs to the captured
message, issue processing, normalization and repository preferences; it is not
reconstructed from a newer draft after a delayed result. A preflight warning or
branch cancellation before Git is attempted does not count as a failed commit.
Failed progress acknowledgement precedes publication to Recent messages. Closing
or cancelling an owner must reject late completion callbacks instead of saving
into a later window's history or updating its controls.
Keep the visible draft separate from the attempt
The source uses m_sLogMessage for client PreCommit output, issue-ID insertion
and message-file formatting; those steps do not call the message control's
SetText. Native Commit previously published all three back to its visible
message. A real failed ReCommit with an issue ID failed the exact Undo check. Source
comparison also found this unregistered replacement of the visible draft; the
source keeps these buffers separate.
The editor now retains the raw user draft, with explicit editor commands such as Add Signed-off-by retaining their visible behavior. Local attempt text carries hook output, issue processing and formatting to Git/providers. Recent messages store the prepared attempt separately. The existing formatter receiver now asserts byte-exact raw editor text, byte-exact prepared history and exact Git commit bytes, rather than conflating the buffers. Failed commits retain raw editor text and its Undo target while history preserves the prepared attempt. The receiver waits for the actual native editor to become editable after model/refresh completion before invoking Undo; an earlier optimistic model-only wait consumed Undo while the editor was still disabled.
ReCommit begins a new editor draft
The source installs the next template and explicitly calls ClearUndoBuffer
at CommitDlg.cpp:1030, before running the next Start Commit hook. ReCommit is a
new draft with a new Undo boundary. Refresh, appearance updates, normal history
selection and failed commits must not clear the user's current Undo stack.
The next draft reads its template once, excludes leftover operation messages and
retains the separate issue field, as the source does. The template passes through
the actual Start Commit hook before the new editor session is published. Failed
or obsolete preparation retains the previous draft and Undo until a new snapshot
is accepted. A dedicated editor Undo manager keeps unrelated input-field Undo
separate. The connected editor session distinguishes the next draft from an ordinary
programmatic message update, including a next template identical to the old
text. Subsequent native edits remain normally undoable. Late updates from a
retired editor cannot reset a replacement editor's session.
Resetting Amend/author/date controls is part of installing that draft. Delayed SwiftUI checkbox callbacks must not reinstall the previous Amend/ordinary message or override the new template/Start-hook result. A later deliberate user toggle retains its ordinary metadata behavior. ReCommit restores the normal file list, selection and commit-specific controls, while the captured repository and saved completion-button preference keep their existing semantics.
Checkpoint and remaining work
The Debug app build and ten native case/engine checks passed across Apple and bundled Git through the grouped checkpoint and focused repairs. Core code was unchanged and its suites were not repeated. Actual private Git commits, client hook scripts, exact raw/history/commit bytes, Amend→ReCommit sessions, unrelated window Undo and manual restoration were checked. Held hook configuration and restoration scheduling exercise late cancellation/drain boundaries without claiming every live hung child process. Both Git engines reproduced the actual nonzero exit after a new HEAD and the separate native replacement error. All fifteen owned receivers, including failed attempts, were reaped and independently absent.
Recorded evidence retains the initial actor compile failure, actual Git partial-failure discovery, template-LF fixture correction, raw-buffer source correction and native view-settlement repair. Passing pre-repair unaffected cases were retained; only affected and previously unstarted checks ran afterward. The build has existing compiler/toolchain warnings. No new visual layout or screenshots are claimed for this behavioral batch. A complete current hosted CI pass was not established.
Physical keyboard/IME/VoiceOver, every external hook/plugin, live signed sandbox and installed Finder/App Store acceptance remain open. This family does not certify the entire Commit dialog or application port.