Repository navigation
A pull request can only be tried against today's trunk, never as its author wrote it #290
Description
Applying a pull request today means carrying its diff onto the current checkout. That answers one question: does this change still work against today's trunk? It is the cheap question — the clone, the installed dependencies and the build are all reused — and most of the time it is the right one.
It is not the only one a reviewer asks. Does the pull request work as its author wrote it? is a different question, and on the command line it has a different answer: fetch the pull request's branch and stand on it. That route cannot fail to apply, because nothing is applied — the tree simply becomes what the author tested. It is how contributors habitually try each other's work.
The app performs the first route silently and presents its failures as the pull request's. In the case that surfaced this (Trac #62064, via #282 and #226), the apply refused with conflicts; the branch itself was fine — seventeen months old, and exactly what its author meant to be tested. A contributor who only wanted to see the change running was charged for a question they had not asked.
What the option costs, and why the button must say so
Standing on a seventeen-month-old tree means a different lockfile and a different build: install and rebuild, minutes not seconds — and the same again on the way back to trunk. That is inherent to the question, not an implementation failure; the command line charges exactly the same. The app's job is to state the price before the click, not to hide the route because it has one.
What is plumbing and what is design
The plumbing exists: the bundled git implementation can fetch a pull request's ref at depth 1 and check it out. No git binary, no GitHub CLI, nothing new on the host — checked by hand against a real pull request.
The open part is the model, not the fetch. A site holds a pristine trunk and one branch per ticket (#108); a foreign branch is a third kind of thing. Where the contributor's parked work goes while they stand on it, what state the dev server and build watcher are in across the switch, and what "back" is called and shown as — those are design questions this issue leaves open on purpose.
Deliberately not proposed
Replacing the current apply. Onto-today's-trunk stays the default: it is the cheap route, and with the second half of #226 it stops failing for the wrong reasons. This issue is only about the other question existing at all, priced honestly, for the contributor who is asking it.
Trac attachments are out of scope — an attachment has no branch to stand on. This is a pull-request-only route.
Related
- "No longer applies" hides a patch that is already in the tree — sometimes in the same file as one that is not #226 — applying from a recorded base; the fix for the default route's false failures
- A patch that no longer applies is a dead end, and the app is already holding the way out #282 — what the contributor is told when the default route refuses
- Working on a second ticket means rebuilding the world: tickets should be branches, not sites #108 — the branch model this option has to coexist with
Activity
Say how much of a patch failed, why, and what to do next when it will…
juanmaguitar commentedon Aug 13, 2026
Closing as not planned for the current experimental validation phase. This remains a valid, searchable observation, but there is not enough user evidence or near-term intent to keep it in the active work queue. It can be reopened if real usage shows material impact.
juanmaguitar commentedon Aug 18, 2026
Reopening under #350, on the condition the closing note set: the intent now exists. The design work behind #350 names standing on a pull request's branch as its first piece, and #349 needs the same foreign-ref plumbing for release branches — two consumers where there were none.
Two additions to the scope as written here:
Everything else in the body stands, the price-before-the-click rule especially.
juanmaguitar commentedon Sep 9, 2026
Still open; the ref-fetch plumbing no longer needs implementation.
fetchBranchinsrc/git-write.cjsfetches an explicit ref through the pinned HTTPS, HTTP, or file transports. Reframe the remaining work as UI and product state above that primitive: create the local PR branch, park and switch safely, state the dependency rebuild cost before the action, and provide the route back.[Add] Pin the ticket move's conflicts to Git's, and word them by kind (…
juanmaguitar commentedon Sep 11, 2026
Spike run against the question this issue leaves implicit: once you stand on the author's branch, does it still install and build? Eight open core PRs, the real command-line ritual, on the app's own partial clone.
The ritual is two git commands.
gh pr checkout 4535fetchesrefs/pull/4535/headfromorigin, names the local branch with the author's own head ref (58442-add-parameter-to-filter-archives, notpr/4535), and adds no remote. It only writes the fork's URL intobranch.<name>.pushremote. So the app needsfetchBranch(dir, 'origin', 'refs/pull/N/head')unchanged plus a checkout. No second remote, no credentials, no new plumbing.Measurements (macOS arm64, Node 24.18, which is what Electron 43 ships, so this is the app's own runtime):
npm cinpm run build:devThree corrections to the body:
The price is seconds, not minutes. The body justifies the price-before-the-click rule with "install and rebuild, minutes not seconds". Measured: 15s + 16s. The rule loses most of its weight.
Old branches do not take longer, they fail, on dead native dependencies (puppeteer with no arm64 Chromium, node-sass wanting a node-gyp toolchain that is gone). And they fail in 12 to 24 seconds, faster than the slowest success.
npm installbreaks the "nothing is applied" promise;npm cikeeps it.npm installrewritespackage-lock.jsonfrom lockfileVersion 1 to 3, 29,100 lines inserted, and the tree is dirty before the contributor touches anything.npm cileavesgit statusempty after install and after build. The app currently runsnpm install(src/install-runner.js:27), so the PR route needsnpm ci.How rare the failing case is. Of the 100 most recently updated open PRs, 97 have a 2026 head and none is older than 2022. Of the 100 oldest, 94 have a head before 2022. The dead zone is roughly 250 abandoned PRs out of 3,450 open, about 7%, all in one corner. A live core PR carries a 2026 head regardless of when it was opened.
Two things that do not work as gates, both tested rather than assumed:
node-sassand oldpuppeteerentries too. No cheap predictor.What this suggests for the design. No pre-emptive dialog. This issue's own test in #350 says a dialog, decision or wait added to the newcomer's path is the wrong answer, and a confirmation before crossing is exactly that, asked about a case they will almost never meet and cannot answer anyway. Instead: cross without asking; when
npm cifails, say which package died, within 20 seconds; and offer the diff route there, which for an abandoned PR works fine and already exists. The install failure becomes a first-class state rather than a wall of npm output.Caveats: eight PRs, one platform. The failures are puppeteer with no arm64 Chromium, so the same branches may well install on Windows x64. That is the reason not to hard-code a date threshold anywhere.
[Add] A pull-request checkout module and the Git reads it needs (#458) (
[Add] Wire pull-request checkout through IPC (#458) (#460)
[Add] Check out a pull request from the Apply panel (#458) (#461)
Bump the version to 1.1.0-beta.2 (#466)