Working Tree dialog parity
Current light/dark main-window review: primary dialog visual review.
Reference: ChangedDlg.cpp, ChangedDlg.h, IDD_CHANGEDFILES in the resource
file, and RepoStatusCommand, pinned by upstream.json.
Implemented
- Standalone native Working Tree window, repository permission retained while open.
- Branch link above a dense file list, followed by lower-left filters, lower-right summary, and Save unified diff / Stash / Commit / Refresh / OK actions. The source-labelled Save unified diff action opens the aggregate viewer; saving is available there.
- Original status artwork; Path, Extension, Status, Lines added, Lines removed and Modification date columns. Columns sort on their displayed values.
- Unversioned, ignored and assume-unchanged/skip-worktree filters. The core also supports clean files, although upstream's unmodified checkbox is hidden.
- Finder file/folder scope and Show Whole Project. Show all staged files includes staged files outside that scope; switching it off keeps staged files inside scope.
- Context commands for Diff, Stage, Unstage, Rename, path-filtered Log, Reveal and Copy paths. Rename opens the native source/name/browse window; see RENAME-PARITY.md. Enter/double-click opens selected-file HEAD-to-working-tree unified comparison.
- Unified diff export uses the requested scope, independently of out-of-scope staged rows and row highlighting. Staged and later unstaged changes are included.
- Commit forwards the dialog's project/file scope. Stash save/apply/pop/list and branch Switch open dedicated native windows. Their remaining parity is recorded in STASH-PARITY.md, REFLOG-PARITY.md and SWITCH-PARITY.md.
- Explicit refresh and completed operations update the file list. Background Finder cache polling does not disable status controls or replace the current selection.
Verification
The suite has 42 tests. New real-Git tests cover literal Unicode/newline paths, folder scope, staged files outside scope, a mixed index/worktree file, ignored and unversioned files, clean paths, assume-unchanged and skip-worktree flags, and unborn HEAD. Reading status and diff leaves the index and working-tree contents intact.
Native checks on disposable sample data verified unversioned/ignored/flag filters,
opening a mixed-file comparison, and staging/unstaging an unversioned file through
its context menu. Native Save unified diff output matched Git's HEAD-to-working-tree
patch byte-for-byte. Added-line sorting was verified in ascending and descending
order (3, 2, 1, unknown); Stash save opened the foreground confirmation and was
cancelled without changing the repository. site/assets/status.png shows the running native window.
Remaining upstream behavior
- Full GitStatusListCtrl menus: submodule-specific handoffs and complete marked-row enablement. Group/changelist workflows are mapped below. Revert/conflict/index flags are available; file history/Blame/export/editor/Open/deletion now have native routes below.
- Full conditional Stash/Switch menus and post-operation behavior; the dedicated dialog ports remain partial.
- Complete displayed/signed acceptance. Refresh ownership, cancellation/progress, F5, source filter persistence and selection restoration are implemented in the October 14 lifecycle batch below. Window geometry uses the shared native persistence.
- Physical alternative-diff tool activation and broader multi-repository, rename, conflict and submodule native QA. Invocation-dependent filter enablement and alternate unified routing are implemented in the scope batch below.
- Native scoped Finder invocation and signed Finder menu/badge appearance still need end-to-end validation; core scope tests do not establish that integration.
The main workspace overview still exists. The status command now opens this standalone replacement; these entries remain partial until the remaining behavior and UI have been compared and exercised.
The file menu now offers upstream Ignore name/extension and containing-folder actions for unversioned/deleted selections. Ignore parity records rule semantics and native Commit/Working Tree handoff evidence; post-close restoration remains unverified.
Local-change index flags
Skip worktree, Assume Unchanged and Unflag are now shared with Commit. The existing Show ignore local changes flagged files filter exposes flagged rows for unflagging. Native confirmation, restoration to Modified and assume-unchanged status were verified; Git tests cover clearing both flags and linked-worktree index separation. See Commit's index flag audit for source review, test evidence and remaining acceptance work.
Shared native columns and clipboard
Working Tree now reuses Commit’s native AppKit header integration without a leading checkbox column. Nine physical text columns retain the source six-column default: Path, Extension, Status, Lines added, Lines removed and Last modified. Filename and File size are optional; LFS Lock is offered only with the common repository LFS marker. The header saves visibility, order and adjusted widths under WorkingTree.FileColumns, independently of Commit’s layout. Existing saved LFS visibility migrates on read without rewriting preferences. Path stays visible.
The shared header supports content fitting, automatic header/content widths and confirmed Reset columns. No retains the layout; Yes restores the six-column default, clears adjusted widths/order and ownership. Busy and Quit confirmation block settings changes. All nine headers retain a single ascending/reverse sort column with path ties. Metadata is read once per refresh, including size/date and missing paths; dates and sizes use the existing native shared formatting.
Copy to Clipboard offers original-icon Full paths, Relative paths, File/folder names and Copy all information. Text follows displayed row order; Copy all uses the saved visible-column order and headings. The shared integration also routes Command-C/Control-Insert to relative paths, Shift to paths/status, and the clicked column to single-column copy. Native LF replaces Windows CRLF. Flagged and staged status text follows the actual table; renamed rows include their source path in the displayed Path column. Literal names retain tabs/newlines.
See column QA for current evidence and limits. Physical pointer/keyboard/context menu input, full status-list menus and signed sandbox/Finder acceptance remain pending. This is partial dialog parity.
Copy all now retains its heading when Path is the only visible column, using the shared source command-mask rule. Explicit column/path copies omit headings. See menu/copy QA.
Exact status row color roles
Working Tree applies the pinned default CColors role to all nine text columns, with source combined index/worktree priority and semantic selected text. Rename is distinct from modification; unversioned/ignored/normal rows stay neutral. See Appearance and status color QA. Native RGB/appearance resolution is checked separately from current pixel and accessibility/contrast acceptance.
Working Tree operation family — October 14, 2026
ChangedDlg's refresh/F5/cancel flow and saved AddBeforeCommit, ChangedFilesIncludeStaged and repository-specific ShowWholeProject choices now have native counterparts. Ignored/local-change flags remain session choices, as in source. Scoped reopening restores Whole Project; an unrestricted root forces it on without overwriting the scoped choice. Changing filters retains visible selections. The empty table uses the source explanation of settings.
Refresh reads status, branch, rebase state, submodules, LFS availability, metadata and line statistics into a replacement snapshot before publishing. Failure or cancellation preserves the previous table, selection and branch. LFS owner reads remain separately optional and cannot overwrite a retired window. Refresh, Stage/Unstage, index flags, diff export/viewer preparation and column reset share owned cancellation/lifetime accounting. Current work and a cancellable progress control remain visible while the table is disabled. Close requests cancel and wait; forced retirement cancels work and fences late state, panels, viewers and preferences. Quit protection survives removal of the owner window.
Core cancellation now reaches Unstage's HEAD inspection and actual mutation, diff HEAD inspection and diff child, and every private-index flag command. Cancellation cannot be swallowed as an unborn HEAD; private index flags check cancellation before replacing the real index and remove their temporary lock on failure. Completed Git mutations are retained rather than claiming rollback.
Debug compilation and all ten affected Core checks have passing evidence. The new lifecycle and existing LFS/column receivers passed with both system and bundled Git; all four receivers were reaped. Only the actual failing Core fixture was repeated. See results and repairs. Physical scrollbar/keyboard/panel acceptance, signed security scopes and full status-list/menu parity remain open.
Captured file-menu workflow family — October 14, 2026
The pinned GitStatusListCtrl's working-copy menu supplies two-file comparison, single-file Log/old-name Log/Blame, Export, alternative editor, Open/Open With, Explore and Delete. Working Tree now exposes these with the original source icons and explicit row gates. Missing tracked files retain historical Blame and Delete but do not offer Open or Export. Unversioned/ignored rows omit Log and Blame. Directories/gitlinks omit file editors and two-file comparison. The ChangedDlg mask excludes Save As, Restore and Prepare Diff; this batch does not add those excluded commands.
A snapshot retains displayed row order, exact status records, the focus mark and a generation. The mark can sit outside the highlighted set, as in source; it controls Delete eligibility while the highlighted paths remain its targets. Selection-away/return, filter changes and refresh invalidate old menus. Existing Stage, flags, Ignore, Resolve, clipboard and comparison closures also check that snapshot before dispatch. The shared native Delete key integration accepts an unversioned/ignored focus mark; context Delete also supports a missing tracked mark. Shift requests permanent deletion.
Open With and Export use dialog-owned native panels; deletion uses a default-No confirmation. Their pending responses retain operation/Quit ownership, repeat the snapshot gate and refuse late responses after retirement. External launch and editor errors use the shared operation diagnostics. Export retains working contents and relative paths independently of staged contents; directories are skipped by the shared source-compatible exporter. Deletion retains the shared fresh-status/index preflight, Trash behavior and partial-outcome diagnostics. All deletion Git inspections/private-index commands are now cancellable. Successful or failed deletion refreshes the table while retaining its error.
Debug and all 17 affected Delete/Export Core tests passed. The file-menu and existing LFS/column receiver families passed with system and bundled Git after an obsolete Delete-key expectation was updated and outside-highlight focus marks were retained. The initial system-Git lifecycle regression also passed; it was not repeated. All seven initial/final receivers were reaped. See results and limits. Actual application/editor launches, physical panels, Trash/Finder appearance, signed grants and full status-list parity remain open.
Working Tree groups and changelists — October 14, 2026
Working Tree now reads the same worktree-local changelist document as Commit and reuses the pinned PrepareGroups/SetItemGroup category order. Explicit assignments take priority over status/flags; ignore-on-commit follows ordinary changelists. Group headers use non-path identities, the source-style colored heading/rule layout, and no checkboxes in this dialog. The nine physical columns and independent saved column layout remain available. Sorting applies within each category; clipboard/file-menu order follows the resulting displayed rows.
The native table interaction receives every header slot and ignores it when resolving keyboard/clipboard file selections. A group menu selects its captured files rather than passing a header identity to Git. Its generation and member status are checked after selection/filter/refresh changes.
File menus add Remove from changelist, Move to an existing name, a new-name native dialog and ignore-on-commit. The pinned legacy enum-value comparison excludes a pure Added mark rather than excluding all unversioned paths. Pending name replies retain operation/Quit ownership and cannot assign after retirement. Assignments change only changelist metadata; Working Tree does not silently stage or unstage ignore-on-commit paths. Keep changelists persists through the same preference used when the next Commit dialog opens. The shared mutation API now propagates cancellation through metadata-location reads and checks before publishing its locked replacement. Failed/cancelled saves retain the prior document and clean up their owned lock.
Debug, eleven affected Core tests and six grouped native groups/file-menu/LFS receivers passed with system and bundled Git. A capture-only correction supplied the native background; one Groups receiver regenerated inspected light/dark content renders without repeating app/Core/LFS validation. All seven receivers were reaped. See results and capture limits. The subsequent shared-layout checkpoint below repairs first-column heading clipping and the observed optional-header discrepancy. Complete whole-window visual acceptance remains unfinished. Physical header gestures/name dialog appearance, full source group-state accessibility and signed worktree access remain open. This does not certify complete status-list parity.
Submodule history handoffs — October 14, 2026
The status-list source separates Show log (the superproject's gitlink path) from Show submodule log (the child checkout's history). Working Tree and Commit now expose the second command with the original Log artwork. Working-tree child history uses the child's current history rather than pinning it to the superproject's older gitlink. Historical Log comparisons retain their existing revision-pinned child routing.
A shared owned lookup verifies that the path is an indexed/configured or HEAD-recorded gitlink, its checkout is confined, its .git marker is regular, and Git discovers that exact checkout root. An uninitialized empty directory cannot silently discover the parent repository. Cancellation and retired owners fence the read and child-window callback; independent accounting blocks Quit while even a removed owner's lookup settles. App Store routes retain and check the parent lease for both repositories.
The connected Submodule Diff/handoff batch passed twelve Core checks and four grouped native receivers with both Git engines. See results and limits. Full marked-row/directory menu variants and signed child scope acceptance remain open; these new routes do not complete all status-list behavior.
Shared file-list layout batch — October 14, 2026
Commit and Working Tree group headers now draw across the visible native table width, with a colored heading and trailing rule independent of the Path column. The AppKit drawing layer does not intercept pointer events or create duplicate accessibility elements; the underlying group row retains its full accessible label and its existing context/selection behavior. Keyboard/clipboard mapping still uses the same group/file slots. Horizontal scrolling, resize and appearance changes update the drawing geometry through owned, coalesced notifications.
The shared column integration now detects replaced column objects within the same table, resolves their existing semantic headings and reapplies saved order, width and visibility. It does not record automatic repair as a user layout edit. This also applies to the LFS Locks table. Deferred configuration and geometry observers retire with their probe and cannot reinstall a drawing layer afterward.
Debug and six grouped native layout/groups/LFS receivers passed with both Git engines. Two unsupported column-surgery fixtures were stopped/reaped; the final ordinary-table data-source correction was rechecked only on system Git. All nine owned receivers were reaped. Refreshed light/dark content renders were inspected and show full titles and the intended columns. See actual evidence, fixture repairs and limits. Full physical appearance/scrolling/accessibility and signed acceptance remain open; no Core behavior changes in this batch.
The Commit file-workflow batch also corrects Working Tree operation cleanup: completion releases the old token before starting its refresh, so the old defer cannot clear the new operation's busy/progress state. Failure diagnostics are restored after starting the refresh. Existing Working Tree lifecycle/file-menu checks are part of the grouped validation; see the connected audit.
Invocation, aggregate comparison and related-dialog family — October 14, 2026
ChangedDlg's original invocation is now represented separately from highlighted rows. A single directory/root enables Unversioned and Ignored; a single file or multiple explicit paths disables those controls without overwriting their saved values. Missing files remain explicit file invocations, and Git symlinks remain files rather than adopting their target's directory type. The scoped title shows the invoked path or multiple paths' common directory; Whole Project shows the repository root. Explicit root invocation keeps its filters available.
The source-labelled Save unified diff now opens the aggregate read-only unified viewer, where saving is available. It does not use row highlights or out-of-scope staged rows as its path selection. A folder invocation compares its common folder (or the repository with Whole Project); the pinned source's explicit single-file precedence remains in effect even with Whole Project checked. Shift requests the configured alternative viewer. The selected-row context command continues to compare only those selected paths. Both use the existing owned, cancellable preparation and late-owner fence. Commit's handoff applies the source's first-file/common-directory rule and Whole Project choice.
Stash save is always present; Pop, Apply and List follow an existing loose or packed refs/stash, including a linked worktree's shared reference. A fresh owned read before dispatch refuses a restore/list command after the stash disappears. Pop precedes Apply in source order and both retain the original artwork. Working Tree's Stash, Commit and Switch handoffs now route directly through that dialog's repository and access lease, independently of the main workspace's active root. Pop uses ChangedDlg's Show Changes setting 2, Apply its setting 0. Existing child operation callbacks update Working Tree after repository changes.
Related-dialog refresh requests are coalesced while an owned operation is busy. A new invocation arriving during that work is retained for the next refresh; multiple requests do not start parallel reads. Cancelling Quit releases a pending refresh/invocation. Retirement discards queued work. Existing Stage/Unstage and child mutation callbacks use the same owned refresh path.
The pinned CheckRepo DWORD passed as GetStatus's bUpdate argument controls
UpdateFileList's local cache reload. The old remote/SVN acquisition block is
inside #if 0; this source does not fetch a remote or expose a Remote checkbox.
No network command is introduced under that obsolete name.
Debug compilation, all thirteen affected Core checks and all eight grouped native receivers passed on the first batch validation. The four native families ran with system and bundled Git; every owned receiver was reaped. See results and limits. Full physical layout/input, configured external-tool activation, signed Finder/sandbox acceptance and remaining status-list menu variants are still open. This remains partial dialog parity.
The pinned ChangedDlg m_bRemote/CheckRepo value is passed as GetStatus's bUpdate
argument and then UpdateFileList's local update flag. IDD_CHANGEDFILES has no
remote-status control or fetch action. The earlier README remote-status gap was
removed after tracing these source calls; this does not certify all Working Tree
menus, LFS network behavior or native/signed acceptance.
Shared repository titles and path-cell tooltips now consume the source Advanced preferences; see repository presentation and its grouped evidence.
Primary file-list command family — October 16, 2026
Working Tree now offers Commit… for the captured selected paths, independently of the footer Commit's invocation/Whole Project scope. An unversioned/ignored mark permits it; a tracked assume-unchanged/skip-worktree mark suppresses it, as in GitStatusListCtrl. The original Commit icon is retained.
Add is enabled by the selection mark. Shift exposes Add as Executable (+x) and Add as Symlink only for a non-directory mark. These commands open the existing native Add progress window with the captured paths and requested mode, using the Working Tree's repository/access lease. Add completion refreshes both open primary file lists, even when another repository is active in the workspace. Staging/unstaging remain available as native index actions; force Add is distinct from ordinary tracked-file staging.
Both Commit and Working Tree use one captured marked-row policy for Add, base comparison, Revert, Resolve and Ignore. Mixed selections retain the source marked-row enablement; commands keep the complete captured selection. Resolve precedes the other command groups. Working Tree's index-flag menu and mutation now use the same mark, including the existing Core partial-success report when another selected path has no stage-zero index entry. A partial result refreshes the list as well as displaying its diagnostic. A refresh snapshot retains HEAD availability so unborn repositories omit the context unified comparison.
This is source command/dispatch parity; full physical menu layout, signed sandbox prompts and every mixed-state mutation remain separately unverified.
See grouped native evidence for exact checks, the scope-fixture repair and acceptance limits.
Native file-list refresh position — October 16, 2026
Refresh/filter replacement now restores the owning table after native rows and columns settle. Working Tree collects optional LFS metadata before publishing its new table, and quiet read cancellation retains the prior snapshot. Source preference, multi-selection/focus, file-only Select All and owning F5/Escape are connected in the file-list refresh family. Eight grouped case/engine runs pass; physical and signed acceptance remain open.
Detailed statistics and native Stash footer — October 17, 2026
The information field now follows ChangedDlg::UpdateStatistics and GitStatusListCtrl::GetStatisticsString: line additions/deletions, normal, unversioned, modified, added, deleted and conflicted totals in the source compact format. Its native read-only multiline field supports text selection; the former native visible/staged overview remains as its tooltip. Totals use accepted file and numeric-statistic data, invocation/Whole Project/Show all staged scope, and unversioned/ignored/local-flag acquisition choices. Ignored files join the source unversioned category; rename/type-change action codes join modified, copies join added and action categories can overlap. Binary/absent line counts contribute zero, matching source numeric conversion.
The pinned BuildStatistics resets normal without incrementing it; the native source-format field retains that zero. Show unmodified remains a hidden source control. ChangedDlg does not attach IDC_SUMMARYTEXT through SetStatLabel, so no selected-file summary is invented for that dormant resource. Consolidated removed-index/unversioned-copy rows and every combined raw-action case remain separate review work; this is not certification of all status-list statistics.
Stash now uses an owned native pull-down with the source Save/Pop/Apply/List order and original icons from its own preferences. Popup items capture their model, accepted file-list generation and available actions; each is single use. Refresh, foreign owners and retirement reject stale commands. The existing real stash-ref preflight still controls dispatch, and the existing repository/lease routes and scope behavior remain. No extra Git fetch or remote-status feature is introduced.
All fifteen static Changed Files controls now have partial mappings, including explicit dormant-resource decisions. Four distinct native case/engine combinations pass with system and bundled Git. Both raw light/dark captures were individually reviewed: the selectable statistics wrap without clipping and the native Stash footer fits. All eight owned receivers were reaped and independently absent. Core was unchanged and not repeated. See batch evidence for the fixture repairs and remaining acceptance. Physical input/VoiceOver, all mixed-action cases, real child-dialog completion and signed Finder/App Store acceptance remain open.
Exact changelist groups — October 17, 2026
Working Tree shares the exact changelist storage and grouping family. Native Move menus use byte-exact identities, group lookups distinguish canonical spellings and ambiguous name help/accessibility exposes UTF-8 bytes. Assigning, removing and reopening membership shares the atomic, versioned repository data. The wider working-file selection identity migration remains open; this does not certify every filename or the complete dialog.
The grouped native family passes with both Git engines, including exact group selection, moving membership, reopening metadata and preserving Git state before the explicit commit. All owned receivers were reaped. Final raw captures:

