TurtleGit for Mac

View Markdown source ↗

Fetch and Pull literal refspecs

This family implements the existing Fetch/Pull dialog's single remote-branch field as a literal Git refspec argument. It does not introduce additional fields, patterns, shell parsing or multiple-refspec syntax.

Pinned source and accepted input

The source is TortoiseGit commit 7338078f8ddd924b8cddee35f512f2286072136d:

Core now removes branch-name-only prevalidation. It trims outer whitespace as existing native submission does, rejects embedded NUL in an active field, then passes the resulting string as exactly one argument after the remote. Git validates force prefixes, source/destination mappings, wildcard and negative refspecs. An invalid refspec produces the actual engine failure and output; it is not reported as an invalid branch before transport. A field containing spaces is still one argument, not several refspecs.

A command-only -c core.precomposeunicode=false preserves literal decomposed reference bytes for Fetch, Pull and the associated Rebase target lookups, even when stored repository configuration enables worktree filename precomposition. This override does not rewrite configuration. Public failure receipts retain the Fetch/Pull command arguments and streamed-output delivery metadata.

Existing option and engine distinctions

All-remotes Fetch and named-all omission remain unchanged. Pull's exact configured-tracking omission remains unchanged. Tags and prune retain their three-state flags, and depth, verbosity, SSH preparation and cancellation retain their existing behavior. Default CLI operation remains CLI; selected Fetch uses the captured libgit2 configuration. Pull remains ordinary Git.

Selected libgit2 intentionally follows the pinned source rather than replacing it with CLI refspec semantics:

  1. Look up the named remote, falling back to an anonymous URL remote.
  2. If the single field is nonempty, call git_remote_add_fetch with the raw refspec. This changes the named remote's stored fetch configuration.
  3. Fetch with a null explicit-refspec array on the already loaded remote. The newly persisted mapping applies to a later operation, not that first operation's loaded refspec set.

The current helper already implements this ordering; this family exposes valid input to it. A nonempty refspec on an anonymous URL remote fails because there is no named configuration identity. The actual library's refspec support and error are retained, including differences from the selected CLI Git version. No retry falls back to CLI or rewrites the field into a conventional tracking mapping. Existing source-specific handling of force and tag defaults is unchanged.

Fetch followed by Rebase

The effective field also follows the pinned dialog's named-all omission. Fetch no longer forces a displayed branch into the transport when named-all is selected. Pull followed by Rebase omits it only for the exact byte-identical configured tracking selection; a different field remains explicit. The handoff retains the exact source Rebase preset:

FetchRebaseResult.upstreamPreset retains that spelling. If it resolves to a commit after successful Fetch, upstreamResolved is true and upstream captures its immutable object ID; later ref movement cannot change that accepted target. If it does not resolve, upstreamResolved is false and upstream is the literal editable preset. No ancestry/fast-forward/up-to-date decision is manufactured. Native Rebase opens that preset for editing instead of silently choosing the refspec destination or an unrelated FETCH_HEAD. A successful Fetch with an unresolved preset is not reported as a failed Fetch.

An empty/missing ref is distinguished from a metadata process failure: quiet resolution exit 1 means unresolved; unexpected execution failures or invalid successful object-ID output retain the successful transport diagnostics in FetchRebaseExecutionFailure. Cancellation remains cancellation. The existing all-remotes Rebase guard remains a Mac profile constraint.

Pinned source selected libgit2 returns before the automatic CLI handoff. The Mac retains its existing selected-library continuation as an explicit extension, using the same raw preset/immutable-resolution rules. Ordinary resolved targets remain immutable; this changes the previous CLI named-remote FETCH_HEAD adaptation when it conflicted with the source preset. See also Fetch parity.

Validation scope and remaining limits

The grouped checkpoint records 51 distinct Core methods cumulatively passing, including thirteen new FetchRefspecTests methods covering:

Retained source-Rebase fixtures now request explicit branches where intended and assert editable unresolved presets instead of selecting unrelated fetched commits. The retained invalid-input test now uses NUL, rather than labeling an ordinary source/destination mapping as injection. The retained Rebase diagnostic fake recognizes invocation-only Git configuration flags rather than assuming a fixed argument position. Native form/history/retry/ownership acceptance passes in six distinct CLI case/engine pairs: Fetch, Pull and Rebase with system and bundled Git. The first Pull native attempt exposed a missing submitted-command receipt in progress; the repair streams that captured receipt through the existing parser while preserving raw Git output for Core observers. Two affected Core methods and four affected native pairs then passed. The final Debug build exited zero, with one contradictory generic compiler exit-zero diagnostic recorded.

Retained streaming/cancellation/forced-cleanup fixtures inspect Git global options rather than relying on fixed argument positions. Cancellation requires the exact retained result, its cancellation diagnostic and failure state, while keeping process, unrelated-process, HEAD/index and close assertions. See the dated checkpoint for initial failures, focused repairs and retained-check results. These checks do not establish every server's refspec support, signed deployment or a full hosted CI pass.