Smart git commit
Workflow
Commit what has already changed: grouping and staging are the only edits this skill makes. Don't fix lint, reformat, or touch file contents on the way past. Mention anything the diff surfaces when you report back instead.
Step 1: Inspect changes
Run these in parallel:
git status: see all modified/untracked filesgit diff: see unstaged changesgit diff --cached: see staged changesgit log --oneline -10: learn the repo's commit conventions (scopes, area names)
If there is nothing to commit, say so and stop.
Step 2: Group files by area
Split the changes into atomic commits, one logical change per commit:
- Group by subsystem or top-level directory (e.g.
api/,docs/,.github/workflows/, a service, a model layer). - Keep a change together with its own tests and docs when they belong to the same logical change.
- Take area names from the repo's own conventions (recent commit subjects,
CLAUDE.md,README) rather than inventing new ones. - Bundle files that don't fit neatly with the closest related group.
- Treat already-staged files like any other change: they join their group and are re-staged with it.
Done when every changed file from git status is assigned to exactly one group, and no group spans two unrelated top-level areas.
Step 3: Determine commit type per group
| Type | When to use |
|---|---|
feat |
New feature, model, endpoint, workflow |
fix |
Bug fix, correcting logic, fixing a broken test |
docs |
Documentation-only changes |
refactor |
Restructuring without behavior change |
test |
Adding or updating tests |
chore |
Config, dependency, CI/CD, tooling changes |
style |
Formatting, whitespace, no logic change |
If recent commits use scopes (feat(api): …), use the same scopes; otherwise use bare types. Always produce conventional commits, even when the repo's history doesn't.
Step 4: Commit each group
For each group, stage only its files and commit:
git add <files in group>
git commit -m "$(cat <<'EOF'
type: short imperative description
Optional body if the change needs explanation.
EOF
)"
Message rules:
- Lowercase type prefix
- Imperative mood: "add", "fix", "update"; not "added", "fixes"
- Max ~72 chars on the subject line
- No period at the end of the subject line
- Body only when the why isn't obvious from the subject
- No em dashes anywhere in the message. Use a comma, colon, or parentheses, or rewrite the sentence
Examples:
feat: add customer metrics endpoint
fix: handle null totals in order aggregation
docs: document retry behavior for ingestion jobs
refactor: simplify date-parsing helpers
test: cover empty-cart checkout path
chore: update CI workflow schedule
Step 5: Push to remote
Before pushing, confirm git status is clean, so no changed file was silently dropped from a commit.
After all commits are created:
git push
If the branch has no upstream yet:
git push -u origin HEAD
Run the push outside the sandbox. git push needs network access to reach the remote; a sandboxed shell blocks it, and the failure surfaces as a DNS/connection error that looks like an auth or remote problem. If the push fails with a connection error, suspect the sandbox first.
Close out with the outcome first: the commit subjects and whether the push landed, in a line or two. No per-commit writeup.
Safety rules
- NEVER amend commits that have already been pushed
- NEVER force push to
mainormaster - NEVER skip hooks (
--no-verify) - NEVER commit files that likely contain secrets (
.env, credentials, tokens) - If
git pushis rejected (non-fast-forward), stop and tell the user. Do not force push