TurtleGit for Mac

View Markdown source ↗

Cherry Pick parity audit

Status: native Log handoff and Cherry Pick plan implemented; displayed acceptance and advanced options remain pending. This document does not establish complete Cherry Pick or Rebase parity.

Upstream reference

Pinned TortoiseGit revision: 7338078f8ddd924b8cddee35f512f2286072136d. src/TortoiseProc/GitLogListAction.cpp, ID_CHERRY_PICK, opens CRebaseDlg in Cherry Pick mode with every selected Log commit. It does not execute a lone git cherry-pick immediately. RebaseDlg.cpp prompts for Parent 1 or Parent 2 when replaying a merge commit. Pick, Skip, Edit, Squash and ordering belong to the selected commit plan. The pinned documentation screenshot is doc/images/en/GitCherryPick.png; its disabled reference row, numbered commit list, Pick ALL/ordering controls, attribution checkbox, lower tabs and initial Continue/Abort buttons were compared with the native implementation.

Implemented backend

GitRepository.cherryPickPlan(revisions:) accepts the Log's newest-first selection and prepares oldest-first replay. It captures immutable commit IDs, target HEAD and symbolic branch identity. Starting on a different branch at the same hash is rejected. Duplicate selections, stale targets, invalid plans, first-retained Squash and missing/invalid merge mainlines are rejected.

Cherry Pick uses Git's interactive replay based at the captured target HEAD. Existing target history remains the base; selected commits are appended. Pick, Skip, Edit, Squash and reordered plans share the existing Rebase recovery commands. Originally empty commits are retained; commits whose patch becomes empty stop for recovery instead of silently dropping their changes.

For a merge, the selected mainline determines the patch. A temporary one-parent Git object preserves the merge tree, original author/date and message, with that mainline as parent. It changes no reference or index while preparing the plan. The replay then copies its patch onto the target. This differs internally from upstream's direct cherry-pick -m engine. Both mainlines have been compared against actual git cherry-pick -m output trees and author/message metadata.

The application's headless sequence-editor entry point records the Cherry Pick mode and synthetic-to-original commit mapping in the worktree's rebase-merge directory before Git starts executing the todo. Reopened sessions display the original selected merge IDs and metadata, including after a conflict or Edit stop. Continue, Skip and Abort use Git's persistent replay state. Aborting restores the captured target branch and HEAD. Git removes session metadata when the operation ends.

Verification and remaining work

The Cherry Pick checkpoint a2a00d8 recorded 16 focused RebaseTests, zero failures on 2026-10-06. The subsequent Add audit records 20 passing focused tests and the extended native checks. These include ordinary Rebase regression coverage and Cherry Pick selection/Skip, stale branch identity, both merge mainlines, Edit/reopening/Continue, conflict/reopening/Abort, merge-conflict/Skip, reordered Squash, detached HEAD, originally empty commits and attribution compared with git cherry-pick -x for ordinary/merge commits. They execute the real application's headless editor rather than a mock editor. Unsigned Debug and App Store build/package results are recorded separately in qa/cherry-pick-native-2026-10-06.json. The earlier backend checkpoint 021e611 is separately recorded in qa/cherry-pick-backend-2026-10-06.json.

Native handoff and plan

Log now routes its single/multiple visible-order selection to the shared native plan. The old one-command Cherry Pick confirmation is no longer reachable from that menu. The original icon appears beside the single/multiple menu labels. First-selected HEAD, bare and active-merge contexts omit the operation; busy/note/jump states disable it. Merge, root and stash rows can be handed to the plan; HEAD later in a multi-selection does not suppress the command, matching upstream.

Cherry Pick mode disables Branch/reverse/Upstream/browse/Onto, with an empty Branch and HEAD Upstream, and hides Force/Preserve. Numbered rows show action icons, hash, message, author and formatted date. Pick ALL, action menus and Up/Down edit the plan. The attribution checkbox persists CherrypickAddCherryPickedFrom and adds the original commit ID (including for merge commits). Initial Continue/Abort and Revision Files/Commit Message tabs follow the pinned resource/screenshot.

