Skip to content

safe-merge

Use when ready to merge a feature branch — validates all quality gates (tests, build, lint, conflicts, migrations) before merging. Also use when you want automated pre-merge verification.

ModelSourceCategory
sonnetcoreGit

Context: fork

Full Reference

Pre-merge quality gate validation. Ensures feature branches meet all requirements before merging to main.

Mandatory Announcement — FIRST OUTPUT before anything else:

┏━ 🚀 safe-merge ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ [one-line: branch name being merged] ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
CheckCommandFail Action
Not on maingit rev-parse --abbrev-ref HEADAbort — cannot merge FROM main
Clean working treegit status --porcelainPrompt to commit or stash
PR existsgh pr status --json state,reviewDecisionWarn — create PR first
Branch agegit log -1 --format=%ci HEADWarn if >7 days, flag if >14 days
Integration branchCheck if integrate/ prefixVerify all constituent branches merged first

Run all checks in sequence. Stop on first failure.

GateCommandRequirement
Type checknpm run check (or project equivalent)Exit code 0, no type errors
Buildnpm run build (or project equivalent)Successful completion
Lintnpm run lint (or project equivalent)No errors (warnings OK)
Testsnpm test (or project equivalent)All pass

Auto-detect the project’s test/build commands from package.json, Makefile, pyproject.toml, Cargo.toml, or go.mod.

Terminal window
git fetch origin main
git merge --no-commit --no-ff origin/main

If conflicts detected → abort merge, report conflicting files, provide resolution instructions.

If clean → git merge --abort (we’re just checking, not merging yet).

Detect migration files in the branch diff:

Terminal window
MIGRATION_FILES=$(git diff origin/main --name-only | grep -E "supabase/migrations/|drizzle/|prisma/migrations/|db/migrate/|alembic/versions/")

If migration files detected, run three checks:

Check 4a: Conflicting migrations on main

Terminal window
# Find migrations added to main after this branch diverged
MERGE_BASE=$(git merge-base HEAD origin/main)
MAIN_NEW_MIGRATIONS=$(git diff $MERGE_BASE..origin/main --name-only | grep -E "supabase/migrations/|drizzle/|prisma/migrations/")

If both branch AND main have new migrations since divergence — migration conflict risk:

  • ⚠ Both this branch and main have new migrations since diverge point. Rebase onto main before merging to ensure correct migration ordering.
  • Do NOT proceed until rebase is clean

Check 4b: Migration-first pattern (advisory)

If the branch diff contains BOTH migration files AND app code changes:

  • ℹ This branch has migrations mixed with app code. Consider the migration-first pattern: merge migration PR first, then app code PR. This prevents coupled failures.
  • Advisory only — do not block

Check 4c: Rollback plan

If migration files are present:

  • Verify migration files exist (not just schema changes without migrations)
  • Check for rollback plan or note in PR description
  • Prompt: “Has the database been backed up before applying these migrations to production?”

Use the project’s merge strategy. Default to squash merge via PR using REST API:

Terminal window
SLUG=$(git remote get-url origin | sed 's|.*github.com[:/]||;s|\.git$||')
env -u GITHUB_TOKEN gh api "repos/${SLUG}/pulls/${PR_NUM}/merge" \
--method PUT \
--field merge_method=squash \
--field commit_title="<type>(<scope>): <description> (#${PR_NUM})"

Never use gh pr merge — it uses GraphQL (rate-limited). Always use REST gh api.

If no PR exists, merge locally:

Terminal window
git checkout main && git pull origin main
git merge --no-ff <feature-branch>
git push origin main
Terminal window
git checkout main && git pull
npm run build && npm test

Confirm main is still green after merge.

## Safe Merge Report — <branch-name>
Pre-Flight ✓ branch: feat/my-feature ✓ clean tree ✓ PR #42
Quality Gates ✓ typecheck ✓ build ✓ lint ✓ tests (14 pass)
Conflicts ✓ no conflicts with main
Migrations ○ no schema changes
Merge ✓ squash merged via PR #42
Verdict: MERGE SUCCESSFUL

If any gate fails:

  1. STOP — do not proceed
  2. Report which gate failed with full error output
  3. Provide fix instructions
  4. Never merge until all gates pass
MistakeFix
Merging with failing testsRun full test suite — no exceptions
Skipping build checkBuild failures break deploy — always verify
Merging with conflictsResolve conflicts on the feature branch, not main
Not pulling latest main firstAlways fetch + check against latest main
Merging directly without PRGo through PR for audit trail and review