# GitHub - Pull Request Workflow Squash merges break git's merge bookkeeping. A deleted base branch closes every stacked child PR, and a new push invalidates review anchors. These procedures keep cleanup, stacking, and review reliable. ## Stacked PRs and squash merges - Squash-merged branches never appear as merged to git: the tip never becomes an ancestor of `main`. Delete them with `git branch -D` once the remote ref shows `[gone]`. - `git branch --merged` catches only true merge commits. Diff each tip against `main` to detect squash-merges, and categorize before you delete. - `git fetch --prune` before local pruning confirms what truly merged into `origin/main`, so cleanup cannot delete unmerged work. - Stacked PRs need every base branch in the same repository as the target. A cross-repo stack, fork head against upstream base, breaks because GitHub cannot resolve the shared history. - `gh pr merge --delete-branch` on a stacked PR does not retarget the children. GitHub closes every PR whose base branch was deleted. Retarget remaining PRs to `main` first, merge without branch deletion, clean up last. - Plan the rebase order from `gh pr list --repo <org/repo> --author <handle> --state open --json number,title,headRefName,baseRefName`. - MERGEABLE compares each branch against `main` in isolation. Same-day PRs that write one shared file can all show clean while each is a divergent add/add. Mergeability says nothing about PR-to-PR overlap. The merge order decides where conflicts surface, and taking one side is silent data loss. - Prove a union merge lost nothing: grep the merged file for a signature phrase from every source PR. If all hit, nothing dropped. - After a parent squash-merge, `git rebase --onto main <old-parent-tip>` replays only the child's unique commits. ## Review threads and anchors - Only `gh pr diff` defines a PR's scope. A merge-base diff pulls in already-merged commits from other PRs, and a divergent worktree yields phantom findings. The GitHub diff is authoritative for added files. - Read PR-head code without a checkout: `git show <sha>:<path>` and `git diff <base> <head> -- <path>`. - `refs/pull/<n>/head` exists on the base repository regardless of the source fork: `git fetch <remote> pull/<n>/head:review-pr-<n>` plus a scratch worktree. - Read the thread before you draft: `pulls/<n>/reviews`, `pulls/<n>/comments`, `gh pr view --comments`. This removes findings maintainers already handled or resolved. - A PR head can move mid-review and invalidate every anchor. Re-verify at the live head before posting and after every force push. - `CHANGES_REQUESTED` with a last commit older than the last review means the author's turn. `mergeStateStatus: DIRTY` or `CONFLICTING` means rebase is the first blocker. - Post reviews with `gh api repos/{owner}/{repo}/pulls/{n}/reviews --input payload.json` and `event: COMMENT`. The `--input` form preserves backticks and markdown where `-f` flags do not. - A batched `COMMENT` review needs a non-empty top-level body and 422s when any `path`, `line`, or `side` anchor misses the diff. Post inline-only sets individually via `pulls/<n>/comments`. - Anchor inlines at the live head: `commit_id`, `side: RIGHT`, `line` inside a hunk. The API silently drops out-of-hunk lines and rejects binary-file anchors. Verify every inline landed. - Build payloads with jq `--arg body "$body"`, which escapes newlines where a raw heredoc through `jq --argjson` throws a parse error. - Verify handles with `gh api users/<handle>` and the repo's MAINTAINERS or CODEOWNERS before tagging people in outward-facing issues. Near-identical spellings exist. - Confirm a suspected bypass with a throwaway probe test at the PR head: run it, then delete it. It turns a suspicion into a confirmed finding. ## Reviewing versioned and duplicated code - Copy-paste versioning hides its bugs in the divergence. Three byte-identical middleware copies differed by one dropped `runtime.SuppressHTTPClientInstrumentation(ctx)` line, so one version emitted a duplicate net/http span per call. CI stayed green because the only end-to-end test covered one version. The divergence surfaced from mechanically diffing the copies. - Read prior maintainer rounds before you post. One finding was the deliberate opposite of an earlier round's request for tools-only aggregator packages, and the retraction is part of adjudication. The misleading error had a real cause in unchecked load errors. - When the key files do not exist yet, such as a PR that adds stubs, standard diff review fails. Compare the stubs against the parallel implementations of the same pattern and the design intent. - Near-duplicate implementations inherit each other's bugs. Two recompressors that differed only in the output writer type shared a goroutine-blocking bug. Unify the duplicates first, then fix once through the shared close path. ## How to apply 1. `git fetch --prune`, then list the stack with the `gh pr list` command above. 2. Retarget every child PR to `main` before you merge its parent, without `--delete-branch`. 3. Rebase a child after the parent squash-merge: `git rebase --onto main <old-parent-tip>`. 4. Categorize by tip diff, confirm `[gone]`, then `git branch -D`. 5. Read `pulls/<n>/reviews`, `pulls/<n>/comments`, `gh pr view --comments` before you draft. 6. Re-verify findings at the live head. Build the payload with jq `--arg`, post with `event: COMMENT`, then verify every inline landed. ## Observations - [git] Squash-merged branches never appear as merged to git: the tip never becomes an ancestor of `main`. #branch-cleanup (source: agent sessions, 2026-02) - [github] Merging a stacked PR with branch deletion closes every child PR. #stacked-prs (source: agent sessions, 2026-07) - [github] The review API silently drops inline comments anchored outside diff hunks or on binary files. #github-api (source: agent sessions, 2026-10) - [code-review] Mechanically diffing versioned copies surfaces divergence that reading one copy hides. #duplication (source: agent sessions, 2026-06) ## Relations - relates_to [[resources/documentation/Git - Rebase, Stash, and Recovery]] (`git rebase --onto` after a squash-merge) - relates_to [[resources/documentation/GitHub - gh CLI and API Usage]] (review posting via `gh api`) - relates_to [[resources/documentation/Agents/Agents - Worktree Workflows and Pre-PR Review]] (scratch review worktrees) ## Sources - Personal agent-session notes, February 2026 to November 2026