fix(git): serve want-by-sha for unadvertised refs (PR merge commits) - #27
fix(git): serve want-by-sha for unadvertised refs (PR merge commits)#27DanielHabenicht wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #27 +/- ##
==========================================
+ Coverage 96.12% 96.20% +0.07%
==========================================
Files 6 6
Lines 1650 1869 +219
==========================================
+ Hits 1586 1798 +212
- Misses 64 71 +7 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Thanks for your contribution @DanielHabenicht ! I left a few comments. You also need to fixup the commit msg/body. |
actions/checkout on a pull_request event fetches the synthetic merge commit by bare SHA. That commit lives only under GitHub's unadvertised refs/pull/<n>/merge, so the mirror clone never captured it and upload-pack rejected the want with "not our ref", breaking CI behind the proxy. Before serving, ensure_fresh scans the upload-pack request for want lines and, for any SHA missing from the mirror, fetches it from upstream and pins it under a reserved refs/proxy-wants/<sha> ref. Pinning makes the object a valid want tip (so upload-pack serves it) and keeps it from git gc. The namespace is hidden from the advertisement yet still honored as a want tip, and excluded from prune so pins survive periodic refreshes. Because those pins are excluded from prune and gc, --max-wants bounds how many a mirror retains: the oldest are pruned beyond the cap so they cannot accumulate without bound. Relies on the upstream serving arbitrary SHAs (GitHub's allowAnySHA1InWant); an upstream that refuses leaves the want unsatisfied for upload-pack to reject. Ordinary branch/tag clones pay only a cheap cat-file check, never an extra upstream call. Assisted-by: Claude:claude-opus-4-8
14a02b8 to
6e36d14
Compare
| // would be pruned straight away (see `prune_wants`), so fetching it is pure | ||
| // waste. The excess is dropped and upload-pack rejects those wants. | ||
| if self.cfg.max_wants > 0 && missing.len() > self.cfg.max_wants { | ||
| tracing::warn!( |
There was a problem hiding this comment.
The risk is that if we don't surface this to the user, they'll expect it to work and might be confused why the shas are not available. Someone will need to check the logs to see what's going on.
But, as long as it's a documented behavior, it would be ok.
|
|
||
| /// Collect an iterator of oids into a `HashSet` for order-insensitive assertions | ||
| /// against `parse_wants`. | ||
| fn want_set<I: IntoIterator<Item = String>>(oids: I) -> HashSet<String> { |
There was a problem hiding this comment.
Place helper fns at the bottom, after all tests.
| .take_while(u8::is_ascii_hexdigit) | ||
| .collect(); | ||
| // sha1 (40) or sha256 (64); ignore anything else (e.g. a stray token). | ||
| if oid.len() == 40 || oid.len() == 64 { |
There was a problem hiding this comment.
You could ignore parsing oids over the max_wants here. Then you don't need to truncate and check for missing in ensure_wanted_oids.
Before serving an upload-pack RPC, parse the client's
wantlines and, for any SHA missing from the mirror, fetch it from upstream on demand and pin it under a reservedrefs/proxy-wants/<sha>ref. Pinning makes the object a valid want tip (so upload-pack serves it) and keeps it fromgit gc. The namespace is hidden from the ref advertisement (uploadpack.hideRefs) yet still honored as a want tip, and excluded fromfetch --pruneso pins survive periodic refreshes.Relies on the upstream serving arbitrary SHAs (GitHub's allowAnySHA1InWant); an upstream that refuses leaves the request to fail as before - no regression. Ordinary branch/tag clones pay only a single cheap cat-file check, never an extra upstream call.
What kind of change does this PR introduce?
Summary
actions/checkout on a pull_request event fetches the synthetic merge commit by bare SHA. That commit lives only under GitHub's unadvertised refs/pull//merge, so
clone --mirrornever captured it and the mirror's upload-pack rejected the want with "fatal: not our ref ", breaking CI behind the proxy.Tests
Checklist
cargo fmt --all --check,cargo clippy --all-targets --all-features --locked -- -D warnings,cargo test --all-featuresAssisted-by:trailer (see CONTRIBUTING.md / AGENTS.md)Breaking change?
If yes, describe the impact and the migration path (flags / env, on-disk cache layout).