| name | smart-merge |
| description | Merges branches with comprehensive validation while preserving feature branches. Use when user wants to merge PR, sync with main, update feature branch, complete merge, or finalize work. Runs full validation (tests, lint, CI, review comments), merges without deleting branches, and always returns to the working branch. |
| license | MIT |
| context | fork |
| agent | general-purpose |
| allowed-tools | Read, Grep, Glob, Bash(git *), Bash(gh *), Bash(pnpm *), Bash(npm *), Bash(npx *), Bash(yarn *), Bash(pytest *), Bash(python *), Bash(mypy *), Bash(ruff *), Bash(pylint *), Bash(go *), Bash(golangci-lint *), Bash(wc *) |
Smart Merge
Merges branches with pre-merge validation while preserving your feature branch.
Two Merge Modes
| Mode | Direction | Purpose | Core Command |
|---|
| Sync | main -> feature | Keep feature branch current | git merge origin/main |
| PR Merge | feature -> main | Complete work via PR | gh pr merge --merge |
Feature branch is never deleted. You stay on (or return to) your working branch after every operation.
Package Manager Detection
Detect the project's package manager before running validation. The script checks in priority order: pnpm-lock.yaml wins over any other lock file, so projects with multiple lock files default to pnpm.
| Lock File | Manager | Run Command |
|---|
pnpm-lock.yaml | pnpm | pnpm <script> |
package-lock.json | npm | npm run <script> |
yarn.lock | yarn | yarn <script> |
requirements.txt / pyproject.toml | pip/poetry | pytest / ruff check / mypy |
go.mod | go | go test ./... / go build ./... |
if [ -f pnpm-lock.yaml ]; then PM="pnpm"
elif [ -f yarn.lock ]; then PM="yarn"
elif [ -f package-lock.json ]; then PM="npm run"
elif [ -f go.mod ]; then PM="go"
elif [ -f pyproject.toml ] || [ -f requirements.txt ]; then PM="python"
else PM="pnpm"; fi
Pre-Merge Validation
Run these checks before every merge. Stop and report failures instead of proceeding.
| Check | JS/TS Command | Python Command | Go Command | Gate |
|---|
| Type check | $PM typecheck or npx tsc --noEmit | mypy src/ | go vet ./... | Block |
| Lint | $PM lint | ruff check src/ | golangci-lint run | Block |
| Tests | $PM test | pytest | go test ./... | Block |
| Build | $PM build | N/A | go build ./... | Block |
| CI green | gh pr checks $PR | Same | Same | Block (PR mode only) |
| Comments replied | See comment check below | Same | Same | Block (PR mode only) |
If any check fails, stop the merge and report which check failed with the full error output.
Mode 1: Sync (main -> feature)
Bring main into your feature branch. Run regularly to catch conflicts early.
Steps:
- Save current branch:
FEATURE_BRANCH=$(git branch --show-current)
- Fetch latest:
git fetch origin
- Run pre-merge validation (all checks above except CI and comments)
- Merge main into feature:
git merge origin/main
- If conflicts occur, resolve them (see Conflict Resolution below)
- Run validation again after merge completes
- Verify you are still on
$FEATURE_BRANCH: git branch --show-current
Conflict Resolution:
- List conflicted files:
git diff --name-only --diff-filter=U
- Resolve each file
- Stage resolved files:
git add <file> (stage each file by name, not git add .)
- Complete merge:
git commit
- Re-run validation
Rebase alternative (linear history):
Use rebase only on local/personal branches, never on shared branches.
git fetch origin
git rebase origin/main
git push --force-with-lease
Mode 2: PR Merge (feature -> main)
Merge your PR after approval. Confirm with the user before executing the merge.
Steps:
- Save current branch:
FEATURE_BRANCH=$(git branch --show-current)
- Get PR number:
PR=$(gh pr view --json number -q '.number')
- Check for unreplied review comments (see below). If any exist, stop and report them.
- Run full pre-merge validation (all checks including CI)
- Show PR summary to user:
gh pr view $PR --json title,commits,changedFiles --jq '
"Title: \(.title)\nCommits: \(.commits | length)\nFiles changed: \(.changedFiles)"
'
- Ask the user to confirm before proceeding
- Pick merge strategy. Default to
--merge. Use --squash if the repo enforces squash merges, --rebase if it enforces linear history. Check repo policy: gh repo view --json mergeCommitAllowed,squashMergeAllowed,rebaseMergeAllowed
- Execute merge (do not use
--delete-branch):
gh pr merge $PR --merge --body "$(cat <<'EOF'
- Key change 1
- Key change 2
Tests: passed
Reviews: addressed
EOF
)"
- Return to feature branch:
git checkout "$FEATURE_BRANCH"
Check unreplied review comments:
PR=$(gh pr view --json number -q '.number')
REPO=$(gh repo view --json nameWithOwner -q '.nameWithOwner')
UNREPLIED=$(gh api repos/$REPO/pulls/$PR/comments --jq '
[.[] | select(.in_reply_to_id) | .in_reply_to_id] as $replied |
[.[] | select(.in_reply_to_id == null) | select(.id | IN($replied[]) | not)]
| length
' 2>/dev/null) || {
echo "Warning: Could not fetch comments. Verify manually."
UNREPLIED=0
}
if [ "$UNREPLIED" -gt 0 ]; then
echo "Blocked: $UNREPLIED unreplied comments. Address them before merging."
exit 1
fi
Post-Merge Verification
Run this checklist after every merge operation:
Post-Merge Checklist:
- [ ] On correct branch: git branch --show-current
- [ ] Clean working tree: git status
- [ ] Merge visible in history: git log --oneline -5
- [ ] Validation passes: $PM test && $PM lint && $PM typecheck
If any check fails, see Error Recovery below.
Merge Message Format
Keep merge messages under 10 lines:
- Key change 1 (what was added/fixed)
- Key change 2
- Key change 3
Tests: X passed
Reviews: N/N addressed
Refs: #123, PROJ-456
Rules
| Rule | Action |
|---|
| Run validation before and after every merge | Block the merge on any failure |
| Confirm with user before PR merge | Show PR summary first, then ask |
Never use --delete-branch flag | Feature branch must survive the merge |
| Never reply to PR comments from this skill | Report unreplied comments, let user handle them |
| Never force push to shared branches | Use --force-with-lease only on personal branches after rebase |
| Stop on failing tests, lint errors, pending CI, unreplied comments, or unresolved conflicts | Report the failure and do not proceed |
Branch Preservation
| Operation | Branch Status After |
|---|
| Sync (main -> feature) | Feature branch updated, stays checked out |
| PR Merge (feature -> main) | Feature branch kept, switched back after merge |
To delete a branch after merge (only when the user explicitly requests it):
git branch -d feature/my-branch
git push origin --delete feature/my-branch
Error Recovery
Merge failed mid-way:
git merge --abort
git status
On wrong branch after merge:
git checkout "$FEATURE_BRANCH"
Undo a completed merge:
git reflog
git reset --hard <sha>
**Sync: Simple merge with no conflicts**
User: "Sync my branch with main"
- Detected pnpm from
pnpm-lock.yaml
- Ran
pnpm test && pnpm lint && pnpm typecheck -- all passed
- Ran
git fetch origin && git merge origin/main -- fast-forward merge
- Ran validation again -- all passed
- Confirmed on branch
feature/auth-flow
Result: Branch synced, 0 conflicts, all checks green.
**Sync: Merge with conflicts**
User: "Update my feature branch from main"
- Detected npm from
package-lock.json
- Ran
npm run test && npm run lint -- passed
- Ran
git fetch origin && git merge origin/main -- 2 conflicts in src/api.ts and src/config.ts
- Listed conflicts:
git diff --name-only --diff-filter=U
- Resolved both files, staged with
git add src/api.ts src/config.ts
- Completed merge:
git commit
- Ran validation again -- passed
- Confirmed on branch
feature/new-api
Result: Branch synced, 2 conflicts resolved, all checks green.
**PR Merge: Successful merge after review**
User: "Merge my PR"
- Detected pnpm, ran full validation -- all passed
- Checked unreplied comments -- 0 unreplied
- Verified CI:
gh pr checks 47 -- all green
- Showed summary: "Title: Add auth module | Commits: 3 | Files changed: 7"
- User confirmed
- Ran
gh pr merge 47 --merge (no --delete-branch)
- Returned to
feature/auth-module with git checkout
Result: PR #47 merged, feature branch preserved, back on working branch.
**PR Merge: Blocked by unreplied comments**
User: "Merge my PR into main"
- Detected pnpm, ran validation -- all passed
- Checked unreplied comments -- found 2 unreplied
- Stopped. Reported: "Blocked: 2 unreplied review comments on PR #32. Address them before merging."
Result: Merge blocked. User needs to reply to review comments first.