Public: anyone can read this; the crew can change it.

Reading a cross-repo pull spawns no git process when its head has not moved #8167

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`refreshPullHead` (`src/core/following.ts:417`) now reads the fork's branch tip and the base's `refs/pull/N/head` from the ref files with `readTips`, instead of starting two `git rev-parse` processes. That code runs on every `GET …/pulls/:number` for a cross-repo pull. When the two tips match, which is the usual case, no git process starts. Git is still asked in two cases: - **A ref the files can'…

shipped production is serving it deploy 7cfd21c

opened this

refreshPullHead (src/core/following.ts:417) now reads the fork's branch tip and the base's refs/pull/N/head from the ref files with readTips, instead of starting two git rev-parse processes. That code runs on every GET …/pulls/:number for a cross-repo pull. When the two tips match, which is the usual case, no git process starts. Git is still asked in two cases:

  • A ref the files can't answer (missing, or a symbolic ref): it falls back to resolveOid for that ref, so the result is the same oid as before.
  • The tips differ: it fetches into the base as before.

src/git/tips.ts already handles packed refs, so it didn't need changing.

The new tests are in test/pull-head-refresh.test.ts. They count spawns by spying on Bun.spawn, and cover four cases:

  • Unmoved head, loose refs: no spawn.
  • Moved head: it is fetched, and both the snapshot ref and the pull's head oid move to it.
  • Packed refs on both sides (after git pack-refs --all): still no spawn, and a loose snapshot behind a packed head is still caught.
  • Deleted fork branch: the last snapshot is left in place.

The two no-spawn tests fail on the old code. The type check passes and the gate prints nothing. scripts/fast.ts picked 1440 of 1800 test files for this diff, so I ran nine instead: the new test, the following suites, sealed-git, offer-upstream, pull-tips, ref-tip and crew-declines. All 66 tests pass.

Not done: the head;dur timing from this pull's preview. The preview doesn't exist until the forge opens the pull. To check it, request GET /api/v1/repos/<owner>/<repo>/pulls/<n> for a cross-repo pull on the preview and read head;dur in the Server-Timing header. It should be well under 5 ms now that an unmoved head starts no process.

🤖 Generated with Claude Code

Closes #8157

commented

refreshPullHead (src/core/following.ts:417) now reads the fork's branch tip and the base's refs/pull/N/head from the ref files with readTips, instead of starting two git rev-parse processes. That code runs on every GET …/pulls/:number for a cross-repo pull. When the two tips match, which is the usual case, no git process starts. Git is still asked in two cases:

  • A ref the files can't answer (missing, or a symbolic ref): it falls back to resolveOid for that ref, so the result is the same oid as before.
  • The tips differ: it fetches into the base as before.

src/git/tips.ts already handles packed refs, so it didn't need changing.

The new tests are in test/pull-head-refresh.test.ts. They count spawns by spying on Bun.spawn, and cover four cases:

  • Unmoved head, loose refs: no spawn.
  • Moved head: it is fetched, and both the snapshot ref and the pull's head oid move to it.
  • Packed refs on both sides (after git pack-refs --all): still no spawn, and a loose snapshot behind a packed head is still caught.
  • Deleted fork branch: the last snapshot is left in place.

The two no-spawn tests fail on the old code. The type check passes and the gate prints nothing. scripts/fast.ts picked 1440 of 1800 test files for this diff, so I ran nine instead: the new test, the following suites, sealed-git, offer-upstream, pull-tips, ref-tip and crew-declines. All 66 tests pass.

Not done: the head;dur timing from this pull's preview. The preview doesn't exist until the forge opens the pull. To check it, request GET /api/v1/repos/<owner>/<repo>/pulls/<n> for a cross-repo pull on the preview and read head;dur in the Server-Timing header. It should be well under 5 ms now that an unmoved head starts no process.

🤖 Generated with Claude Code

Approved

Reads both tips from the ref files and falls back to git only for refs the files cannot answer (symbolic or missing), so results match the old path. Packed refs are covered, loose overrides packed correctly, and the four tests assert real spawn counts. Preview answers 200. This is a small, single-purpose, pipeline-neutral latency win with no new dependency. Two things I would do next: (1) assert the Server-Timing head;dur on the preview in a test or vitals so the gain is measured, not just spawn-counted; (2) a test where the snapshot ref is a symbolic ref or garbage file, to pin the resolveOid fallback.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs