
Git Commit Workflow
- 157 installs
- 49 repo stars
- Updated August 4, 2026
- laurigates/claude-plugins
Standardize commit messages, branch naming, and pre-commit checks so agents and teams produce reviewable history during active feature work.
About
Guides Claude through a disciplined git commit workflow: how to stage logical hunks, write conventional messages, tie commits to tasks, and avoid noisy history so pull requests stay small and reviewable across SaaS, API, and CLI repos.
- Conventional commit patterns
- Branch and scope conventions
- Pre-commit hygiene guidance
- Review-ready change grouping
- History that maps to tasks
Git Commit Workflow by the numbers
- 157 all-time installs (skills.sh)
- +4 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #188 of 733 Git & Pull Requests skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/laurigates/claude-plugins --skill git-commit-workflowAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 157 |
|---|---|
| repo stars | ★ 49 |
| Last updated | August 4, 2026 |
| Repository | laurigates/claude-plugins ↗ |
What it does
Standardize commit messages, branch naming, and pre-commit checks so agents and teams produce reviewable history during active feature work.
Files
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.
Conventional Commit Format
Standard Format
type(scope): description
[optional body]
[optional footer(s)]For footer/trailer patterns (Co-authored-by, BREAKING CHANGE, Release-As), see git-commit-trailers skill.
Commit Types
- feat: New feature for the user
- fix: Bug fix for the user
- docs: Documentation changes
- style: Formatting, missing semicolons, etc (no code change)
- refactor: Code restructuring without changing behavior
- test: Adding or updating tests
- chore: Maintenance tasks, dependency updates, linter fixes
- perf: Performance improvements
- ci: CI/CD changes
Examples
# 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 #Nfor 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-issuesThe 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 git add ... && git commit ... — chaining index-modifying git commands risks an index.lock race condition |
git add -A, git add --all, git add . | 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.sh
set -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"
doneInvoke once:
bash /tmp/commit-loop-trim-descriptions.shEach 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 bodyAgentic Optimizations
| Context | Command |
|---|---|
| Pre-commit context | bash "${CLAUDE_PLUGIN_ROOT}/skills/git-commit-workflow/scripts/commit-context.sh" |
| Context + issues | bash "${CLAUDE_PLUGIN_ROOT}/skills/git-commit-workflow/scripts/commit-context.sh" --with-issues |
| Quick status | git status --porcelain |
| Staged diff stats | git diff --cached --stat |
| Recent commit style | git log --format='%s' -5 |
| Open issues for linking | gh issue list --state open --json number,title --limit 30 |
Git Commit Workflow - Reference
Detailed reference material for scope guidelines, staging workflows, issue references, logical change grouping, and troubleshooting.
Scope Guidelines
Common scopes by area:
# Feature areas
feat(auth): login system changes
feat(api): API endpoint changes
feat(ui): user interface changes
feat(db): database schema changes
# Component-specific
fix(header): navigation menu bug
fix(footer): copyright date
fix(sidebar): responsive layout
# Infrastructure
chore(deps): dependency updates
chore(ci): CI/CD configuration
chore(docker): container configurationPre-commit Hook Integration
Pre-commit hooks often AUTO-MODIFY files (formatters, linters with autofix). This is expected behavior.
# 1. Run pre-commit checks
pre-commit run --all-files --show-diff-on-failure
# 2. Check if pre-commit modified any files
git status --porcelain
# M src/file.ts <- Modified by pre-commit (formatting)
# 3. Stage modified tracked files (original + pre-commit modifications)
git add -u
# 4. Verify pre-commit passes now
pre-commit run --all-files # Should exit 0
# 5. Commit with all changes
git commit -m "feat(feature): add feature with formatting fixes"Understanding Pre-commit Exit Codes:
- Exit 0: All hooks passed
- Exit 1: Hook failed OR files were modified (re-stage and re-run)
Pre-commit file modifications are normal - stage them and proceed with the commit.
Logical Change Grouping
Group Related Changes
# Example: Authentication feature with multiple files
# Group 1: Core implementation
git add src/auth/oauth.ts
git add src/auth/token.ts
git commit -m "feat(auth): implement OAuth2 token handling"
# Group 2: Tests
git add tests/auth/oauth.test.ts
git add tests/auth/token.test.ts
git commit -m "test(auth): add OAuth2 integration tests"
# Group 3: Documentation
git add docs/api/authentication.md
git add README.md
git commit -m "docs(auth): document OAuth2 flow"Separate Concerns
# Example: Mixed changes
# Separate linter fixes from feature work
# Group 1: Linter/formatting (chore commit)
git add src/**/*.ts # (only formatting changes)
git add .eslintrc
git commit -m "chore(lint): apply ESLint fixes and update config"
# Group 2: Feature implementation (feat commit)
git add src/feature/implementation.ts
git add tests/feature.test.ts
git commit -m "feat(feature): add new user management feature"Change Classification
Linter/Formatting Group:
- Whitespace-only changes
- Lock files (package-lock.json, Cargo.lock)
- Auto-generated linter configs
- Commit type:
chore
Feature/Fix Groups:
- Implementation code
- Related tests
- Relevant documentation
- Commit type:
feat,fix,refactor
Documentation Group:
- README updates
- API documentation
- User guides
- Commit type:
docs
GitHub Issue References (Autolink Format)
ALWAYS reference related GitHub issues in commit messages. This creates traceability, enables project management, and provides context for future code archaeology.
Autolink Reference Formats
GitHub automatically converts these patterns into clickable links:
| Format | Example | Use Case |
|---|---|---|
#N | #123 | Same repository issue/PR |
GH-N | GH-123 | Alternative same-repo format |
owner/repo#N | octo-org/api#456 | Cross-repository reference |
Closing Keywords
GitHub recognizes 9 keywords to automatically close issues when commits merge to the default branch:
| Keyword | Variants | Effect |
|---|---|---|
| close | close, closes, closed | Closes the issue |
| fix | fix, fixes, fixed | Closes the issue |
| resolve | resolve, resolves, resolved | Closes the issue |
Reference Syntax Patterns
# Close issue in same repository
Fixes #123
Closes #456
Resolves #789
# Close issue in different repository
Fixes octo-org/octo-repo#100
# Close multiple issues (use full keyword for each)
Fixes #123, fixes #456, fixes #789
# Reference without closing (for related context)
Refs #234
Related to #567
See #890Formatting Flexibility
- Case insensitive:
FIXES #123,Fixes #123,fixes #123 - Optional colon:
Fixes: #123,Fixes #123 - Whitespace:
Fixes #123orFixes#123(space optional)
When to Use Each Pattern
| Scenario | Pattern | Example |
|---|---|---|
| Bug fix that resolves an issue | Fixes #N | Fixes #123 |
| Feature that completes an issue | Closes #N | Closes #456 |
| Work related to but not completing issue | Refs #N | Refs #789 |
| Partial progress on larger issue | Refs #N | Refs #101 |
| Breaking change with migration guide | See #N | See #202 |
Important: Keywords only auto-close issues when merged to the default branch. PRs targeting other branches link but don't auto-close.
Automatic Issue Detection
Before creating commits, scan open issues to find matches for staged changes:
# Fetch open issues for matching
gh issue list --state open --json number,title,labels --limit 30
# Get changed files for analysis
git diff --cached --name-onlyMatching Heuristics:
- File paths mentioned in issue body -> High confidence
- Error messages or function names match -> High confidence
- Directory/component matches issue labels -> Medium confidence
- Keyword overlap in issue title -> Medium confidence
See: github-issue-autodetect skill for full detection algorithm and decision tree.
Issue Reference Examples
# Fix with auto-close (single issue)
git commit -m "fix(api): handle timeout
Fixes #123"
# Feature linked to multiple issues
git commit -m "feat(ui): redesign dashboard
Implements designs from #456
Closes #457, closes #458"
# Cross-repository reference
git commit -m "fix(shared): resolve validation bug
Fixes org/shared-lib#42"
# Breaking change with migration reference
git commit -m "feat(api)!: change authentication
BREAKING CHANGE: API key format changed.
See migration guide: #789"
# Reference without closing (use "Refs" or "Related to")
git commit -m "refactor(auth): extract token validation
Refs #234"Workflow Examples
Complete Staging and Commit Flow
# 1. Check current state
git status
# 2. Run pre-commit checks
pre-commit run --all-files
# 3. Stage files explicitly
git add src/feature.ts
git add tests/feature.test.ts
# 4. Review what's staged
git status
git diff --cached --stat
# 5. Commit with conventional message
git commit -m "feat(feature): add new capability
Implements X feature with Y functionality.
Includes unit tests and integration tests.
Closes #123"
# 6. Verify commit
git log -1 --statAmending Commits
# Fix last commit (before pushing)
git add forgotten-file.ts
git commit --amend --no-edit
# Update commit message
git commit --amend -m "feat(auth): improved OAuth2 implementation"Interactive Staging
# Stage parts of a file
git add -p file.ts
# Review hunks and choose:
# y - stage this hunk
# n - do not stage
# s - split into smaller hunks
# e - manually edit hunkTroubleshooting
Accidentally Staged Wrong Files
# Unstage specific file
git restore --staged wrong-file.ts
# Unstage all
git restore --staged .Wrong Commit Message
# Amend last commit message (before push)
git commit --amend -m "corrected message"
# After push (prefer pre-push correction when possible)
git commit --amend -m "corrected message"
git push --force-with-lease origin branch-nameForgot to Add File to Last Commit
# Add file and amend
git add forgotten-file.ts
git commit --amend --no-editNeed to Split Last Commit
# Undo last commit but keep changes staged
git reset --soft HEAD~1
# Unstage all
git restore --staged .
# Stage and commit in groups
git add group1-file.ts
git commit -m "first logical group"
git add group2-file.ts
git commit -m "second logical group"#!/usr/bin/env bash
# Commit Context Gathering Script
# Collects all pre-commit context in a single execution.
# Usage: bash commit-context.sh [--with-issues]
#
# Gathers: status, staged diff stats, recent log, branch info,
# and optionally open GitHub issues for auto-linking.
# Replaces 4-6 individual tool calls with one.
set -uo pipefail
WITH_ISSUES=false
[ "${1:-}" = "--with-issues" ] && WITH_ISSUES=true
echo "=== COMMIT CONTEXT ==="
# Branch info
current_branch=$(git branch --show-current 2>/dev/null || echo "DETACHED")
echo "BRANCH=$current_branch"
# Status summary
echo ""
echo "--- STATUS ---"
git status --porcelain 2>/dev/null | head -30
staged_files=$(git diff --cached --name-only 2>/dev/null)
staged_count=$(echo "$staged_files" | grep -c "." 2>/dev/null || echo "0")
echo ""
echo "STAGED_COUNT=$staged_count"
if [ "$staged_count" -eq 0 ]; then
# Show unstaged files that could be staged
echo ""
echo "--- UNSTAGED CHANGES ---"
git diff --stat 2>/dev/null | tail -5
echo ""
echo "HINT: No files staged. Use 'git add <file>' to stage changes."
fi
# Staged diff stats
if [ "$staged_count" -gt 0 ]; then
echo ""
echo "--- STAGED DIFF STATS ---"
git diff --cached --stat 2>/dev/null
echo ""
echo "--- STAGED FILES ---"
while IFS= read -r line; do printf ' %s\n' "$line"; done <<< "$staged_files"
# Detect change types for commit message suggestion
echo ""
echo "--- CHANGE ANALYSIS ---"
new_files=$(git diff --cached --name-only --diff-filter=A 2>/dev/null | wc -l)
modified_files=$(git diff --cached --name-only --diff-filter=M 2>/dev/null | wc -l)
deleted_files=$(git diff --cached --name-only --diff-filter=D 2>/dev/null | wc -l)
renamed_files=$(git diff --cached --name-only --diff-filter=R 2>/dev/null | wc -l)
echo "ADDED=$new_files"
echo "MODIFIED=$modified_files"
echo "DELETED=$deleted_files"
echo "RENAMED=$renamed_files"
# Detect common scopes from file paths
echo ""
echo "--- DETECTED SCOPES ---"
echo "$staged_files" | sed 's|/[^/]*$||' | sort -u | head -5 | sed 's/^/ /'
fi
# Recent commits (for style matching)
echo ""
echo "--- RECENT COMMITS (style reference) ---"
git log --oneline -n 8 2>/dev/null | sed 's/^/ /'
# Conventional commit detection
conv_count=$(git log --oneline -n 10 2>/dev/null | grep -cE "^[a-f0-9]+ (feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\(.+\))?:" || echo "0")
echo ""
echo "CONVENTIONAL_STYLE=$([ "$conv_count" -ge 5 ] && echo "yes" || echo "mixed")"
# Pre-commit hook detection
echo ""
echo "--- PRE-COMMIT ---"
if [ -f ".pre-commit-config.yaml" ]; then
echo "CONFIGURED=true"
if [ -f ".git/hooks/pre-commit" ] && grep -q "pre-commit" .git/hooks/pre-commit 2>/dev/null; then
echo "INSTALLED=true"
else
echo "INSTALLED=false"
fi
else
echo "CONFIGURED=false"
fi
# Open issues (for auto-linking)
if [ "$WITH_ISSUES" = true ]; then
echo ""
echo "--- OPEN ISSUES ---"
if command -v gh >/dev/null 2>&1; then
gh issue list --state open --json number,title,labels --limit 20 2>/dev/null | \
jq -r '.[] | "#\(.number) \(.title) [\(.labels | map(.name) | join(","))]"' 2>/dev/null | \
head -15 | sed 's/^/ /' || echo " (gh auth or repo not available)"
else
echo " (gh CLI not available)"
fi
fi
echo ""
echo "=== CONTEXT COMPLETE ==="