gix-transport: run git-upload-pack for local repositories even if it's not in PATH#2700
Merged
Sebastian Thiel (Byron) merged 3 commits intoJul 13, 2026
Conversation
Amey Pawar (ameyypawar)
marked this pull request as draft
July 8, 2026 12:01
Amey Pawar (ameyypawar)
marked this pull request as ready for review
July 8, 2026 17:08
Contributor
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bf86e75b59
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "Codex (@codex) review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "Codex (@codex) address that feedback".
Sebastian Thiel (Byron)
force-pushed
the
fix/2313-upload-pack-fallback
branch
from
July 12, 2026 16:53
bf86e75 to
536ea45
Compare
…oxideLabs#2313) Local clones spawn the service program, like git-upload-pack, by name and would fail if it could not be found in PATH. This is common on Windows, where git can be installed such that git itself is available but its subcommands are not, for instance with scoop. Now, when spawning the service program for a local repository fails because it cannot be found, find the same program in the directory that git --exec-path reports - the location git itself uses to run its subcommands - and run it from there. If it cannot be found there either, run the git binary that is always findable with the service as its subcommand, which it can always dispatch. Remote transports are unaffected - they keep the standard invocation so servers can provide their own implementations - and no shell is involved in any of this. The newly added gix_path::env::core_dir_program() provides the lookup and may serve other Git-provided programs in the future. Git for Windows builds with SKIP_DASHED_BUILT_INS and thus does not provide programs for builtin subcommands like git-upload-pack in its core directory. The test now grounds itself in a listing of that directory instead, and the documentation of core_dir_program() points out the difference - such programs are still run through git itself thanks to the second fallback.
This way it can be found even if not in path, or through Git.
- Reject path components in core_dir_program names. Co-authored-by: Sebastian Thiel <[email protected]>
Sebastian Thiel (Byron)
force-pushed
the
fix/2313-upload-pack-fallback
branch
from
July 13, 2026 05:58
83e3071 to
151a0af
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2313.
Problem
Local clones spawn the service program, like
git-upload-pack, by name, and fail withNotFoundwhen it isn't inPATH— even thoughgititself is findable. As Eliah Kagan (@EliahKagan)'s analysis in the issue lays out, this is common on Windows, where installations like scoop's putgitinPATHbut not its subcommands, and where we already supportgitnot being inPATHat all.Changes
Following the resolution order discussed in the issue:
PATHas before.NotFound, find it wheregitfinds it: the newgix_path::env::core_dir_program(name)looks the program up in the directory reported bygit --exec-path(via the cachedcore_dir()), which is the locationgititself uses to run its subcommands — and run it from there by absolute path. This works on all platforms and is the "conscious choice" variant: it's very clear which program runs.gitrun it: spawnexe_invocation()with the service as its subcommand — passed as a separate argument, no shell involved.The fallback can only ever engage for local repositories: it is gated on the non-SSH arm of the transport, so remote invocations keep the standard
git-upload-packcommand name that servers may customize. The async client has no file transport, so nothing changes there. As the retry is keyed on the failed spawn itself, there is no TOCTOU between checking and running.git-receive-packgets the same treatment as the logic is service-generic.The
auxiliary.rsmachinery for Git-for-Windows directories is deliberately left untouched —--exec-pathalready answers this particular question on every platform, while the broader executable-finding facility discussed in the issue (and #1886) remains open for its own design.Validation
Reproduced the issue and verified the fix end-to-end on macOS with a
PATHcontaining only agitsymlink:gix clone file://…fails withNo such file or directory (os error 2)GIT_EXEC_PATHadditionally pointing at an empty directory, the clone still succeeds via thegit upload-packform, exercising the last fallback.Tests:
gix-path:core_dir_programreturns an existing absolute path forgit-upload-packandNonefor programs that don't exist.gix-transport: the fallback invocation shape is asserted for both branches — never a shell, repository path as final argument, sub-command as a separate argument in thegit-run form.cargo test -p gix-path -p gix-transport --features blocking-client -p gix -p gitoxide-core,cargo clippy --workspace --all-targets -- -D warnings,cargo fmt --all -- --checkall pass.