Final squash of all branch commits into one clean commit and force push for merge. Use after PR approval, before merging.
Squashes all branch commits into a single clean commit and force pushes for the final merge. This is the last step before merging the PR on GitHub.
No documentation pipeline is run — docs were handled during finalize and review cycles.
Parse $ARGUMENTS for flags:
--no-push — squash and commit but don't force push--dry-run — show what would be squashed without doing itVerify you are NOT on the default branch:
!git rev-parse --abbrev-ref HEAD
If on the default branch, stop:
"You are on the default branch. Merge-prep is for feature branches only."
Detect the default branch:
!gh repo view --json defaultBranchRef -q '.defaultBranchRef.name' 2>/dev/null || git rev-parse --verify main 2>/dev/null && echo main || echo master
Store as BASE_BRANCH.
Run git status --porcelain. If there are uncommitted changes, stop:
"Working tree has uncommitted changes. Commit or stash them first."
Merge-prep should only operate on committed code.
gh pr view --json reviewDecision -q '.reviewDecision'
If the result is APPROVED, proceed normally.
If not approved (or no review), warn:
"PR has not been approved yet (status: [status]). Continue anyway? This is unusual — merge-prep is typically run after approval. (yes/no)"
Wait for confirmation.
git log $(git merge-base HEAD $BASE_BRANCH)..HEAD --oneline
git diff $(git merge-base HEAD $BASE_BRANCH)..HEAD --stat
"The following N commits will be squashed into a single commit: [commit list]
Touching N files: [diff stat summary]
This will rewrite history and require a force push. Continue? (yes/no)"
Wait for confirmation. If no, stop.
In --dry-run mode: Show this preview and stop.
git reset --soft $(git merge-base HEAD $BASE_BRANCH)
git diff --cached --stat
Confirm the staged changes match the diff stat from step 1. If they don't match, something went wrong — stop and report.
Read the PR title and description:
gh pr view --json title,body
Read any changeset files:
ls .changeset/*.md 2>/dev/null
Generate a conventional commit message from:
Present to the user for review:
"Proposed commit message:
type(scope): subject [description] Signed-off-by: [name] <[email]>Accept, edit, or abort? (accept/edit/abort)"
If "edit", ask the user for their changes. If "abort", the user can recover
with git reflog.
git commit -m "<final message>"
Skip if --no-push flag is set. Report:
"Squashed commit created locally. Push manually with:
git push --force-with-lease origin HEAD"
Use --force-with-lease for safety (fails if remote has commits not in local):
git push --force-with-lease origin HEAD
"Force pushed squashed commit to [branch]. PR: [url] Ready to merge on GitHub."
git tag -d session/start 2>/dev/null || true
If the PR body has changed significantly from the squash (e.g., the commit message is now more comprehensive), offer to update:
"Update PR description with the final commit message? (yes/no)"
If yes:
gh pr edit --body "<updated body>"
If the squash fails mid-operation:
git reflog then git reset --hard <pre-squash-ref>"If the force push fails:
git fetch && git log origin/[branch]..HEAD and retry."