Safe PR Workflow
The Problems
-
Pushing to a merged branch. When a PR is merged but you continue working on the same branch, subsequent pushes silently update the merged PR's branch on the remote. No new PR is created -- the commits just land on a dead branch. The user sees no PR and has to manually fix things.
-
Stale commits leaking into a new PR. When multiple PRs are created from the same branch over time, earlier commits that were already merged via a previous PR can end up in the new PR's diff. This happens when the branch is not rebased onto the latest base branch before creating the new PR.
-
PR merged mid-push. A PR can be merged by another person (or CI) while you are still pushing additional commits to the same branch. The push succeeds, but the new commit lands on a dead branch -- it is not part of the merge and no one will see it. This is a race condition that must be checked after every push, not just before.
Rules
Before every git push
-
Check if the current branch already has a merged or closed PR:
gh pr list --head <current-branch> --state merged --json number,title gh pr list --head <current-branch> --state closed --json number,title -
If a merged/closed PR exists on this branch, do not push. Instead:
- Create a new branch from the current HEAD
- Push the new branch
- Create a fresh PR from the new branch
-
If no merged/closed PR exists, push is safe.
Before creating a PR with gh pr create
-
Run the same merged/closed PR check above -- verify the branch doesn't already have a merged/closed PR. If it does, create a new branch first.
-
Rebase onto the latest base branch to ensure only the intended commits are in the PR:
git fetch origin main git rebase origin/mainAfter rebasing, verify the commit list is what you expect:
git log --oneline origin/main..HEADEvery commit listed will appear in the PR. If you see commits that were already merged in a previous PR, the rebase did not complete correctly -- investigate and resolve before pushing.
-
Force-push with lease after rebasing to update the remote branch safely:
git push --force-with-lease origin <branch>
After every git push
Re-check the PR state immediately after pushing. The PR may have been merged between the pre-push check and the push itself:
gh pr list --head <current-branch> --state merged --json number,title
If the PR was merged and your push included commits that are not part of the merge:
- Fetch the latest base branch and rebase:
git fetch origin main git rebase origin/main - Verify only the orphaned commit(s) remain with
git log --oneline origin/main..HEAD. - Create a new branch, push, and open a fresh PR:
git checkout -b <new-descriptive-branch> git push -u origin <new-descriptive-branch> gh pr create --base main ...
When continuing work after a PR was merged mid-session
If you pushed earlier in the session and the PR was merged, any new commits need a new branch:
# Check current branch state
gh pr list --head $(git rev-parse --abbrev-ref HEAD) --state all --json number,title,state
# If merged PR found, create new branch from current HEAD
git checkout -b <new-descriptive-branch>
git push -u origin <new-descriptive-branch>
gh pr create --base main ...
When reusing a branch for a second PR
If the user creates multiple PRs from the same branch across the session (e.g. the first PR was merged and they kept working):
- Fetch and rebase onto the base branch before pushing or creating the new PR.
- Confirm with
git log --oneline origin/main..HEADthat only the new commits are ahead. - If stale commits appear, the rebase will typically drop them automatically (git skips already-applied cherry-picks). If not, investigate the conflict.
What Not To Do
- Never assume a branch is clean for pushing just because
git pushsucceeds. A push to a merged PR's branch succeeds silently. - Never reuse a branch that had a merged PR for new work without creating a fresh branch.
- Never create a PR without first rebasing onto the latest base branch. Skipping the rebase risks including already-merged commits in the new PR's diff.
- Never use
git push --force-- always usegit push --force-with-leaseto avoid overwriting someone else's work. - Never skip the post-push PR state check. A PR can be merged between your pre-push check and the actual push, leaving your commit orphaned on a dead branch.
