Skip to content

fix: reuse locked git commit for source deps without rev#6096

Closed
wolfv wants to merge 1 commit into
mainfrom
fix/git-source-cache-without-rev
Closed

fix: reuse locked git commit for source deps without rev#6096
wolfv wants to merge 1 commit into
mainfrom
fix/git-source-cache-without-rev

Conversation

@wolfv
Copy link
Copy Markdown
Member

@wolfv wolfv commented May 12, 2026

Summary

Closes #6091.

A conda source dep declared as { git = "https://..." } (no rev) re-fetched the remote's default branch on every command. The fix is a 5-line helper that seeds the dispatcher's GitResolver with the locked commits, so the existing no-fetch fast path engages.

Why this was happening

The "skip fetch" fast path in pixi_git::source::GitSource::fetch only fires when GitUrl.precise is Some(sha):

match (self.git.precise, remote.db_at(&db_path).ok()) {
    (Some(rev), Some(db)) if db.contains(rev.into()) => /* no fetch */,
    _ => /* fetch */,
}
  • With rev = "<40-char sha>": parsed into GitReference::FullCommit; GitUrl::from_reference auto-fills precise via reference.as_sha(). Fast path hits.
  • Without rev: parsed into GitReference::DefaultBranch; as_sha() returns None; precise stays unset. Fast path skipped — even though the lock file does store the resolved sha.

GitResolver already keeps an in-process (url, ref) → sha cache that fetch() consults before going to the network. It just wasn't seeded from the lock file.

What this change does

seed_git_resolver_from_lock_file walks every conda source package in the lock file, parses any git+...#<sha> URL via LockedGitUrl::to_pinned_git_spec, and inserts (repository_url, requested_reference) → sha into the dispatcher's GitResolver. It's called once, right after the dispatcher is built in Workspace::update_lock_file.

After seeding, pin_and_checkout for { git = "url" } (no rev):

  1. builds GitUrl::from_reference(url, DefaultBranch) — precise unset
  2. GitResolver::fetch looks up RepositoryReference { url, DefaultBranch }, finds the seeded sha, calls url.with_precise(sha)
  3. GitSource::fetch sees precise = Some(sha), finds the commit in the local db, returns without touching the network

Scope / safety

pixi update and pixi add build their own dispatcher off an unlocked lock file (unlock_packages / UpdateContext::builder), so seeding does not pin stale refs there — those flows continue to re-resolve mutable refs as expected. The seed only affects update_lock_file, which is the entry point for pixi run, pixi install, pixi shell, etc.

If the user changes a manifest spec (e.g. adds a branch = "..." or changes the URL), PinnedGitCheckout::matches_source_spec correctly returns false and a re-lock fires; the seeded entry for the old (url, ref) pair is harmless because the new pair isn't in the map.

Test plan

  • Added test_seed_git_resolver_seeds_default_branch_source covering the default-branch case end-to-end (build a lock file with a git source pin, seed an empty GitResolver, assert resolver.precise(...) returns the locked sha).
  • cargo check --workspace --tests
  • cargo clippy -p pixi_core -p pixi_command_dispatcher --tests --lib
  • Manual: in a workspace with kelvin = { git = "https://github.com/bgreni/Kelvin" } confirm that pixi run <task> no longer fetches after the first install.

🤖 Generated with Claude Code

A dep declared as `kelvin = { git = "https://..." }` (no `rev`) used to
re-fetch the remote's default branch on every command. The lock file
already stores the resolved commit, but the install/run path goes
through `pin_and_checkout` with `GitReference::DefaultBranch`, which
leaves `GitUrl.precise` unset and skips the no-fetch fast path in
`pixi_git::source::GitSource::fetch`.

Seed the dispatcher's `GitResolver` with every locked git source at
the start of the update flow. The resolver maps `(url, ref)` to the
resolved sha, so the next `pin_and_checkout` for the same `(url, ref)`
pair picks up the precise commit and the fast path engages.

`pixi update` builds its own dispatcher off an unlocked lock file, so
it remains unaffected and still re-resolves mutable refs as expected.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@baszalmstra
Copy link
Copy Markdown
Contributor

I think #6094 might already solve this issue. The problem was that we didnt populate precise at all.

@wolfv wolfv closed this May 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

pixi run always triggers git fetch if no rev given

2 participants