The Sync conflict status-list family now reuses the Working Tree file-action, clipboard, metadata, ownership and native interaction backend with the narrower source menu/column mask. Column preferences and reset defaults use a separate ConflictSyncDlg profile; ordinary Working Tree defaults remain unchanged. The grouped conflict-table and existing Working Tree menu checks pass on both Git engines. Wider path identity and physical/signed acceptance remain open.
The working-file identity continuation now preserves distinct valid UTF-8 spellings through status/rename/statistics reads, amend joins, per-path metadata and index flags. Native row IDs and highlighted/ checked String sets still require their separate migration; this is not full filename-selection parity.
Exact file selection identity
Working Tree now retains distinct valid UTF-8 Git path membership in its native row IDs, highlighted selections, group lookup, marked/captured menus, submodule and locked-path membership, and selected/focused refresh restoration. Captured menus expire when just a canonical spelling changes. The shared native selection replacement adapter also serves Commit and Sync conflict lists. Original path text remains in captions and operation arguments. See working-file identity and batch evidence. This supersedes the earlier pending selection migration for this dialog; other dialog models, LFS owner maps, Finder states and filesystem alias behavior remain open.
The connected workspace file workflow continuation covers exact overview selection, Finder reopening, shared viewer caches and Add/Commit drop identities. Earlier workspace-selection limitations describe the prior checkpoint; complete physical/signed and application parity remain open.
Missing staged-file recovery
The connected status-read recovery is tracked in missing staged-file parity, with the source three-choice prompt, per-read apply-to-rest and explicit refresh notice. Its grouped checkpoint remains separate from older dialog checks above.
Primary conditional control follow-up
The shared conditional UI audit records the Commit split control, Log control states and Working Tree refresh/cancellation follow-up, with focused validation and remaining acceptance kept explicit.