From gitmastery
Create atomic git commits with conventional format. Hooks enforce no wildcards, no AI footers, conventional format. Presents each commit for user review via AskUserQuestion before execution.
npx claudepluginhub jugrajsingh/skillgarden --plugin gitmasteryThis skill is limited to using the following tools:
Create atomic commits with conventional format. **One commit at a time, user-reviewed.**
Creates isolated Git worktrees for feature branches with prioritized directory selection, gitignore safety checks, auto project setup for Node/Python/Rust/Go, and baseline verification.
Executes implementation plans in current session by dispatching fresh subagents per independent task, with two-stage reviews: spec compliance then code quality.
Dispatches parallel agents to independently tackle 2+ tasks like separate test failures or subsystems without shared state or dependencies.
Create atomic commits with conventional format. One commit at a time, user-reviewed.
Hooks auto-validate all git commands — no manual checks needed:
| Command | Hook Validates |
|---|---|
| git add | Rejects wildcards, directories (including submodules), -A, --all |
| git commit | Validates conventional format, rejects AI footers |
| git update-index | Not hooked — use for submodule pointer updates |
&& — each git add, pre-commit, git commit is a separate Bash callpwd
git status --short
git diff --cached --name-only
If files staged: git reset HEAD to unstage first.
git diff --stat
git log -3 --oneline
Separate commits for:
Atomic = one logical change, buildable, reversible.
a) Present via AskUserQuestion — user MUST approve before execution:
AskUserQuestion(
questions=[{
"question": """Ready to create commit 1/N?
**Commit Message:**
feat(auth): add JWT refresh endpoint
Implements automatic token refresh 5 minutes before expiry.
Tokens are refreshed in background to avoid request delays.
**Files:**
- src/auth.py (+45/-3)
- src/tokens.py (+30)
**Stats:** 2 files, +75/-3
**Commands:**
1. git add src/auth.py src/tokens.py
2. pre-commit run
3. git commit -m "feat(auth): add JWT refresh endpoint
Implements automatic token refresh 5 minutes before expiry.
Tokens are refreshed in background to avoid request delays."
Proceed with this commit?""",
"header": "Commit 1/N",
"options": [
{"label": "Execute", "description": "Stage files, run hooks, and commit"},
{"label": "Skip", "description": "Skip this commit"}
],
"multiSelect": false
}]
)
CRITICAL: The commit body shown in "Commit Message" MUST appear in the git commit command too. Do NOT put explanation only in the dialog.
b) If user selects "Execute", run commands ONE AT A TIME:
# Step 1: Stage (hook validates — no wildcards/directories)
git add src/auth.py src/tokens.py
# Step 2: Pre-commit hooks
pre-commit run
# Step 3: Commit ONLY if hooks pass (exit code 0)
git commit -m "feat(auth): add JWT refresh endpoint
Implements automatic token refresh 5 minutes before expiry.
Tokens are refreshed in background to avoid request delays."
NEVER batch these commands — run each, wait for result, then proceed.
When pre-commit fails, follow this priority order — always prefer autofix tools over manual edits:
pre-commit fails
→ hooks auto-fixed files? → re-stage, retry
→ lint errors remain? → run autofix CLI tools
→ still failing? → agent edits code
→ still failing? → ask user
These hooks modify files automatically. Just re-stage and retry (max 5 retries):
git add file1.py file2.py # Re-stage auto-fixed files
pre-commit run # Retry
When hooks report lint errors but don't auto-fix them, run the tool's autofix command before attempting manual edits:
| Hook | Autofix Command | What It Fixes |
|---|---|---|
| ruff | ruff check --fix <files> | Safe fixes (F841, RUF022, I001, etc.) |
| ruff | ruff check --fix --unsafe-fixes <files> | Unsafe fixes (E402, etc.) — use when safe didn't resolve |
| codespell | codespell --write-changes <files> | Typos in code/comments |
Workflow (separate Bash calls):
# Run safe fixes first
ruff check --fix file1.py file2.py
# If errors remain, try unsafe fixes
ruff check --fix --unsafe-fixes file1.py file2.py
# Re-stage and retry
git add file1.py file2.py
pre-commit run
IMPORTANT: Only pass the specific failing files to autofix commands, not the entire repo.
When autofix tools can't resolve the error (e.g., actual logic issues, bandit findings), the agent fixes the code directly:
from e to bare re-raises--unsafe-fixes: Move imports to top of file manuallyThen re-stage and retry.
If none of the above resolves it, present via AskUserQuestion:
AskUserQuestion(
questions=[{
"question": """Pre-commit hook failed — manual fix required:
**Hook:** {hook_name}
**File:** {file}:{line}
**Error:** {error_message}
How would you like to proceed?""",
"header": "Hook Failed",
"options": [
{"label": "Fix manually", "description": "I'll fix the code, then retry"},
{"label": "Skip commit", "description": "Skip this commit entirely"}
],
"multiSelect": false
}]
)
Pre-commit stashes unstaged changes before running hooks. If mypy is configured with pass_filenames: false and always_run: true, it scans the entire project against this stashed (incomplete) snapshot — unstaged files vanish, breaking imports.
Fix: Configure the mypy hook with pass_filenames: true (no always_run). This way mypy only checks the staged files, not the whole project. The pysmith pre-commit template already uses this pattern.
# CORRECT — checks only staged files, no stash conflict
- id: mypy
entry: uv run mypy
pass_filenames: true
# WRONG — scans everything against stashed snapshot
- id: mypy
entry: uv run mypy .
pass_filenames: false
always_run: true
If you encounter this in an existing project, fix the .pre-commit-config.yaml rather than working around it with file moves or staging tricks.
The git add hook blocks directories — including submodules. Use git update-index to stage submodule pointer changes instead of git add.
Detection: Look for these patterns in git status:
modified: sub (new commits) — submodule has commits, pointer needs updatingmodified: sub (modified content) — submodule has uncommitted changesmodified: sub (new commits, modified content) — bothIf submodule has modified content, commit inside first:
cd submodule
pwd # Verify location
git status
git add file.py
pre-commit run
git commit -m "feat: change description"
cd ..
pwd # Verify back in root
Then update the submodule pointer in root repo:
# Get the commit hash the submodule now points to
git -C submodule rev-parse HEAD
# Stage the pointer update (160000 = gitlink mode)
# Use --add if submodule is new to the index, omit for existing
git update-index --add --cacheinfo "160000,{HASH},submodule"
git commit -m "chore(submodule): update reference"
Why update-index instead of git add:
git add submodule triggers the directory block hookgit update-index --cacheinfo 160000 directly stages the gitlink pointerguard.sh only watches git add and git commit — update-index passes throughCRITICAL: Never chain cd with other commands. Run cd alone, wait for response, then pwd to verify, then proceed.
## Commits Created
1. `abc1234` feat(auth): add JWT refresh endpoint
- 2 files, +75/-3
- Pre-commit: Passed
2. `def5678` test(auth): add refresh token tests
- 1 file, +120
- Pre-commit: Passed (2 retries)
Total: 2 commits | 3 files | +195/-3
NEVER add AI footers — no "Co-Authored-By: Claude", no "Generated by AI". The hook will block them, but don't generate them in the first place.
<type>(<scope>): <subject>
<body - explain what and why, wrap at 72 chars>
<footer - BREAKING CHANGE: or Fixes #123>
| Part | Rule |
|---|---|
| Subject | Imperative, lowercase, no period, <=50 chars |
| Body | Include for most commits, wrap at 72 chars |
| Footer | BREAKING CHANGE: or issue refs (Fixes #123) |
Types: feat, fix, docs, style, refactor, test, chore, perf, ci, build
# WRONG: Chained commands
git add file.py && pre-commit run && git commit -m "msg"
# WRONG: Wildcards / directories
git add *.py
git add src/
# WRONG: AI footer
git commit -m "feat: add feature
Co-Authored-By: Claude <noreply@anthropic.com>"
# WRONG: Chained cd
cd submodule && git status
# WRONG: git add for submodule (hook blocks directories)
git add esalchemy
# RIGHT: update-index for submodule pointer (--add for new submodules)
git update-index --add --cacheinfo "160000,abc123,esalchemy"
# WRONG: Body only in dialog, not in commit
git commit -m "feat: add feature" # Missing body that was shown in AskUserQuestion