Merge
Combine merge-and-cleanup and merge-to-main into one flow. Default to fast-forward; preserve a merge commit when fast-forward isn't possible or the user asks for one. Always interactive about deleting branches and worktrees.
Flow
- Refuse if already on main. If
git rev-parse --abbrev-ref HEADreturnsmain(ormaster), stop and report — there's nothing to merge. - Working tree must be clean. If there are uncommitted changes, ask the user whether to commit, stash, or abort. Do not silently stash.
- Capture the feature branch name —
FEATURE=$(git rev-parse --abbrev-ref HEAD). - Sync main.
git checkout maingit pull --ff-only origin main
- Try fast-forward merge first.
git merge --ff-only "$FEATURE"- If it succeeds, history is linear — done with the merge step.
- If it fails (branch diverged), proceed to step 6.
- Fall back to merge commit —
git merge --no-ff "$FEATURE".- If there are conflicts, stop and report. Do not auto-resolve.
- Write a meaningful merge-commit message; do not accept the default if it's just "Merge branch …".
- Push —
git push origin main. - Interactive cleanup. Ask the user: "Delete
$FEATURE(local + remote) and any associated worktree?"- On yes:
- If a worktree exists for
$FEATURE(git worktree list | grep -F "$FEATURE"),cdto the main repo dir first, thengit worktree remove <path>. git branch -d "$FEATURE"(use-Donly if user explicitly confirms —-drefuses if branch isn't merged, which is the safety we want).git push origin --delete "$FEATURE"(ignore failure if branch was never pushed).
- If a worktree exists for
- On no: leave everything in place.
- On yes:
- Report final status — commit hash on main, whether branch was deleted, whether a worktree was removed.
Notes
- Prefer ff-only. Linear history is easier to reason about. Only fall back to a merge commit when the branch genuinely diverged.
- Never
--no-verify. If a pre-push hook fails, fix the underlying issue; don't bypass. - Worktree-first cleanup. If the feature branch was developed in a worktree, you cannot delete the branch from inside the worktree. Always
cdto the main repo working directory first. - Conflict policy. This skill does not auto-resolve conflicts. If
git mergereports a conflict, stop and surface it to the user — they decide.
Gotchas
git pull --ff-onlyon main fails if main has diverged locally (e.g., you committed directly to main). That's a different problem — surface it; don't paper over with--rebase.git branch -drefuses on unmerged branches. That refusal is your safety net — never automatically promote to-D.git push origin --deleteexits non-zero if the remote branch doesn't exist. That's fine in this flow (branch was local-only) — log and continue.- macOS case-insensitive filesystems can mask case-only conflicts; if the feature branch differs only in case from another branch,
git checkoutwill surprise you.