docs(runbook): stale "out-of-date" PR after a stacked PR is retargeted (refs #195)
CI / lint (pull_request) Successful in 1m43s
CI / k8s (pull_request) Successful in 9s
CI / build (pull_request) Successful in 1m8s
CI / docs (pull_request) Successful in 44s
CI / unit (pull_request) Successful in 1m21s
CI / frontend (pull_request) Successful in 2m20s
CI / mutation (pull_request) Successful in 4m28s
CI / verify-stack (pull_request) Skipped

Gitea 1.27 blocks the merge on a stored commits_behind that a same-second
retarget + force-push can leave stale, while Update branch recomputes it
live and refuses. Record the symptom, the cause and the amend + force-push fix.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
not
2026-10-02 12:56:13 +02:00
co-authored by Claude Opus 5.5
parent 5fdcbd27c0
commit 7baa5d2006
+39
View File
@@ -15,6 +15,7 @@ those containers share a filesystem — or a `localhost` — breaks.
| `pg_isready` passes before PostGIS is ready | add a `PostGIS_Version()` probe | the db healthchecks |
| `upload-artifact@v4` fails ("not supported on GHES") | pin `@v3` | `.gitea/workflows/ci.yaml` (`mutation` job) |
| `upload-artifact@v3` fails with "Artifact service responded with 500" | mark the upload `continue-on-error: true` (server-side; issue #62) | `.gitea/workflows/ci.yaml` (`mutation` job) |
| PR says "out-of-date" but *Update branch* fails ("Unable to update pull request") | push a new head SHA (`commit --amend --no-edit` + `push --force-with-lease`) | §10, server-side |
---
@@ -289,3 +290,41 @@ re-run hides the failed one, so keep the failing job id from the original report
- Remember `concurrency.cancel-in-progress: true` in `ci.yaml`: a new push to the same
ref, or a re-run, kills the in-flight run the same way. Check `run_attempt` before
concluding a job hung.
---
## 10. A retargeted stacked PR says "out-of-date" but *Update branch* fails
**Symptom** — the PR shows *This branch is out-of-date with the base branch* and
*This pull request is blocked because it's outdated* (branch protection
`block_on_outdated_branch` on `main`), yet **Update branch** answers *Unable to update
pull request* (API: `HeadBranch of PR NN is up to date`). `git merge-base` confirms the
branch sits on the tip of `main`. Seen on #194 (#195).
**Why** — Gitea 1.27 keeps two answers to "is it behind?":
- The banner and the merge block read a **stored** `pull_request.commits_behind`
(`MergeBlockedByOutdatedBranch`: `CommitsBehind > 0`).
- *Update branch* recomputes it **live** from git (`services/pull/update.go`) and refuses
when nothing is behind.
The stored count is only refreshed by a push to the head or base branch, or by a
retarget. #194 was stacked on #193; its rebased branch was force-pushed in the **same
second** that merging #193 deleted the parent branch and Gitea retargeted #194 to `main`.
The retarget compared `main` against `refs/pull/194/head` before the push queue had
updated that ref (the old head missed the squash commit → `CommitsBehind = 1`); the push
handler's own resync ran against the deleted old base and failed. Nothing pushed
afterwards, so the stale `1` stuck. Close/reopen does not recompute it.
**Fix** — give the head a new SHA with the same content; the push resyncs the count:
```bash
git commit --amend --no-edit # new committer date → new SHA
git push --force-with-lease origin <branch>
```
PR CI re-runs on the new SHA (the old statuses don't carry over).
**Avoid it** — when the parent of a stacked PR merges, let Gitea finish retargeting the
child to `main` (its timeline shows *changed target branch*) **before** pushing the
rebased child branch.