git-flow-pro — small, clear commits; PRs that get reviewed
When to use this skill
Trigger when the user wants to package work for review or history. Strong signals:
- "commit this", "make a commit", "git commit"
- "open a PR", "draft a PR description"
- "clean up my branch", "squash these", "rebase onto main"
- "what should I name this branch?"
Do not trigger for: pushing to main (require confirmation), force-pushing to shared branches (require confirmation), or rewriting published history (require confirmation).
The output contract
Git artifacts that:
- Tell a story — the commit log reads like a changelog. Each commit is one logical change.
- Match conventions — Conventional Commits (or whatever the repo uses), the team's branch naming, the team's PR template.
- Explain the why — not the diff. The diff already shows what changed.
- Stay safe — no force-push to shared branches without explicit confirmation; no rewriting commits that have been reviewed.
Workflow
1 — Sense the conventions
Before writing anything:
git log --oneline -20— what does this project's history look like? Conventional Commits (feat:,fix:)? Imperative present tense? Past tense?cat .github/pull_request_template.md 2>/dev/null— is there a PR template?git branch -r --contains HEAD | head— what's the trunk branch called (main,master,trunk,develop)?git config user.emailand the recent author list — match the style of the current contributors.
Mirror what's there. Don't introduce Conventional Commits to a project that uses prose, and vice versa.
2 — Stage with intent
Read git status and git diff --cached (and unstaged). Group changes by intent:
- One feature → one commit
- A test for that feature → squashed into the same commit, or right after
- An unrelated typo fix you noticed → separate commit
- Generated files (
package-lock.json, etc.) → include if they belong to the same change
Use git add -p mentally — pick hunks per commit, not whole files when the file has mixed concerns.
3 — Write the commit message
Format (when Conventional Commits is in use):
<type>(<scope>): <imperative present-tense subject, < 72 chars>
<body — what changed and *why*, wrapped at 72 chars>
<footer — Refs, Closes, Co-authored-by, BREAKING CHANGE>
Types: feat, fix, refactor, perf, test, docs, build, ci, chore, style, revert.
Subject rules:
- Imperative present: "add" not "added"/"adds"
- No trailing period
- Capitalize first letter after the colon:
feat(auth): Add password reset— or all-lowercase, whatever the repo does - Under 72 chars
Body rules:
- Skip the body for trivial commits (typo, comment, version bump)
- Otherwise: 1–3 short paragraphs. Lead with why this change was needed, then what changed if non-obvious. The diff covers the rest.
- Reference issues at the end:
Refs #1234,Closes #567
If the project doesn't use Conventional Commits, drop the type prefix but keep the imperative subject rule.
4 — Branch naming
Match the team's style. Common patterns (use whichever the repo's branch list shows):
<type>/<short-slug>:feat/password-reset,fix/login-redirect<author>/<short-slug>:ashish/password-reset<issue>-<slug>:1234-password-reset
Keep slugs short: 2–4 words, kebab-case, no full sentences.
5 — PR description
Use the template if one exists. Otherwise default to:
## What this PR does
<2–4 sentences. The user-visible change first, the technical change second.>
## Why
<The motivation — the bug, the requirement, the upstream blocker. Link the issue.>
## How
<Only if non-obvious. Skip if the diff is self-explanatory.>
## Testing
- [ ] What you verified manually
- [ ] What's covered by automated tests
- [ ] What you explicitly did *not* test
## Risk
<New endpoints? Schema migration? Removed code? If none — write "Low — pure additive change.">
Always link the issue. Always include a screenshot/GIF if the change is visual.
6 — Cleaning up a noisy branch
When the user has 12 WIP commits to squash before merging:
git log --oneline <base>..HEAD— list what's there.- Identify the logical commits (usually 1–4). Don't squash everything to one — atomic history is more useful than a single squash.
git rebase -i <base>— usepickfor the first commit of each group,squashfor the rest. Rewrite messages on the way through.- After rebase, force-push with lease:
git push --force-with-lease. Never plain--forceon a shared branch.
7 — Safety rails
Before any destructive operation, confirm explicitly with the user:
- Force-push to a branch other than your own personal branch
git reset --hardgit rebaseof commits that have already been reviewedgit pushtomain/master/production
Patterns and anti-patterns
✅ Do:
- Commit early, commit often, then squash.
- Keep commits buildable individually — bisect needs that to work.
- Sign commits if the repo requires it (
git config commit.gpgsign true). - Use
Co-authored-by:trailers when pairing.
❌ Don't:
- Don't write commit messages that say "fix bug" or "WIP". Future-you will hate present-you.
- Don't
git push --forcewithout--force-with-lease. The lease prevents wiping out someone else's pushed commit. - Don't include unrelated changes in a PR ("while I was here, I also..."). They belong in a separate PR.
- Don't write a PR description that just lists the files changed. The reviewer can see that.
Example invocation
User: "I'm done with the password reset feature. Make a clean commit and open a PR."
git status: 7 files changed, on branchashish/wip.git log --oneline -20: project uses Conventional Commits, subjects in imperative.- Group: 6 files are the feature, 1 is a typo fix in an unrelated component.
- Commit 1:
chore: fix typo in login error message. Commit 2:feat(auth): add password reset endpoint and email flow. - Branch is currently
ashish/wip— rename tofeat/password-reset(git branch -m). - Push:
git push -u origin feat/password-reset. - PR description: 2-paragraph "what" + "why", link to issue #1234, testing checklist (manual: reset email arrives, link works, password updates; automated: unit + e2e covered).
- Open the PR via
gh pr createwith the body above.
See also
code-auditor— run a final review before the PR is openeddoc-craft— for the README/CHANGELOG update that should accompany a featureship-it— to verify the PR's CI is green before merging