Merge dialog parity
The generic Merge prompt is replaced by a separate resizable native window.
Baseline: 7338078f8ddd924b8cddee35f512f2286072136d, MergeDlg.cpp,
MergeDlg.h, IDD_MERGE, CChooseVersion, MergeCommand.cpp and
AppUtils.cpp::DoMerge. Compare with the
upstream Merge manual
and Git merge documentation.
Implemented
Current branch above From (Branch, Tag and Commit rows), followed by Option and Merge Message groups, then OK/Cancel/Help. The current local branch is excluded from the branch choices. A configured remote push branch is preferred when its ref exists; detached HEAD is displayed explicitly. Branch browsing has a filtered reference sheet; Commit browsing uses native Log in single-revision chooser mode. The controller retains repository access and routes the chooser's existing reference/checkout/Push actions to their native dialogs.
Squash disables the message editor and No Fast Forward. No Fast Forward disables
Squash and Fast Forward Only; Fast Forward Only disables No Fast Forward. No
Commit remains independent. Messages enables its count, initially positive
merge.log or 20. Strategy choices and recursive options match the pinned source.
Only recursive enables strategy options; rename-threshold/subtree enable the
parameter. Hidden option/parameter values are ignored as upstream does. The
message defaults to <Auto Generated by Git>, which sends no custom message.
Squash also ignores the disabled editor.
The actor invokes Git with literal argument arrays and validates the selected
commit, option combinations, count and strategy parameters before merging. It
uses the selected ref name for generated messages and --no-edit for unattended
message handling. It supports squash, no-commit, fast-forward flags, log summaries,
strategy/option/parameter and a custom multiline message. Failure retains Git's
conflict/recovery state and shows the error; open status/log/Commit windows and
the originating repository view are refreshed after success or failure.
Verification
Five real-Git integration tests cover fast-forward preserving unrelated mixed index/worktree edits, No Commit's fast-forward semantics, forced merge parents, custom messages and summaries, pending MERGE_HEAD/message state, squash from an annotated tag, validation before mutation, diverged fast-forward rejection, conflicts remaining abortable, and different ours versus recursive/theirs results. These tests establish the backend cases rather than full UI parity.
Native QA used /private/tmp/TurtleGitMergeDialogQA: Squash prevented editing;
Messages and fast-forward controls followed the upstream enablement. OK with
No Fast Forward, No Commit, Messages and a custom message preserved HEAD, set
MERGE_HEAD to the selected feature branch, staged its file and generated the
expected custom body and summary. Commit then loaded the pending message; enabling
staging mode and committing produced both expected parents, the feature file and
a clean index/worktree. The unrelated untracked file survived both operations.
A separate disposable layout fixture verified native Commit-chooser Cancel,
recursive strategy option enablement, rename-threshold parameter enablement,
Escape and Cancel. HEAD/index/worktree remained unchanged.
site/assets/merge.png is an actual 1360 × 1204 native capture of the final layout.
Still partial
- Issue tracking and spelling/completion. Native editor font preferences and window geometry is implemented; physical geometry acceptance remains pending.
- Full reference chooser controls, persisted revision history and native chooser acceptance with a different branch/commit, tag merge and detached/unborn cases.
- Physical progress/sheet/cancellation and post-action routing acceptance, live streaming, displayed conflict-hint acceptance, git-svn post-action and physical cancel-to-Abort flow.
- Activated Abort Merge context-menu acceptance and three-way conflict editor. The native Abort dialog/models are implemented; physical conflict recovery remains unverified.
- Interactive hooks/signing/editor workflows, strategy variants, user-data/rebase guards, dark/minimum-window/keyboard/sandbox runtime QA.
No complete Merge parity or App Store readiness is claimed. Completing pending merges currently requires Commit staging mode; checked-file merge completion remains an existing limitation.
Progress and recovery post-actions
Merge now runs the captured options/message in an owned native progress sheet. The options window remains fixed until that sheet closes. Command output and success/failure are retained instead of immediately closing the dialog. Exactly one pending operation can dispatch. Closed models cannot merge, and attached reference/progress sheets prevent closing the owner. Commands retain the original merge ref name for Git's generated message. Each Merge request owns a fresh options window so new requests cannot reset an existing draft or operation.
Failure offers Resolve and Commit when the index has conflicts, then an explicit Merge unrelated histories retry when there is no common ancestor, followed by Stash Save. The retry preserves the captured options and adds the explicit Git flag; it does not automatically accept unrelated history. Stash Save retains the merge ref and offers Merge after saving. That return Merge requests Stash Pop following success, completing the native save-and-merge post-action chain.
Success offers requested Stash Pop first. No Commit or Squash then offers Commit.
Otherwise, branch merges offer Remove branch for a local ref and Push; remote refs
omit removal, while Tag/Commit targets do not receive branch actions. Remove
branch asks Delete/Abort before running the source's explicit git branch -D
command. Abort preserves the branch. Duplicate confirmations/responses cannot
repeat removal. Failed removal retains the progress result and reports its error.
All post-actions use the original icons and existing native destination dialogs;
operation/deletion callbacks refresh RefLog, Commit, Status and repository logs.
The receiver and QA record exercise actual models/Git behavior without windows. Core adds optional cancellation and the unrelated-history flag. App Store progress checks the retained security-scope lease before any Git read. Physical window/menu/sheet/confirmation/cancel/refresh routing, active-process interruption, live streaming, displayed conflict hint acceptance, physical cancel-to-Abort behavior, git-svn post-actions, pre-dialog user-data/rebase guards and signed access remain pending. Existing screenshots depict the options, not the progress sheet. Full Merge/application parity remains incomplete.
Conflict hint and Abort reset foundation
A failed merge with actual unmerged index entries now presents upstream's conflict
information in an owned informational sheet, including the reminder to commit
resolved files and the Don't show this message again checkbox. Progress stays
busy and its post-actions remain unavailable until acknowledgement. Unchecked OK
does not save a preference. Checked OK saves MergeConflictsNeedsCommit, and
later merges skip the hint. The progress owner cannot close or cancel while the
hint sheet is pending. No hint is shown for failures without conflicts. Only the
native controller presents the sheet; headless callers can supply a presenter.
The Abort Merge backend now exposes source's three reset modes: Merge defaults
to git reset --merge; Mixed and Hard reset HEAD. This differs from substituting
git merge --abort. Merge reconstructs the prior index while preserving unrelated
working edits, Mixed resets the index while retaining working files, and Hard
restores tracked files. All modes preserve HEAD and untracked files. Pre-cancelled
operations do not run, and bare repositories are rejected.
The receiver and QA record cover blocking acknowledgement, checked/unchecked suppression, a fresh-process preference read, later suppression, non-conflict failure and all three Core modes. They do not display windows. Private UUID preference domains are used and removed; standard preferences and clipboard are untouched. Core tests additionally check unrelated working edits, untracked preservation, unchanged HEAD, pre-cancellation and bare rejection.
Close returns OK; Cancel/titlebar dismissal freshly checks the index and requests Abort Merge only when conflicts remain. The native three-choice Abort dialog and comparison callback are now wired. Physical hint/suppression/keyboard rendering, signed access and broader abort/recovery cases remain pending. The hint retains upstream wording; its Abort Merge context-menu entry is now implemented, with activated Finder/native popup acceptance still pending. Full application parity remains incomplete.
Native Abort Merge dialog and Cancel routing
Abort Merge now has upstream's reminder, Reset Type radio group (Merge selected by default), Show modified files in working tree, and OK/Cancel/Help. Comparison opens the existing HEAD-to-working-tree dialog without resetting. The controller retains repository access and transitions the same native window to reset progress; upstream uses separate modal windows. Each request owns its own controller.
Completed Merge progress keeps Close distinct from Cancel. Close preserves the conflicted result. Cancel and titlebar dismissal read current index conflicts, close the progress owner, and open Abort Merge only if conflicts remain. Duplicate dismissals and post-actions are blocked during that read. A cancelled operation uses the same path after it finishes. The conflict hint must be acknowledged first.
Merge-mode reset failures return to the choices on Retry. Mixed/Hard failures retry the captured mode directly. Successful Merge reset has no post-actions; Mixed/Hard expose Bisect good/bad/skip/reset when active, and Hard offers Submodule Update when applicable and Clean up. These route to existing native dialogs and refresh repository/status/log views. Store access is checked before Git operations.
The headless receiver checks actual Git state, all three reset modes, selection snapshots, comparison callback, Close/Cancel distinction, fresh resolved-conflict dismissal, duplicate protection, index-lock failures and mode-specific retry, and active Bisect post-actions. It creates no windows and cannot establish physical layout/keyboard/owner-sheet acceptance. Active-process cancellation routing, submodule post-action acceptance, activated context-menu acceptance, saved geometry, live progress output, signed scope and the full Reset workflow remain pending. Existing screenshots have not been updated to show this dialog. Full application parity remains incomplete.
Abort Merge context menus and original icon
The shared command now opens the native Abort Merge dialog from Finder requests,
the application command menu/sidebar, and the workspace status context menu.
Finder follows MenuInfo.cpp: Abort Merge follows Resolve in the same group and
requires an active merge plus a tracked item or a folder in the worktree. It does
not require an unresolved conflict or a single selection. Bare repositories and
inactive merges omit it. Workspace/menu availability uses refreshed merge metadata;
opening the dialog itself performs no reset until OK.
The original menumergeabort.ico is copied unchanged, with SHA-256 provenance and
the existing upstream resource-license notice. Finder's icon preference hides
its image while retaining the command; the app's context-icon preference applies
through the existing labels. The Sidebar's operation buttons also use their
original command icons. Incoming requests retain literal paths and repository
access and dispatch the independent Abort controller. Status-window dispatch avoids
explicitly raising the workspace.
Core condition/metadata/request tests and the actual extension menu builder verify this command, exact source group order, original image availability and toggling, URL/path round-trips, real merge metadata serialized through the cache, and removal after abort/refresh. The builder creates no Finder controller, windows or popups. See the verification record. Installed Finder activation, security-scope approval, app menu gestures and new real screenshots remain pending; cache freshness depends on repository refresh.
Live CLI output and cancellation confirmation
The primary Merge result now uses the shared GitCliOutputParser and native
GitProgressOutputState presentation. The pinned baseline is
CAppUtils::DoMerge, CProgressDlg::UpdateCmdOutput / UpdateProgressFromLine
and OnCancel. Core Merge forwards typed stdout/stderr chunks for its actual
merge command; validation remains outside the transport log. Coalesced wake-ups
retain parser-held bytes, CR updates replace the preceding line, and split UTF-8
is decoded after parser emission. The native view shows phase/green percentage
when Git or a hook provides it and scrolls to the end. This does not invent a
percentage for commands that emit no progress.
GitOutputLimitinKiB is captured at result construction (default 2048 KiB, bounded 16..102400). Its soft display limit drops presentation bytes; full success, failure and cancellation diagnostics remain in rawOutput and the completion callback. Repository conflict/common-ancestor queries still determine recovery independently of display truncation. Explicit unrelated retry resets the parser, phase and visible bytes with a fresh token. Later branch-deletion completion appends its diagnostics to the full raw callback, preserving prior Merge output. Branch deletion itself still uses its existing completion-time output path.
Cancel now honors ConfirmKillProcess. The native Yes/No sheet uses the source wording and default Yes. No retains the owned process; Yes cancels its process group. Cancellation cannot be submitted twice while a question is pending. If transport finishes while the question is open, result close/post-actions wait; a late answer cannot mark that completed merge cancelled. The existing cancelled-result conflict check and Abort Merge handoff remain in place.
Merge live-output QA records focused Core and four-Git hidden native checks: split Unicode, local CR replacement and 50% while an owned helper still runs; actual fast-forward HEAD and three conflict stages; 16 KiB capture after preference changes and complete raw diagnostics/recovery; No/Yes cancellation with unchanged HEAD/index and owned child cleanup; deferred successful auto-close with duplicate late answers; full diagnostics after real branch deletion. Existing Merge progress and Fetch/Rebase receivers are regression gates. Helper-generated progress verifies delivery timing, not actual Git merge throughput or displayed UI.
Complete progress controls/layout, physical scrolling/defaults/focus/keyboard/ themes/accessibility, source project hooks and git-svn variants, full post-action progress, signed permissions/Finder/App Store acceptance remain pending. Existing screenshots predate these changes. Full Merge/application parity is incomplete.
Merge message history
The Merge Message editor has Paste last message and Recent messages…
context-menu actions when history exists. They use the original Copy and Log
icons. Paste replaces the current selection without adding a newline. Recent
messages uses the shared native history picker, including multiple selection,
Delete and double-click; insertion adds a trailing newline when the editor was
nonempty. Either action replaces the exact <Auto Generated by Git> placeholder.
Squash disables editing and these actions.
Custom nonempty messages are saved before submitting an operation and on Cancel
or closing an unsubmitted window. No Commit excludes saving, as upstream
specifies. A failed merge still retains its submitted message. Closing its result
does not save the same message again or reorder another dialog's newer message.
History is shared across repositories and reloads preferences before mutations.
The source MaxHistoryItems preference defaults to 25: reload reads at most 25
entries, while saving a newly added message can retain a 26th entry. Its zero-limit
first-entry behavior and exact UTF-16 duplicate comparisons also follow RegHistory.
The Commit history's existing repository scope and cap remain independent.
Saved Data → Log messages (Input dialog) → Clear removes both histories. This intentionally fixes an upstream asymmetry: the pinned Saved Data page counts Commit and Merge messages but its Clear handler deletes only Commit history.
After building Debug, python3 scripts/test-merge-history.py runs isolated,
headless native editor/controller checks. The four-engine record is
merge-history QA. It covers menu labels/icons,
placeholder/selected-range/newline insertion, disabled/busy guards, Cancel,
No Commit, save before a failed real Git operation, concurrent-dialog close
ordering, invalid count rejection, history-picker layout and Saved Data clear.
No main app is launched. Physical menu/sheet interactions, keyboard/undo,
light/dark appearance and signed/sandbox acceptance remain unverified.
The shared picker now identifies selections by row index, so canonically
equivalent Unicode spellings in Merge history remain independently selectable.
The Commit and Merge sheets share the upstream HistoryDlg geometry identifier
and focus their native table initially. See history picker verification.
Message editor font
Settings → Dialogs → Font for log messages selects a native fixed-pitch family and
point size for both Commit and Merge. The LogFontName and LogFontSize
preference names and default size of 9 follow TortoiseGit's CommonAppUtils and
SetDialogs. Menlo replaces Windows' default Consolas; unavailable names fall
back to Menlo or the system monospaced font. Invalid stored sizes fall back to 9;
the native size field accepts 1–1000 points. Changes apply to open editors without
altering draft text, selection or adding an undo entry. Commit styling derives
bold/italic faces from the chosen base font when AppKit provides those faces.
Fonts without a requested face, such as the measured Monaco bold conversion,
retain the native font; synthetic Windows-style font traits remain pending.
Commit and Merge editors, Log message details and Rebase message/progress views use this setting. Other upstream consumers, including Input, Import Patch and Revision Graph, still need integration. The native font control lives under Dialogs as in upstream. No complete typography or visible appearance parity is claimed. Headless checks are recorded in message font QA.
Owned lifetime cleanup
Merge metadata reads now share the owner's cancellation token, including push
settings and merge.log. Revision validation uses the operation token and retains
cancellation errors instead of translating them into an invalid revision.
Forced owner/progress closure invalidates the model, terminates owned work and
fences late output, recovery reads, dismissal checks, deletion results and pending
confirmation answers. Normal Cancel uses a fresh recovery-inspection token so
conflict recovery remains available. A completed merge is not rolled back by
closing its result window. Acknowledged post-actions retain their normal handoff.
The hidden native cleanup receiver covers live remote/config metadata, revision
validation, merge execution, failure status inspection, dismissal status and
branch deletion. It checks recorded process/helper termination, frozen closed
progress state, rejected late confirmation/post-actions, unchanged pre-merge HEAD
and retained completed merge HEAD. This is scoped lifetime verification; physical
sheet/focus behavior, every metadata/error variant and full Merge parity remain
pending. See scripts/test-merge-cleanup.py and the dated QA record.
Full reference and Log revision pickers
Merge now uses the same owned native version-picker coordinator as Switch,
Branch/Tag and New Worktree. Its Branch browse button opens the full reference
browser (ChooseVersion.h::OnBnClickedButtonBrowseRef, gPickRef_All), including
local/remote branches, tags and other namespaces. Returning reloads the catalog
and current branch with an owned cancellation token, maps canonical refs back to
Branch/Tag/Commit, retains the unused commit draft and restores the appropriate
native revision control. Cancel also refreshes the catalog without accepting a
new ref. Merge options and its message are preserved.
The Commit browse button opens native Log in single-revision selection mode, without a working-tree row, at the typed revision. Accept changes the commit hash; Cancel retains the draft. Both pickers lock the owner, reject duplicate and competing actions, and close/invalidate on forced owner closure. Stale callbacks and rejected presentation cannot affect another picker. Reference context commands inherit the repository's normal browser configuration; Log commands retain the existing Merge configuration. Tag remains a popup without a browse button, matching the source chooser layout.
test-merge-pickers.py checks hidden native reference-table/menu/icon routing,
branch/tag/symbolic-remote/notes mapping, F5/fresh catalogs, option/message/draft
preservation, actual native first responder, full Log ancestry/graph/single
selection, stale/cancel/rejected/forced-parent ownership, owned process termination
during the return-catalog read, and unchanged repository
HEAD/tree/config. The application termination guard now includes Merge pickers,
progress and pending confirmations. These checks do not establish physical sheets, real key/mouse
input, displayed appearance or signed scope acceptance. Full Merge parity,
including user-data/rebase preflight, remains pending.
Abort Merge ownership audit, October 10
A source/control audit at 9400d1d confirms that the nine Abort Merge resource
roles exist in the native dialog, but controller/factory ownership remains
incomplete. Upstream Show modified files is a modal HEAD-to-working-copy child;
the native factory opens an independent app-level comparison. The application
Quit handler does not gate this controller’s active reset, and forced close only
sets a model invalidation flag without cancelling the owned reset or rejecting
its late callback. Options and progress also share one resized native window,
where the source closes options and opens a separate progress dialog.
These are implementation gaps to fix and verify, not parity-complete behavior. See the owner audit. Existing model/Git tests remain useful for reset effects and retry/post-actions but do not establish native modal ownership or physical/signed acceptance.
Abort Merge ownership follow-up, October 10
At 789303d, Abort Merge owns its HEAD-to-working-tree Changed Files sheet.
The factory retains that ownership instead of replacing it with a global modeless
comparison. Duplicate comparison, OK, Close and application Quit are fenced while
the child is attached; forced owner close closes and invalidates the child.
OK now hides the options window and opens a distinct native Reset progress window. Merge failure Retry retires progress and reopens options; Mixed/Hard Retry keeps the progress window and retries the captured mode. Closing the final progress retires the owner. Force-close cancels the stored worker and its token, keeps busy until owned work unwinds, and rejects late output, repository-refresh and auto-close callbacks. The token also covers both Core preflight reads and post-reset Submodule/Bisect reads.
The four Abort/reset Core tests pass with system, Git 2.39.5 and packaged Git. The hidden native receiver passes with system and packaged Git, including actual controller sheets, separate windows, mode-specific retries, Quit fencing and forced-close process-tree reaping. See the verification record. The earlier audit records the gaps before this change. Live progress streaming, physical keyboard/layout and light/ dark captures, factory entry end-to-end, submodule action acceptance and signed sandbox acceptance remain pending. This dialog remains partial.
Abort Merge live output follow-up, October 10
At 1f89a7f, reset stdout/stderr feeds the shared byte-oriented progress parser
while Git is running. The native window updates before completion and honors the
configured display limit. Final success retains the parsed display without
repeating the raw result; failure retains streamed diagnostics and adds a concise
exit status. Cancellation retains received output. Forced close rejects all later
output and repository-refresh callbacks. Raw terminal output remains available to
the repository-refresh callback independently of the limited progress display.
A completed reset is not relabeled cancelled when its post-action inspection is
cancelled afterward.
The hidden native receiver exercises successful, failed, cancelled, forced-close and limited-output reset helpers, then retains the existing real Git reset and ownership checks, with system and packaged Git. Core reset tests also pass on system, Git 2.39.5 and packaged Git. The first limit fixture used one long line, which hit the parser's existing 8 KiB per-line cap; the corrected fixture uses several lines to exercise the distinct 16 KiB display cap. The failed receiver's helper was explicitly stopped. The runner now cleans exact-fixture process groups in a finally block and rejects leftover helpers even after reported success; its cleanup function was separately checked with owned and unrelated groups. See the streaming record. Physical keyboard/layout/appearance captures, the full progress menu/options, factory/submodule acceptance and signed sandbox acceptance remain pending.
Abort Merge keyboard and layout follow-up, October 10
At 40adef4, options Return opens the separate progress window; Escape closes
options. Progress Return/keypad Enter closes a terminal result and leaves active
work running; Escape cancels active work and closes a terminal result. Native
window routing rejects parent Return/Escape while the comparison sheet is
attached. The hidden receiver exercises these key equivalents with system and
packaged Git alongside ownership, streaming, cancellation and all three retry
modes. These are AppKit event-routing checks, not physical keyboard acceptance.
Visual inspection caught two actual layout/availability defects before publication: flexible hosting collapsed options to a narrow window, and a nonpublished callback made Show modified files appear disabled at initial render. The fixed options now keep 660×265 points with all nine source roles readable; progress starts at 760×420 with a 600×300 minimum. The comparison button fills the options width and uses busy/child state for availability. Child windows inherit the parent appearance. The post-action menu has one arrow.
Four unedited native content captures are published on the website: options in light/dark (1320×530 pixels) and a real Git index-lock failure in light/dark (1520×840). They were rendered from hidden, inactive AppKit windows with private preferences and a disposable repository. Window chrome is excluded. All four were inspected; the clipped/disabled drafts and synthetic-output captures were not published. See the layout record. Physical keyboard/pointer/VoiceOver, full progress menus/options, factory/menu entry, submodule post-actions and signed sandbox/Finder acceptance remain pending. The dialog stays partial; no full-app completion claim is made.
Abort Merge cancellation confirmation, October 11
At 218f741, Abort Merge honors the existing ConfirmKillProcess preference from
Settings. The source CProgressDlg::OnCancel asks Yes/No before killing the
running process and closes progress after cancellation. The native port now
owns that same-worded Yes/No sheet. No leaves the command running; Yes cancels
and waits for owned process cleanup before retiring progress and options. Without
confirmation enabled, Cancel follows the same retirement behavior directly.
Received output remains available to the model/action log and repository refresh.
The pending sheet blocks duplicate prompts, Close, post-actions and application Quit, including when Git has finished while the question remains open. Completion is deferred until the reply so success is not relabeled cancelled. Request and token identities reject duplicate replies, an old reply during a new prompt and replies after forced owner close. Forced close cancels the worker and tears down the owned alert without publishing late state or refresh callbacks.
The first native completion-during-prompt check exposed AppKit calling the alert reply before sheet detachment completed: auto-close was blocked by the still attached sheet. Deferring the reply to the next main-queue turn fixed the case. The final hidden native receiver passed with system and packaged Git, including actual Yes/No buttons, both replies after successful completion, direct cancel retirement, forced sheet teardown, and independent stale/duplicate reply cases. See the confirmation record. These are native event/controller checks on the current host; physical input, other macOS runtime versions, full progress menus/options, factory/submodule and signed acceptance remain pending. Full dialog/app parity is not certified.
Abort Merge progress output, October 11
Abort Merge now uses the shared native selectable output control. Its context menu
matches the pinned CProgressDlg::PreTranslateMessage: Copy, a separator and Copy
all information to clipboard, with the original clipboard icon on both actions.
Copy is disabled without a selection. Copy All preserves selection and viewport;
the application context-menu icon preference applies to both commands. Completed
output follows the existing font and styling preferences, highlights fatal/error/
warning prefixes and detects links.
The current work label and progress bar are above the output, following
IDD_GITPROGRESS. Parsed percentages update while reset runs; completion fills the
bar to 100 percent. Native macOS rendering determines the bar appearance; the
inactive hidden capture renders it gray, so these checks do not establish the
upstream red error-bar appearance. Animation, completion timing text, Dock progress
and full progress options remain pending. This is still a partial port.
The receiver checks the actual Abort Merge output view and menu targets using a private clipboard, including Unicode, icon preferences, selection/viewport and completed error/link attributes. Its progress fixture uses one ordered stderr stream: an earlier mixed stdout/stderr fixture allowed a delayed diagnostic to overwrite the simulated carriage-return progress line. The failed run was stopped and its owned helper group cleaned by the runner.
Final checks pass with both system and packaged Git, and the shared output-control regression passes. Four inspected native content captures were refreshed on the website. See the output record for exact source/capture hashes and verification scope.
Abort Merge completion footer, October 11
The reset progress consumer now appends the shared source-style completion footer: Success, the Git exit-code failure status, or User cancelled. The current-work label uses that status and the model's terminal percentage is 100. The existing ShowGitexeTimings preference controls elapsed milliseconds and the finish time; UseSystemLocaleForDates controls native locale versus the explicit timestamp format. Elapsed time uses the monotonic clock and is captured when reset finishes, before optional post-reset metadata inspection. Raw repository-refresh output is kept separately from this presentation footer.
The footer has an explicit range for the shared native control's blue success or red failure styling. Retry resets this range; invalidated owners cannot publish a footer. This advances the completion timing/footer gap recorded above, while animation, Dock progress, native error-bar appearance, full options and physical/ signed acceptance remain pending.
Final two-engine native checks verify timing on/off, source completion statuses, terminal100 and the actual success/error output footer colors resolved in Aqua and darkAqua. The first color assertion compared distinct dynamic NSColor objects; the corrected receiver compares resolved sRGB values. Inspected progress captures were refreshed with the real Git exit-code status and timed failure footer. See the completion record.
The commit-revision row now uses the shared editable session combo, including programmatic custom choices, exact native Git token identity and disabled/retired/focus guards. Physical popup and complete dialog acceptance remain open.
The October 17 shared message-history continuation connects the complete native AppKit picker, exact history removals, captured commands and forced-owner retirement. The Merge editor now reflects raw-only Unicode spelling changes. Full Merge and physical/signed acceptance remain open.
Command entry and preserved reviews — October 18, 2026
Pinned MergeCommand.cpp routes merge to the normal review and abort to
Abort Merge. Native command entry now follows those routes without inventing
revision/message command switches. Reopening a command-owned Merge draft or the
open Abort review preserves user choices. Both receive owning workspace
preferences; reference/Log choosers, source icons, option controls, accepted Git
operations and post-actions remain the existing implementations. The connected
Stash entry family preserves edited Save drafts and result-question behavior.
See command entry and
batch evidence. Command wiring and
focused native passes do not certify every source control or signed deployment.
Primary Merge progress and recovery family — October 19, 2026
This connected continuation follows pinned AppUtils.cpp::DoMerge,
ProgressDlg.cpp::OnProgressUpdateUI/OnBnClickedOk/OnBnClickedButton1,
CAppUtils::StyleWarningsErrors/StyleURLs and IDD_GITPROGRESS. The primary
MergeProgressWindowModel, controller and dialog in MergeWindow.swift now use
the shared native read-only output control and completion presentation already
used by Abort Merge. This supersedes the primary Merge plain-text result gap;
it does not reopen or certify every Abort Merge behavior.
Completed output honors captured diagnostic styling, native links, context icons,
Copy and Copy all information without moving the reader's selection or viewport.
StyleGitOutput controls diagnostic prefixes; URL styling remains independent,
as in the source. Success/error completion ranges retain the source light/dark
colors and high-contrast success fallback. The current-work label changes to the
terminal status and the completed bar retains 100 percent. The elapsed clock and
finish date are captured at Git completion, before conflict/recovery reads and
questions. ShowGitexeTimings controls the timing suffix, while disabling it
retains the status line; UseSystemLocaleForDates controls native date formatting.
Original repository-refresh output remains separate from presentation records.
When Git returns a cancellation result, the UI completion uses its actual nonzero
exit code, as the source progress dialog does. A cancelled preflight or injected
operation without a process result uses the native User cancelled fallback;
an ordinary failure without an exit code uses Operation failed. These explicit
fallbacks do not invent a Git exit code. The source separately adds its cancelled
record when writing the action log. A failed conflict-status read retains a
diagnostic in native output rather than silently claiming a clean work tree;
this replaces the source's separate error message box.
The existing source result choices remain: conflicts offer Resolve and Commit;
missing common history offers an unrelated-history retry, followed by Stash;
success may first offer Stash Pop. No Commit or Squash then offers Commit and
returns without branch removal, Push or SVN DCommit. A normal committed local
branch offers Remove branch, and branch targets offer Push; Git-SVN adds DCommit
independently of a branch/tag/commit target. Remove branch is the source's plain
git branch -D action with a separate Delete/Abort question and an error result,
not a new source progress command.
Conflict reminders, kill confirmation and branch-deletion questions retain their
captured attempt through actual native sheet detachment. Duplicate replies,
retired owners and Quit cannot start a stale action or persist stale suppression.
Result closure and post-action handoffs also wait for actual producer/read work
and native children to drain. The model's per-instance pending-work count and
workDidDrain callback keep ownership distinct from a visible Busy label.
Forced closure cancels actual work, answers an owned question once and retains
the release until that work and the question have settled; it never runs a queued
post-action. Only an explicitly accepted live handoff can dispatch a child.
Commit, Resolve, Abort, Stash Save/Pop, Push and SVN children retain the originating
repository grant and preference domain. Appearance and opacity are captured from
the closing progress window as values; retaining its native window is unnecessary.
The root forwards that snapshot to each actual child factory. A new retry
owns a fresh output/completion record. Source Close preserves a conflicted result;
Cancel/title-bar dismissal freshly checks conflicts and opens Abort Merge only
when conflicts remain. Native detachment and actual-worker draining replace the
Windows modal/producer-wait mechanics rather than copying HWND behavior.
The grouped record will identify the actual build/check scope and failures after validation; no pass is claimed here before that evidence is recorded. Physical menus/default-button/Escape/VoiceOver, all merge/recovery combinations, complete source geometry, signed sandbox/Finder and whole-application acceptance remain open. Windows taskbar/animation rendering and Alt accelerator equivalence are not established by native delegate checks.
The subsequent connected Switch/Reset command-presentation continuation also
closes primary Merge's command-preamble gap. Core emits an onCommand receipt
after validation and immediately before launching the actual operation. It
contains the executable and complete executed argument array, including global
--literal-pathspecs / -C, operation-specific -c when present, and Merge's
actual temporary message-file argument when used. Native progress prepends its
POSIX-quoted display before process output. That display is never executed or
parsed back into arguments; a failed preflight does not claim a command started.
The earlier Merge checkpoint retains
its historical missing-preamble boundary. New continuation evidence belongs to
Switch/Reset progress, without
adding a new passing-check claim here before validation.
Native source form control continuation
The connected form family records reference keyboard/focus and bounded captions, Push F5 refresh and Synchronization native split controls, with owned state and remaining acceptance kept explicit.