Conventional commit format, staging, and message conventions. Use when writing commit messages, staging files, grouping changes, or auto-detecting linked issues.
Conventional commit format, staging, and message conventions. Use when writing commit messages, staging files, grouping changes, or auto-detecting linked issues.
user-invocable
false
allowed-tools
Bash, Read
Git Commit Workflow
When to Use This Skill
Use this skill when...
Use the alternative when...
Designing the conventional-commit message and staging conventions for a repo
Use git-commit to actually create a commit (handles pre-commit hooks, issue detection)
Reviewing how to group changes logically into focused commits
Use git-commit-trailers for BREAKING CHANGE / Co-authored-by trailer rules
Discussing humble, fact-based commit communication style
Use github-issue-autodetect to add Fixes #N / Closes #N links to messages
Authoring feat(scope): subject rules for your codebase
Use github-pr-title to apply the same conventional format to PR titles
Expert guidance for commit message conventions, staging practices, and commit best practices using conventional commits and explicit staging workflows.
For detailed examples, advanced patterns, and best practices, see REFERENCE.md.
Preconditions
Before staging any files — especially for bulk-edit / commit-loop workflows that touch many subdirectories — verify the working tree is yours alone:
Check
Why
How
Coworker check
Another Claude session in the same checkout may have already pre-staged files (git commit -a retry, abandoned staging) that your loop would sweep into the wrong commit. Run this up front, not opportunistically.
SlashCommand → /git:coworker-check
Working tree scoped
Confirm git status --porcelain shows only your edits
git status --porcelain
If /git:coworker-check returns anything other than clear, stop and either move to a fresh worktree (git worktree add ../<repo>-<task>) or ask the user before proceeding. See .claude/rules/agent-coworker-detection.md for the four detection signals.
Core Expertise
Conventional Commits: Standardized format for automation and clarity
Explicit Staging: Always stage files individually with clear visibility
Logical Grouping: Group related changes into focused commits
Communication Style: Humble, factual, concise commit messages
Pre-commit Integration: Run checks before committing
Note: Commits are made on main branch and pushed to remote feature branches for PRs. See git-branch-pr-workflow skill for the main-branch development pattern.
# Feature with scope
git commit -m "feat(auth): implement OAuth2 integration"# Bug fix with body
git commit -m "fix(api): resolve null pointer in user service
Fixed race condition where user object could be null during
concurrent authentication requests."# Breaking change
git commit -m "feat(api)!: migrate to GraphQL endpoints
BREAKING CHANGE: REST endpoints removed in favor of GraphQL.
See migration guide at docs/migration.md"
Commit Message Best Practices
DO:
Use imperative mood ("add feature" not "added feature")
Keep first line under 72 characters
Be concise and factual
ALWAYS reference related issues - every commit should link to relevant issues
Use GitHub closing keywords: Fixes #123, Closes #456, Resolves #789
Use Refs #N for related issues that should not auto-close
Use lowercase for type and scope
Be humble and modest
DON'T:
Use past tense ("added" or "fixed")
Include unnecessary details in subject line
Use vague descriptions ("update stuff", "fix bug")
Omit issue references - always link commits to their context
Use closing keywords (Fixes) when you only mean to reference (Refs)
Pre-Commit Context Gathering (Recommended)
Before committing, gather all context in one command:
# Basic context: status, staged files, diff stats, recent log
bash "${CLAUDE_PLUGIN_ROOT}/skills/git-commit-workflow/scripts/commit-context.sh"# With issue matching: also fetches open GitHub issues for auto-linking
bash "${CLAUDE_PLUGIN_ROOT}/skills/git-commit-workflow/scripts/commit-context.sh" --with-issues
The script outputs: branch info, staged/unstaged status, diff stats, detected scopes, recent commit style, pre-commit config status, and optionally open issues. Use this output to compose the commit message. See scripts/commit-context.sh for details.
Explicit Staging Workflow
Always Stage Files Individually
# Show current status
git status --porcelain
# Stage files one by one for visibility
git add src/auth/login.ts
git add src/auth/oauth.ts
git status # Verify what's staged# Show what will be committed
git diff --cached --stat
git diff --cached # Review actual changes# Commit with conventional message
git commit -m "feat(auth): add OAuth2 support"
Bulk-edit / per-plugin commit loops
When a single change touches many subdirectories (per-plugin, per-package, per-doc) and each needs its own scoped commit for release-please, write a one-shot script rather than chaining commands inline.
Why inline loops fail
Pattern
What blocks it
for d in a b c; do git add "$d/" && git commit -m "..."; done
bash-antipatterns.sh blocks broad staging — sweeps in .env, large binaries, and any coworker session's in-flight files in a shared checkout (see .claude/rules/agent-coworker-detection.md)
Repeating git add <paths>; git commit -m "..." as separate Bash tool calls per plugin
Works, but ~3 tool calls × N plugins becomes hundreds of round-trips for a 40-plugin sweep
Canonical recipe
Write the loop to /tmp/commit-loop-<slug>.sh, then run it in one Bash call. The hook treats the file as a script, not a chain — index-modifying commands are sequential within bash, not racing through separate tool invocations.
#!/bin/bash# /tmp/commit-loop-trim-descriptions.shset -uo pipefail
cd"$REPO_ROOT" || exit 1
for p in plugin-a plugin-b plugin-c; do# Skip plugins with nothing staged or modified inside them
[ -z "$(git status --porcelain "$p/")" ] && continue
git add "$p/skills/"# explicit path, never -A or .
git commit -m "docs($p): trim skill descriptions for listing budget"done
Invoke once:
bash /tmp/commit-loop-trim-descriptions.sh
Each iteration runs pre-commit hooks and produces a clean per-plugin commit. Use ; or newlines (not &&) between git add and git commit inside the script.
Failure recovery
If the loop aborts mid-way (a pre-commit hook fails on plugin K of N), the commits for plugins 1..K-1 have already landed — they are not rolled back. Recovery rules:
Situation
Action
Pre-commit hook caught a real issue in plugin K
Fix the issue, re-run the script — the [ -z ... ] && continue guard skips plugins with no remaining changes
Script re-run picks up plugin K's leftover staged paths
Good — the unstaged-or-staged check via git status --porcelain "$p/" catches both
You want to skip plugin K and continue
Edit the script to remove plugin K from the list, re-run
Do not re-stage paths that already committed cleanly; git status is the source of truth for what's left.
ALWAYS use HEREDOC directly in git commit.
git commit -m "$(cat <<'EOF'
feat(auth): add OAuth2 support
Implements token refresh and secure storage.
Fixes #123
EOF
)"
Communication Style
Humble, Fact-Based Messages
# Good: Concise, factual, modest
git commit -m "fix(auth): handle edge case in token refresh"
git commit -m "feat(api): add pagination support
Implements cursor-based pagination for list endpoints.
Includes tests and documentation."
Focus on facts: What changed, Why it changed (if non-obvious), and Impact (breaking changes).
Issue Reference Summary
Scenario
Pattern
Example
Bug fix resolving issue
Fixes #N
Fixes #123
Feature completing issue
Closes #N
Closes #456
Related but not completing
Refs #N
Refs #789
Cross-repository
Fixes owner/repo#N
Fixes org/lib#42
Multiple issues
Repeat keyword
Fixes #1, fixes #2
Best Practices
Commit Frequency
Commit early and often: Small, focused commits
One logical change per commit: Easier to review and revert
Keep commits atomic: Each commit should be a complete, working state
Commit Message Length
# Subject line: <= 72 characters
feat(auth): add OAuth2 support
# Body: <= 72 characters per line (wrap)# Use blank line between subject and body