
Commit
- 37 installs
- 213 repo stars
- Updated August 4, 2026
- yonatangross/skillforge-claude-plugin
Helps with git & pull requests tasks.
About
commit is a Claude Code skill for git & pull requests. It helps solo builders move faster with AI-assisted coding.
- commit
- Git & Pull Requests
- AI-coding skill
Commit by the numbers
- 37 all-time installs (skills.sh)
- Ranked #332 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/yonatangross/skillforge-claude-plugin --skill commitAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 37 |
|---|---|
| repo stars | ★ 213 |
| Last updated | August 4, 2026 |
| Repository | yonatangross/skillforge-claude-plugin ↗ |
What it does
Helps with git & pull requests tasks.
Files
Smart Commit
Simple, validated commit creation. Run checks locally, no agents needed for standard commits.
Note: If disableSkillShellExecution is enabled (CC 2.1.91), the git repository check won't run. This skill requires a git repository.Quick Start
/ork:commit
/ork:commit fix typo in auth moduleArgument Resolution
COMMIT_MSG = "$ARGUMENTS" # Optional commit message, e.g., "fix typo in auth module"
# If provided, use as commit message. If empty, generate from staged changes.
# $ARGUMENTS[0] is the first token (CC 2.1.59 indexed access)STEP 0: Choose Commit Mode (AskUserQuestion — M118 #1465)
Default is "new commit", but voice-flow needs explicit choice when amend / push / stash is wanted:
# Skip when a flag in the invocation makes the mode unambiguous:
# /ork:commit --amend → skip, mode=amend
# /ork:commit --push → skip, mode=new+push
# /ork:commit --stash → skip, mode=stash-first
# ORK_COMMIT_DEFAULT_MODE=new (or amend|push|stash) → skip, use env value
#
# Otherwise, ask:
AskUserQuestion(questions=[{
"question": "How should this commit land?",
"header": "Commit mode",
"options": [
{"label": "New commit (default)", "description": "Create a new commit, leave HEAD intact"},
{"label": "Amend HEAD", "description": "Fold staged changes into the last commit (LOCAL ONLY — refuses if HEAD is published)"},
{"label": "New commit + push", "description": "Commit then `git push` (refuses on protected branches)"},
{"label": "Stash first", "description": "Stash unrelated working-tree changes, then commit only what was already staged"}
]
}])Mode-specific guards:
- Amend HEAD — verify HEAD is not on origin (
git rev-list HEAD..origin/<branch>empty); if it is published, refuse and recommend "New commit" instead. - New commit + push — re-check the protected-branch rule from Phase 1 before pushing; if HEAD's branch is
main/master/dev, abort. - Stash first —
git stash push -k -m "ork:commit autostash"(keep-index), commit, thengit stash popafter push success.
Workflow
Phase 1: Pre-Commit Safety Check
# CRITICAL: Verify we're not on dev/main
BRANCH=$(git branch --show-current)
if [[ "$BRANCH" == "dev" || "$BRANCH" == "main" || "$BRANCH" == "master" ]]; then
echo "STOP! Cannot commit directly to $BRANCH"
echo "Create a feature branch: git checkout -b issue/<number>-<description>"
exit 1
fiPhase 2: Run Validation Locally
Run every check that CI runs:
# Backend (Python)
poetry run ruff format --check app/
poetry run ruff check app/
poetry run mypy app/
# Frontend (Node.js)
npm run format:check
npm run lint
npm run typecheckFix any failures before proceeding.
Phase 3: Review Changes
git status
git diff --staged # What will be committed
git diff # Unstaged changesPhase 3b: Agent Attribution (automatic)
Before committing, check for the branch activity ledger at .claude/agents/activity/{branch}.jsonl. If it exists and has entries since the last commit, include them in the commit message:
1. Read .claude/agents/activity/{branch}.jsonl (one JSON object per line) 2. Filter entries where ts is after the last commit timestamp (git log -1 --format=%cI) 3. Skip agents with duration_ms < 5000 (advisory-only agents go in PR, not commits) 4. Add an "Agents Involved:" section between the commit body and the Co-Authored-By trailer 5. Add per-agent Co-Authored-By trailers: Co-Authored-By: ork:{agent} <noreply@orchestkit.dev>
If the ledger doesn't exist or is empty, skip this step — commit normally.
Phase 4: Stage and Commit
CC 2.1.113 idiom: Multi-line Bash with leading# intent:comments now shows the full command in the transcript — prefix complex scripts with a one-line intent comment so future readers (and/recapscans) can grep the transcript for what happened without re-reading the diff.
# intent: stage the hook change + its test + built artifacts
# Stage files
git add <files>
# Or all: git add .
# Commit with conventional format (with agent attribution if ledger exists)
git commit -m "<type>(#<issue>): <brief description>
- [Change 1]
- [Change 2]
Agents Involved:
backend-system-architect — API design + data models (2m14s)
security-auditor — Dependency audit (0m42s)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: ork:backend-system-architect <noreply@orchestkit.dev>
Co-Authored-By: ork:security-auditor <noreply@orchestkit.dev>"
# Verify
git log -1 --statHandoff File
After successful commit, write handoff:
Write(".claude/chain/committed.json", JSON.stringify({
"phase": "commit", "sha": "<commit-sha>",
"message": "<commit-message>", "branch": "<branch>",
"files": [<staged-files>]
}))Commit Types
| Type | Use For |
|---|---|
feat | New feature |
fix | Bug fix |
refactor | Code improvement |
docs | Documentation |
test | Tests only |
chore | Build/deps/CI |
Quick Rules
1. Run validation locally - Don't spawn agents to run lint/test 2. NO file creation - Don't create MD files or documentation 3. One logical change per commit - Keep commits focused 4. Reference issues - Use #123 format in commit message 5. Subject line < 72 chars - Keep it concise
Quick Commit
For trivial changes (typos, single-line fixes):
git add . && git commit -m "fix(#123): Fix typo in error message
Co-Authored-By: Claude <noreply@anthropic.com>"Verification Gate
Before committing, apply the 5-step gate: Read("${CLAUDE_PLUGIN_ROOT}/skills/shared/rules/verification-gate.md"). Run tests fresh. Read the output. Only commit if tests pass. "Should be fine" is not evidence.
Related Skills
ork:create-pr: Create pull requests from commitsork:review-pr: Review changes before committingork:fix-issue: Fix issues and commit the fixesork:issue-progress-tracking: Auto-updates GitHub issues with commit progress
Rules
Each category has individual rule files in rules/ loaded on-demand:
| Category | Rule | Impact | Key Pattern |
|---|---|---|---|
| Atomic Commits | ${CLAUDE_SKILL_DIR}/rules/atomic-commit.md | CRITICAL | One logical change per commit, atomicity test |
| Branch Protection | ${CLAUDE_SKILL_DIR}/rules/branch-protection.md | CRITICAL | Protected branches, required PR workflow |
| Commit Splitting | ${CLAUDE_SKILL_DIR}/rules/commit-splitting.md | HIGH | git add -p, interactive staging, separation strategies |
| Conventional Format | ${CLAUDE_SKILL_DIR}/rules/conventional-format.md | HIGH | type(scope): description, breaking changes |
| History Hygiene | ${CLAUDE_SKILL_DIR}/rules/history-hygiene.md | HIGH | Squash WIP, fixup commits, clean history |
| Issue Reference | ${CLAUDE_SKILL_DIR}/rules/issue-reference-required.md | HIGH | Reference issue #N in commits on issue branches |
| Merge Strategy | ${CLAUDE_SKILL_DIR}/rules/merge-strategy.md | HIGH | Rebase-first, conflict resolution, force-with-lease |
| Stacked PRs | ${CLAUDE_SKILL_DIR}/rules/stacked-pr-workflow.md | HIGH | Stack planning, PR creation, dependency tracking |
| Stacked PRs | ${CLAUDE_SKILL_DIR}/rules/stacked-pr-rebase.md | HIGH | Rebase management, force-with-lease, retargeting |
Total: 9 rules across 8 categories
References
Load on demand with Read("${CLAUDE_SKILL_DIR}/references/<file>"):
| File | Content |
|---|---|
references/conventional-commits.md | Conventional commits specification |
references/recovery.md | Recovery procedures |
Conventional Commits
Format
<type>(<scope>): <description>
[optional body]
[optional footer(s)]Types
| Type | Description | Bumps |
|---|---|---|
feat | New feature for users | MINOR |
fix | Bug fix for users | PATCH |
docs | Documentation only | - |
style | Formatting, no code change | - |
refactor | Code change, no feature/fix | - |
perf | Performance improvement | PATCH |
test | Adding/fixing tests | - |
chore | Build process, deps | - |
ci | CI configuration | - |
revert | Revert previous commit | - |
Breaking Changes
Add ! after type or BREAKING CHANGE: in footer:
feat!: drop support for Node 14
BREAKING CHANGE: Node 14 is no longer supportedScope Examples
feat(auth): add OAuth2 supportfix(api): handle null responsedocs(readme): update install stepsrefactor(core): extract helper functions
Good Examples
feat(#123): add user profile page
- Create ProfilePage component
- Add profile API endpoint
- Include unit tests
Co-Authored-By: Claude <noreply@anthropic.com>fix(#456): prevent XSS in comment display
Sanitize HTML in user comments before rendering.
Co-Authored-By: Claude <noreply@anthropic.com>Git Recovery
Committed to Wrong Branch
# Save work to new branch
git checkout -b issue/<number>-<description>
# Reset original branch
git checkout dev
git reset --hard origin/dev
# Return to feature branch
git checkout issue/<number>-<description>Undo Last Commit (Keep Changes)
git reset --soft HEAD~1Undo Last Commit (Discard Changes)
git reset --hard HEAD~1Amend Last Commit
# Fix message only
git commit --amend -m "new message"
# Add forgotten files
git add forgotten-file.txt
git commit --amend --no-editRevert Published Commit
git revert <commit-hash>
git pushUnstage Files
git restore --staged <file>Discard Local Changes
# Single file
git restore <file>
# All files
git restore .Rule Categories
1. Atomic Commits (atomic) — CRITICAL — 1 rule
The foundational principle: one logical change per commit. Violations make history unusable for bisect, revert, and review.
atomic-commit.md— What makes a commit atomic, detection heuristics, examples
2. Commit Splitting (splitting) — HIGH — 1 rule
When a commit is too large or mixes concerns, how to split it into atomic units.
commit-splitting.md— Interactive staging, hunk splitting, separation strategies
3. Conventional Format (format) — HIGH — 1 rule
Message format rules that enable automated changelog generation and semantic versioning.
conventional-format.md— Type/scope/description format, breaking changes, co-author attribution
4. Issue Reference (issue-ref) — HIGH — 1 rule
When on an issue branch, commit messages must reference the issue number for GitHub auto-linking.
issue-reference-required.md— When to include #N, branch-based detection, soft enforcement via hook
[Rule Name]
[Brief description — 1-2 sentences.]
Incorrect:
// Bad patternCorrect:
// Good patternKey rules:
- [Rule 1]
- [Rule 2]
- [Rule 3]
Reference: [link]
Atomic Commit Rules
A commit is atomic when it contains exactly ONE logical change that can be understood, reviewed, and reverted independently.
The Atomicity Test
A commit is atomic if ALL of these are true:
[x] Does ONE logical thing
[x] Leaves the codebase in a working state (tests pass)
[x] Commit message doesn't need "and" in the title
[x] Can be reverted independently without breaking other features
[x] A reviewer can understand the full change without external contextDetection Heuristics
Directory Spread — Changes spanning unrelated directories signal mixed concerns:
# ATOMIC: Related files in same domain
src/auth/login.ts
src/auth/login.test.ts
src/auth/types.ts
# NOT ATOMIC: Unrelated directories
src/auth/login.ts ← auth feature
src/billing/invoice.ts ← billing feature
config/webpack.config.js ← build configCommit Type Mixing — A single commit shouldn't mix types:
# NOT ATOMIC: feat + fix in one commit
feat: Add user dashboard
fix: Resolve login timeout ← separate commit
# NOT ATOMIC: feat + chore in one commit
feat: Add API caching
chore: Update eslint config ← separate commitFile Count Threshold — More than 10 staged files warrants inspection. Not always wrong, but should be verified:
# OK: 15 files, all test fixtures for one feature
tests/fixtures/user-*.json (15 files)
# NOT OK: 12 files across 6 unrelated modules"And" Test — If describing the commit requires "and", it's two commits:
# Fails "and" test → split it
"Add user authentication AND fix logging format"
# Passes "and" test → atomic
"Add JWT token validation for login endpoint"Common Atomic Patterns
| Pattern | Files | Why Atomic |
|---|---|---|
| Feature + its tests | feature.ts + feature.test.ts | Tests validate the feature |
| Migration + model update | migration.sql + model.ts | Schema change is one concern |
| Refactor across files | Multiple files, same pattern | One refactoring decision |
| Config change | .env.example + config.ts | One configuration concern |
| Dependency update | package.json + package-lock.json | One dependency decision |
Common Non-Atomic Patterns
| Pattern | Problem | Fix |
|---|---|---|
| Feature + unrelated fix | Two concerns | Two separate commits |
| Code change + formatting | Formatting is noise | Format first, then change |
| Multiple features | Can't revert independently | One commit per feature |
| Feature + config change | Different review concerns | Separate unless config IS the feature |
Incorrect — non-atomic commit mixing concerns:
# Mixed commit spanning unrelated areas
git add src/auth/login.ts \
src/billing/invoice.ts \
config/webpack.config.js
git commit -m "feat: Add login AND fix invoice AND update webpack"
# Three unrelated changes - can't revert independently!Correct — atomic commits with single concerns:
# Commit 1: Auth feature + its tests (related)
git add src/auth/login.ts src/auth/login.test.ts
git commit -m "feat(#123): Add JWT token validation for login endpoint"
# Commit 2: Billing feature + its tests (related)
git add src/billing/invoice.ts src/billing/invoice.test.ts
git commit -m "feat(#124): Add invoice generation service"
# Commit 3: Config change (separate concern)
git add config/webpack.config.js
git commit -m "chore: Update webpack for tree shaking"Key Rules
- One logical change per commit — if you say "and", split it
- Tests belong with the code they test — same commit
- Formatting/linting changes are separate commits
- Database migrations go with the code that uses them
- Never mix feature work with unrelated refactoring
Branch Protection Rules
Protected branches are the deployment pipeline. Never commit or push directly to them.
Protected Branches
| Branch | Purpose | Direct Commit | Force Push |
|---|---|---|---|
main | Production-ready code | BLOCKED | BLOCKED |
master | Legacy production | BLOCKED | BLOCKED |
dev | Integration branch | BLOCKED | BLOCKED |
release/* | Release candidates | BLOCKED | BLOCKED |
Branch Naming Convention
# Issue-linked (preferred)
issue/<number>-<brief-description>
issue/123-add-user-auth
# Type-based (when no issue exists)
feature/<description>
fix/<description>
hotfix/<description>Incorrect — Direct commit to main:
git checkout main
git commit -m "quick fix"
git push origin mainCorrect — Feature branch workflow:
git checkout -b fix/issue-123
git commit -m "fix(#123): Resolve auth bug"
git push -u origin fix/issue-123
gh pr create --base mainKey Rules
- Never commit directly to main, dev, or release branches
- Always use feature branches with descriptive names
- All changes reach protected branches through PRs only
- Force push is only allowed on your own feature branches with
--force-with-lease - Delete feature branches after merge
Commit Splitting Strategies
When you have mixed changes in your working directory, use these strategies to create atomic commits.
Strategy 1: Interactive Staging (git add -p)
Stage changes hunk-by-hunk to separate concerns:
# Stage changes interactively
git add -p
# Options at each hunk:
# y - stage this hunk
# n - skip this hunk
# s - split into smaller hunks (if hunk has gaps)
# e - manually edit the hunk boundaries
# q - quit, leave remaining unstaged
# Review what's staged vs unstaged
git diff --staged # Will be committed
git diff # Won't be committed
# Commit the staged portion
git commit -m "feat(#123): Add user validation"
# Repeat for next logical change
git add -p
git commit -m "fix(#456): Resolve timeout in auth"Strategy 2: File-Based Splitting
When changes are in separate files, stage by file:
# Stage only auth-related files
git add src/auth/login.ts src/auth/login.test.ts
git commit -m "feat(#123): Add login validation"
# Stage only billing-related files
git add src/billing/invoice.ts src/billing/invoice.test.ts
git commit -m "feat(#124): Add invoice generation"Strategy 3: Stash-Based Splitting
For complex mixed changes, use stash to isolate:
# Stash everything
git stash
# Apply and stage only what you need
git stash pop
git add -p # Stage only feature A
git stash # Re-stash the rest
git commit -m "feat: Feature A"
# Recover remaining changes
git stash pop
git add -p # Stage feature B
git commit -m "feat: Feature B"Strategy 4: Pre-Commit Formatting Split
Always format BEFORE making logical changes:
# Step 1: Format first (separate commit)
npx prettier --write src/
git add -A
git commit -m "style: Format files with prettier"
# Step 2: Now make your logical changes
# ... edit files ...
git add -p
git commit -m "feat(#123): Add user dashboard"When to Split
| Signal | Action |
|---|---|
git diff --staged shows > 10 files | Review if all related |
| Commit message needs "and" | Split into separate commits |
| Changes span > 3 unrelated directories | Split by directory/concern |
| Mix of feat + fix + chore | One commit per type |
| Formatting mixed with logic changes | Format first, then logic |
Incorrect — staging everything at once, mixed concerns:
# Staging all files including mixed changes
git add .
git commit -m "feat: Add login and fix billing and update config"
# Unreviewable, can't revert parts!Correct — interactive staging for separate atomic commits:
# Stage auth changes interactively
git add -p src/auth/login.ts
# y - stage login validation hunks
# n - skip other hunks
git add src/auth/login.test.ts
git commit -m "feat(#123): Add login validation"
# Stage billing changes interactively
git add -p src/billing/invoice.ts
git add src/billing/invoice.test.ts
git commit -m "fix(#456): Resolve invoice calculation bug"
# Stage config separately
git add config/webpack.config.js
git commit -m "chore: Update webpack config"Key Rules
- Use
git add -pas the default — stage interactively, notgit add . - Format changes always go in their own commit
- Test files go with the code they test, not in separate commits
- When in doubt, split — smaller commits are always safer
- Each commit should pass tests independently
Conventional Commit Format
All commits must follow the Conventional Commits specification for automated tooling.
Format
<type>(<scope>): <description>
[optional body]
[optional footer]
Co-Authored-By: Claude <noreply@anthropic.com>Types
| Type | When | Bumps |
|---|---|---|
feat | New feature or capability | MINOR |
fix | Bug fix | PATCH |
refactor | Code restructuring, no behavior change | — |
docs | Documentation only | — |
test | Adding or fixing tests | — |
chore | Build, deps, CI, tooling | — |
style | Formatting, whitespace, semicolons | — |
perf | Performance improvement | PATCH |
ci | CI/CD configuration | — |
build | Build system changes | — |
Scope
Optional, identifies the area of change:
# Issue reference (preferred)
feat(#123): Add user authentication
# Module name
fix(auth): Resolve token expiration
# No scope (acceptable for small changes)
chore: Update dependenciesBreaking Changes
Use ! after type/scope OR BREAKING CHANGE: footer:
# With ! marker (bumps MAJOR)
feat(api)!: Change authentication endpoint structure
# With footer
feat(api): Change auth endpoints
BREAKING CHANGE: /api/auth/login now requires email instead of usernameTitle Rules
[x] Imperative mood ("Add feature" not "Added feature")
[x] No period at end
[x] < 72 characters (< 50 preferred)
[x] Lowercase after colon
[x] Meaningful — describes WHY, not just WHATIncorrect:
Fixed the bug. # Past tense, period, no type
feat: stuff # Vague
feat: Add user authentication and fix billing # Two concerns
FEAT: Add Auth # UppercaseCorrect:
feat(#123): Add JWT token validation for login
fix(#456): Resolve race condition in payment processing
refactor: Extract database connection pool to shared moduleBody (Optional)
Use for context that doesn't fit in the title:
git commit -m "$(cat <<'EOF'
feat(#123): Add rate limiting to API endpoints
Applied token bucket algorithm with 100 req/min per user.
Redis-backed for distributed deployments.
Co-Authored-By: Claude <noreply@anthropic.com>
EOF
)"Key Rules
- Type is mandatory — no untyped commits
- Scope with issue number when available (
#123) - Title < 72 chars, imperative mood, no period
- One type per commit — if you need
featANDfix, make two commits - Always include
Co-Authored-Bywhen Claude assists - Breaking changes must use
!orBREAKING CHANGE:footer
History Hygiene Rules
A clean git history makes debugging (bisect), code review, and onboarding dramatically easier.
Before Pushing: Clean Up
# Squash WIP commits before pushing
git rebase -i HEAD~3
# In the editor:
pick abc1234 feat(#123): Add user validation
fixup def5678 WIP: more validation
fixup ghi9012 fix typoFixup Commits (During Development)
git commit --fixup HEAD # Auto-squash into previous
git commit --fixup HEAD~2 # Auto-squash into specific commit
# Before pushing, auto-squash all fixups
git rebase -i --autosquash HEAD~5What to Squash
| Squash | Keep Separate |
|---|---|
| WIP commits | Each logical feature |
| "Fix typo" after feature | Bug fixes (different concern) |
| "Address review feedback" | Refactoring (different intent) |
| Multiple attempts at same thing | Test additions (reviewable unit) |
Incorrect — Dirty WIP history:
abc1234 WIP
def5678 fix
ghi9012 more fixesCorrect — Cleaned history:
git rebase -i --autosquash HEAD~4
# Result: One clean commit
abc1234 feat(#123): Add user validation with edge case handlingKey Rules
- Clean up history before pushing — squash WIP and fixup commits
- Each commit in final history should be meaningful and atomic
- Use
--fixupduring development,--autosquashbefore pushing - Never rewrite published history (commits others have pulled)
Issue Reference Required
When on an issue branch (issue/*, fix/*, feat/*), commit messages MUST reference the issue number using #N format.
Why
- Links commits to issues automatically in GitHub
- Enables automated issue closing via
Closes #NorFixes #N - Provides traceability for code review and auditing
Good Examples
# Issue number in scope
git commit -m "fix(#42): resolve null pointer in auth handler"
# Issue number in body
git commit -m "feat(auth): add OAuth2 support
Implements #42"
# Closing reference
git commit -m "fix(api): validate input length
Closes #42"Bad Examples
# No issue reference on an issue branch
git commit -m "fix: resolve null pointer in auth handler"
# Issue number without # prefix
git commit -m "fix(42): resolve null pointer"When to Apply
- Always when the branch name contains an issue number (e.g.,
issue/42-fix-auth,fix/42-null-pointer) - Recommended for any branch linked to a known GitHub issue
- Skip for branches unrelated to issues (e.g.,
chore/update-deps)
Incorrect — missing issue reference on issue branch:
# On branch: issue/42-fix-auth
# No issue reference - breaks traceability!
git commit -m "fix: resolve null pointer in auth handler"Correct — issue reference in commit message:
# On branch: issue/42-fix-auth
# Issue number in scope
git commit -m "fix(#42): resolve null pointer in auth handler"
# Or in body
git commit -m "fix(auth): resolve null pointer in auth handler
Fixes #42"Soft Rule
This is a soft rule enforced by the issue-reference-checker hook, which nudges the developer to add the reference. The commit will not be blocked if the reference is missing.
Merge Strategy Rules
Use rebase-first workflow to maintain clean, linear history on feature branches.
Decision Table
| Scenario | Strategy | Command |
|---|---|---|
| Update feature branch with main | Rebase | git rebase origin/main |
| Merge PR into main | Squash merge or merge commit | Via GitHub PR |
| Shared feature branch | Merge (preserve history) | git merge origin/main |
Rebase-First Workflow
git fetch origin
git rebase origin/main
# If conflicts: resolve, stage, continue
git add <resolved-files>
git rebase --continue
# If rebase goes wrong
git rebase --abortForce Push Safety
# SAFE: Force push your own feature branch
git push --force-with-lease origin issue/123-feature
# DANGEROUS: Never force push protected branches
git push --force origin main # NEVER DO THISIncorrect — Merge main into feature:
git checkout feature-branch
git merge origin/main # Creates noisy merge commitsCorrect — Rebase onto main:
git checkout feature-branch
git rebase origin/main
git push --force-with-leaseKey Rules
- Rebase feature branches onto main — don't merge main into feature branches
- Use
--force-with-leaseinstead of--forcefor rebased branches - Resolve conflicts during rebase, not with merge commits
- Test after every conflict resolution
Stacked PR Rebase Management
Keep stacked PR branches synchronized after feedback, merges, or base branch changes.
Incorrect — merging main into feature branches:
git checkout feature/auth-service
git merge main # Creates unnecessary merge commitCorrect — rebase after base PR feedback:
# Rebase dependent branches in order:
git checkout feature/auth-service
git rebase feature/auth-base
git push --force-with-lease
git checkout feature/auth-ui
git rebase feature/auth-service
git push --force-with-leaseAfter base PR merges to main:
git checkout main && git pull origin main
# Retarget PR #2 to main
gh pr edit 102 --base main
# Rebase PR #2 on updated main
git checkout feature/auth-service
git rebase main
git push --force-with-leaseKey rules:
- Always rebase, never merge main into feature branches
- Use
--force-with-lease(never--force) to prevent overwriting others' work - Rebase in dependency order: base first, then each dependent branch
- After a base PR merges, retarget the next PR to
mainviagh pr edit
Stacked PR Workflow
Break large features into small, dependent PRs that merge in sequence.
Incorrect — single massive PR:
# One 1500-line PR that takes days to review
git checkout -b feature/auth
gh pr create --title "feat: Add complete auth system"Correct — stacked PRs with clear dependencies:
# PR 1: User model (base) — targets main
git checkout -b feature/auth-base
gh pr create --base main --title "feat(#100): Add User model [1/3]"
# PR 2: Auth service — targets PR 1's branch
git checkout -b feature/auth-service
gh pr create --base feature/auth-base --title "feat(#100): Add auth service [2/3]"
# PR 3: Login UI — targets PR 2's branch
git checkout -b feature/auth-ui
gh pr create --base feature/auth-service --title "feat(#100): Add login UI [3/3]"Key rules:
- Keep each PR under 400 lines for effective review
- Number PRs clearly:
[1/3],[2/3],[3/3] - Each PR should be independently reviewable and leave tests passing
- Use draft PRs for incomplete stack items
- Do not stack more than 4-5 PRs deep
- Never merge out of order
#!/bin/bash
# Generated by OrchestKit Claude Plugin
# Created: 2026-02-14
# Validate Conventional Commit Message
# Checks commit messages against the Conventional Commits specification.
#
# Usage: ./validate-conventional.sh [OPTIONS]
# echo "feat: add login" | ./validate-conventional.sh
# ./validate-conventional.sh --message "feat: add login"
#
# Options:
# --message MSG Commit message to validate (alternative to stdin)
# --help Show this help message
#
# Exit codes:
# 0 = valid conventional commit
# 1 = invalid commit message
# 2 = usage error (no input provided)
set -euo pipefail
# =============================================================================
# CONFIGURATION
# =============================================================================
# Conventional commit types
VALID_TYPES="feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
# Maximum subject line length
MAX_SUBJECT_LENGTH=72
MESSAGE=""
# =============================================================================
# ARGUMENT PARSING
# =============================================================================
while [[ $# -gt 0 ]]; do
case "$1" in
--message)
if [[ -z "${2:-}" ]]; then
echo "Error: --message requires a value" >&2
exit 2
fi
MESSAGE="$2"
shift 2
;;
--help|-h)
echo "Validate Conventional Commit Message"
echo ""
echo "Usage:"
echo " echo \"feat: add login\" | $0"
echo " $0 --message \"feat: add login\""
echo ""
echo "Options:"
echo " --message MSG Commit message to validate"
echo " --help Show this help message"
echo ""
echo "Valid types: ${VALID_TYPES//|/, }"
echo ""
echo "Exit codes:"
echo " 0 = valid conventional commit"
echo " 1 = invalid commit message"
echo " 2 = usage error"
exit 0
;;
*)
echo "Error: Unknown option '$1'. Use --help for usage." >&2
exit 2
;;
esac
done
# Read from stdin if no --message provided
if [[ -z "$MESSAGE" ]]; then
if [[ -t 0 ]]; then
echo "Error: No message provided. Use --message or pipe via stdin." >&2
echo "Run '$0 --help' for usage." >&2
exit 2
fi
MESSAGE=$(cat)
fi
if [[ -z "$MESSAGE" ]]; then
echo "Error: Empty commit message" >&2
exit 1
fi
# =============================================================================
# VALIDATION
# =============================================================================
ERRORS=()
SUBJECT_LINE=$(echo "$MESSAGE" | head -1)
# 1. Check type prefix
if ! echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})(\(.+\))?!?:"; then
ERRORS+=("Missing or invalid type prefix. Valid types: ${VALID_TYPES//|/, }")
fi
# 2. Check colon+space separator
if echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})" && ! echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})(\(.+\))?!?: .+"; then
ERRORS+=("Must have a space after the colon (e.g., 'feat: description')")
fi
# 3. Check subject length
subject_text=$(echo "$SUBJECT_LINE" | sed -E "s/^(${VALID_TYPES})(\([^)]*\))?!?: //")
if [[ ${#SUBJECT_LINE} -gt $MAX_SUBJECT_LENGTH ]]; then
ERRORS+=("Subject line too long (${#SUBJECT_LINE} > ${MAX_SUBJECT_LENGTH} chars)")
fi
# 4. Check for trailing period
if [[ "$SUBJECT_LINE" =~ \.$ ]]; then
ERRORS+=("Subject line should not end with a period")
fi
# 5. Check for uppercase after colon (first letter of description)
if echo "$subject_text" | grep -qE "^[A-Z]"; then
ERRORS+=("Description should start with lowercase letter")
fi
# 6. Check scope format (if present)
if echo "$SUBJECT_LINE" | grep -qE "^(${VALID_TYPES})\("; then
scope=$(echo "$SUBJECT_LINE" | sed -E "s/^(${VALID_TYPES})\(([^)]*)\).*/\2/")
if [[ -z "$scope" ]]; then
ERRORS+=("Empty scope in parentheses")
fi
fi
# 7. Check body format (blank line between subject and body)
line_count=$(echo "$MESSAGE" | wc -l | tr -d ' ')
if [[ "$line_count" -gt 1 ]]; then
second_line=$(echo "$MESSAGE" | sed -n '2p')
if [[ -n "$second_line" ]]; then
ERRORS+=("Must have a blank line between subject and body")
fi
fi
# =============================================================================
# OUTPUT
# =============================================================================
if [[ ${#ERRORS[@]} -eq 0 ]]; then
echo "Valid conventional commit"
exit 0
else
echo "Invalid commit message:"
for err in "${ERRORS[@]}"; do
echo " - $err"
done
exit 1
fi
{
"skill": "commit",
"version": "1.0.0",
"testCases": [
{
"id": "conventional-format",
"rule": "conventional-format",
"query": "Commit my authentication changes with a proper message",
"expectedBehavior": [
"Uses conventional commit format: type(scope): description",
"Includes Co-Authored-By trailer in the commit message footer",
"Keeps subject line under 72 characters for readability",
"References issue number with # prefix"
]
},
{
"id": "atomic-commit",
"rule": "atomic-commit",
"query": "I changed the API and updated the docs, commit everything",
"expectedBehavior": [
"Verifies each commit does ONE logical thing",
"Ensures codebase remains working after commit",
"Commit message does not need 'and' in title",
"Each commit can be reverted independently"
]
},
{
"id": "commit-splitting",
"rule": "commit-splitting",
"query": "I have changes to the database schema and the UI, how should I commit?",
"expectedBehavior": [
"Recommends splitting unrelated changes into separate atomic commits",
"Suggests using git add -p for interactive staging",
"Separates unrelated changes into distinct commits",
"Reviews staged vs unstaged changes with git diff"
]
},
{
"id": "quick-commit",
"rule": "conventional-format",
"query": "Fix a typo in the error message",
"expectedBehavior": [
"Uses quick commit pattern for trivial changes",
"Uses fix type prefix for the conventional commit format",
"Includes Co-Authored-By trailer appended to commit metadata",
"Does not spawn agents for simple changes"
]
},
{
"id": "branch-protection",
"rule": "atomic-commit",
"query": "Commit directly to main branch",
"expectedBehavior": [
"Verifies commit is atomic and does not mix unrelated changes on protected branches",
"Refuses to commit to main or dev branches",
"Suggests creating a feature branch first",
"Uses issue/<number>-<description> branch naming convention for traceability"
]
},
{
"id": "issue-reference-required",
"rule": "issue-reference-required",
"query": "I'm committing code for issue #42 but I keep forgetting to add the issue reference. What's required?",
"expectedBehavior": [
"Requires issue number reference in every commit message using the hash-number prefix format",
"Formats commit as type(#42): description following conventional commit with issue reference",
"Warns that commits without issue references break traceability and auto-close linking",
"Enables automatic issue-to-commit linking for progress tracking and audit trail purposes"
]
}
]
}