Retained merges prompt for a mainline using parent subjects and hashes. These prompts occur before any replay, rather than upstream's just-in-time prompts. Cancel leaves HEAD unchanged. All Git-supported parents are offered; upstream explicitly offers two. Active sessions recover Cherry Pick mode, original commit IDs and Edit/Continue/Skip/Abort controls. Closing is blocked during mutations or a parent sheet; closing an idle active window leaves recovery metadata intact. Repository status/Commit and all Log scopes are refreshed after mutation.

A whole-native-source headless receiver hosts the actual Log table and Rebase view. With both system Git and packaged Git 2.55.0, it checks menu labels/icon, single/multiple/merge/root/stash handoff, first-selected HEAD semantics, selection order and guards, numbered rows, actions/order, attribution persistence, parent metadata, cancel-with-unchanged-HEAD, Edit/reopening/mode recovery and Continue. Parent answers are injected: this does not establish displayed NSAlert appearance, default focus, keyboard behavior or window title/close gestures. No displayed app or receiver windows were launched.

Add now uses a native multi-select Log sheet, preserving picker order and repeated row identities through recovery. See Add audit.

Pending: physical author/date override acceptance through full Commit handoffs; root/Octopus replay, linked-worktree Cherry Pick and dirty-target interactions; full conflict tabs and stash/restore; displayed layout/keyboard/accessibility and signed sandbox execution. Existing Rebase screenshots predate these changes and are not presented as Cherry Pick screenshots. App Store acceptance is unverified.

Empty-patch recovery now passes the actual native receiver with Git 2.37.1, 2.39.5, system 2.50.1 and packaged 2.55.0. An already-applied patch stops without conflicts, selects its original ID and native Skip leaves target HEAD unchanged. The focused suite contains 21 passing tests, including reopening that state. See Git compatibility and qa/replay-git-compatibility-2026-10-06.json for scope and reproducibility.

Squash now pauses for an editable combined message and applies the captured first/latest/current author-date preference. Each group requires approval, with the first author retained. See Squash workflow.

Edit now has a multiline tab; Continue applies its message. Split reuses full native Commit selection with parent-based first amendments, normal subsequent parts and reopening after cancellation. See Edit/Split.

The shared Conflict Files tab now retains resolved changes and routes existing native editors and Resolve commands with replay-specific side labels. A conflicted Edit cannot Split or amend destination HEAD before application. Pick/Edit checkbox-selected Continue now retains unchecked changes through a recoverable native amend loop. Squash conflict selection and displayed acceptance remain pending. See Conflict Files.

Already-applied Pick/Edit patches and empty checkbox results now offer Commit/Skip/Cancel through the shared replay dialog; conflict-message hints offer Ignore/Abort. See empty-result workflow.

The shared Split workflow restores checked-conflict Edit recovery when the first Split dialog is cancelled, including reopening and message approval. See Split return QA.

The shared Squash conflict tab shows the whole group and supports staged resolution → combined-message approval, including reopened date policies. Phase-specific primary captions replace the separate Amend control. See Squash conflicts.

Shared empty Squash-group approval offers Commit/Skip/Cancel, preserving correct future ancestry and approved Skip recovery. See empty Squash groups.

Repeated Squash conflicts retain no-change middle messages in the final draft, exclude deliberate Skip steps, and preserve the latest source date. Reopening, empty-group choices and subsequent ancestry are covered by real/headless native fixtures. See repeated conflicts.

The internal Cherry Pick replay overrides rebase.updateRefs=false to keep source branches unchanged even when that repository setting is enabled. Linked-worktree empty-group Skip recovery is exercised independently of the main worktree. See reference recovery.

Configured Rebase references remain associated with the original occurrence after repeated Add and reordering. Automatically omitted patch-equivalent references follow Git's unchanged-reference behavior, while retained references update after Edit approval. See repeated/omitted references.

Row menus now reuse native Log inspection/reference/notes/clipboard commands with original icons and occurrence-aware selection. Advanced Log commands and displayed acceptance remain pending. See row menus.

Custom replay lists now retain completed occurrences, original action/mainline metadata, stable numbering and current/completed styling through reopening. Replay rows records scope and remaining differences.

Active session context now restores original options and Fetch/Pull completion origin after reopening. Session context records versioned metadata, fallback and verification limits.

The owned Add/mainline preparation follow-up connects cancellation, private Log picker preferences, atomic plan/draft publication, merge-parent question retirement and Quit ownership. The underlying replay engine and its just-in-time source difference remain as documented above.