Agent skill

git-workflow-enforcer

Enforce git commits after every phase and task to enable rollback and prevent lost work. Auto-trigger when completing phases, tasks, or when detecting uncommitted changes. Auto-commit with Conventional Commits format. Verify branch safety, check for merge conflicts, enforce clean working tree. Block completion if changes not committed.

Stars 163
Forks 31

Install this agent skill to your Project

npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/git-workflow-enforcer

SKILL.md

<quick_start> <auto_commit_workflow> Automatic commit generation when changes detected:

  1. Detect uncommitted changes: Run git status --porcelain
  2. Classify change type: Phase completion, task completion, or file modification
  3. Generate commit message: Use Conventional Commits format based on context
  4. Validate safety: Check branch, merge conflicts, commit message format
  5. Execute commit: Stage files and commit with generated message
  6. Provide feedback: Show commit hash and rollback command

Example:

Context: Task T001 completed

❌ UNCOMMITTED CHANGES DETECTED
  Modified: api/models/message.py
  Created: api/tests/test_message.py

✅ AUTO-COMMITTING with generated message:
  feat(green): T001 implement Message model to pass test

  Implementation: SQLAlchemy model with validation
  Tests: 26/26 passing
  Coverage: 93% (+1%)

✅ COMMITTED: abc123f
  Rollback: git revert abc123f

</auto_commit_workflow>

<trigger_patterns> Auto-invoke when detecting:

Phase completion markers:

  • "Phase N complete"
  • "/specify complete", "/plan complete", "/tasks complete"
  • "analysis complete", "optimization complete"
  • Phase command finishing

Task completion markers:

  • "T### complete", "task ### done"
  • "task-tracker mark-done" command
  • "mark task complete"

Change detection:

  • git status --porcelain returns non-empty
  • Files created/modified/deleted
  • Working tree dirty before phase transition </trigger_patterns>

<commit_message_generation> Conventional Commits format:

<type>(<scope>): <subject>

[optional body]

[optional footer]

Auto-detection logic:

Context Type Scope Subject Template
Phase 0 docs spec create specification for {feature}
Phase 0.5 docs clarify resolve {n} clarifications for {feature}
Phase 1 docs plan create implementation plan for {feature}
Phase 2 docs tasks create task breakdown for {feature} ({n} tasks)
Phase 3 docs analyze create cross-artifact analysis for {feature}
Phase 4 (RED) test red {taskId} write failing test for {description}
Phase 4 (GREEN) feat green {taskId} implement {description} to pass test
Phase 4 (REFACTOR) refactor - {taskId} improve {description}
Phase 5 docs optimize complete optimization review for {feature}
Phase 6 docs preview create release notes for {feature} v{version}

Body generation:

  • Phase commits: Include metrics (task count, criteria count, etc.)
  • Task commits: Include evidence (tests, coverage, commit hash)
  • Fix commits: Include root cause and solution

See references/commit-templates.md for complete templates. </commit_message_generation> </quick_start>

Check for uncommitted changes when:

  • Phase command completes
  • task-tracker mark-done-with-notes called
  • User mentions "commit", "save progress", etc.
bash
# Check for uncommitted changes
git status --porcelain

# If non-empty output → uncommitted changes exist

</detection_phase>

<classification_phase> 2. Classify Change Type and Extract Context

Phase completion:

  • Extract phase name from workflow state or command
  • Extract feature slug from current directory
  • Get artifact file paths (spec.md, plan.md, etc.)

Task completion:

  • Extract TaskId from task-tracker parameters or conversation
  • Extract task description from tasks.md
  • Get phase marker ([RED], [GREEN], [REFACTOR])
  • Extract evidence (tests, coverage) from completion context

File modification:

  • Analyze changed files to infer purpose
  • Check git log for recent commit patterns
  • Default to "chore" type if unclear </classification_phase>

<validation_phase> 3. Validate Safety Before Committing

Check 1: Branch safety

bash
CURRENT_BRANCH=$(git branch --show-current)

if [[ "$CURRENT_BRANCH" =~ ^(main|master)$ ]]; then
  ❌ BLOCKED: Direct commits to main/master not allowed
  Recommendation: git checkout -b feat/{feature-slug}
  Exit code: 1
fi

if [[ ! "$CURRENT_BRANCH" =~ ^(feat|feature|bugfix|fix|hotfix|chore)/ ]]; then
  ⚠️ WARNING: Branch name doesn't follow convention
  Expected: feat/*, bugfix/*, hotfix/*, chore/*
  Current: $CURRENT_BRANCH
  Proceed? (auto-yes in non-interactive mode)
fi

Check 2: Merge conflicts

bash
# Check for conflict markers
if grep -r "<<<<<<<" . --exclude-dir=.git; then
  ❌ BLOCKED: Unresolved merge conflicts detected
  Resolve conflicts before committing
  Exit code: 1
fi

# Check git status for conflicts
if git status | grep -q "both modified"; then
  ❌ BLOCKED: Merge conflicts in git status
  Run: git status
  Exit code: 1
fi

Check 3: Remote tracking

bash
# Check if branch has upstream
if ! git rev-parse --abbrev-ref @{upstream} &>/dev/null; then
  ⚠️ WARNING: Branch has no upstream tracking
  Recommendation: git push -u origin $(git branch --show-current)
  Continue without upstream? (auto-yes)
fi

Check 4: Commit message format

bash
# Validate Conventional Commits format
COMMIT_MSG="$1"

# Check format: type(scope): subject
if ! [[ "$COMMIT_MSG" =~ ^(feat|fix|docs|test|refactor|perf|chore|ci|build|revert)(\([a-z0-9-]+\))?: ]]; then
  ❌ INVALID: Commit message doesn't follow Conventional Commits
  Expected: type(scope): subject
  Got: $COMMIT_MSG

  Auto-fix? (yes)
  → Prepend "chore: " to message
fi

# Check subject length (<50 chars recommended)
SUBJECT=$(echo "$COMMIT_MSG" | head -1)
if [[ ${#SUBJECT} -gt 72 ]]; then
  ⚠️ WARNING: Subject line too long (${#SUBJECT} > 72 chars)
  Recommendation: Keep under 50 chars for readability
fi

See references/validation-rules.md for complete validation logic. </validation_phase>

<commit_generation_phase> 4. Generate and Execute Commit

Stage files:

bash
# Get list of changed files
CHANGED_FILES=$(git status --porcelain | awk '{print $2}')

# Stage all changed files (auto-add for convenience)
git add $CHANGED_FILES

# Or stage all (if in feature directory)
git add specs/$FEATURE_SLUG/

Generate commit message:

bash
# Use template based on context
if [[ "$CONTEXT" == "phase_complete" ]]; then
  TYPE="docs"
  SCOPE="$PHASE_NAME"
  SUBJECT="create $ARTIFACTS for $FEATURE_SLUG"

  BODY="- Artifacts: $(echo $ARTIFACTS | tr '\n' ', ')
- Phase: $PHASE_NAME
- Feature: $FEATURE_SLUG"

elif [[ "$CONTEXT" == "task_complete" ]]; then
  # Extract from tasks.md
  PHASE_MARKER=$(grep "$TASK_ID" tasks.md | grep -oP '\[([A-Z]+)\]' | tr -d '[]')

  if [[ "$PHASE_MARKER" == "RED" ]]; then
    TYPE="test"
    SCOPE="red"
  elif [[ "$PHASE_MARKER" == "GREEN" ]]; then
    TYPE="feat"
    SCOPE="green"
  elif [[ "$PHASE_MARKER" == "REFACTOR" ]]; then
    TYPE="refactor"
    SCOPE=""
  fi

  SUBJECT="$TASK_ID $(extract_task_description)"

  BODY="Implementation: $NOTES
Tests: $EVIDENCE
Coverage: $COVERAGE"
fi

# Construct full message
COMMIT_MESSAGE="${TYPE}(${SCOPE}): ${SUBJECT}

${BODY}"

Execute commit:

bash
git commit -m "$(cat <<EOF
$COMMIT_MESSAGE
EOF
)"

COMMIT_HASH=$(git rev-parse --short HEAD)

echo "✅ COMMITTED: $COMMIT_HASH"
echo "  Rollback: git revert $COMMIT_HASH"

See references/auto-commit-logic.md for detailed generation rules. </commit_generation_phase>

<verification_phase> 5. Verify and Provide Feedback

Verify commit succeeded:

bash
# Check that working tree is now clean
if [ -n "$(git status --porcelain)" ]; then
  ⚠️ WARNING: Working tree still dirty after commit
  Uncommitted files: $(git status --short)
  Manual review needed
fi

# Get commit details
COMMIT_HASH=$(git rev-parse --short HEAD)
COMMIT_MSG=$(git log -1 --pretty=%B)
COMMIT_TIME=$(git log -1 --format=%ar)
CHANGED_FILES=$(git diff-tree --no-commit-id --name-only -r HEAD | wc -l)

Provide feedback:

markdown
✅ **AUTO-COMMIT SUCCESSFUL**

**Commit:** $COMMIT_HASH ($COMMIT_TIME)
**Message:** $COMMIT_MSG
**Files:** $CHANGED_FILES changed
**Branch:** $(git branch --show-current)

**Working tree:** Clean
**Rollback:** git revert $COMMIT_HASH
**Push:** git push

Check for unpushed commits:

bash
UNPUSHED=$(git log @{u}.. --oneline 2>/dev/null | wc -l)

if [[ $UNPUSHED -gt 0 ]]; then
  ⚠️ **REMINDER: Unpushed Commits**

  You have $UNPUSHED unpushed commit(s) on this branch.

  Push to backup:
  git push
fi

</verification_phase>

<safety_checks> Blocking checks (prevent commit):

  • ❌ On main/master branch (unless deployment phase)
  • ❌ Unresolved merge conflicts
  • ❌ Invalid commit message format (auto-fixable with prompt)

Warning checks (allow but warn):

  • ⚠️ Branch name doesn't follow conventions
  • ⚠️ No upstream tracking configured
  • ⚠️ Commit subject line >50 chars
  • ⚠️ Unpushed commits exist

Auto-fix attempts:

  • Branch: Suggest git checkout -b feat/{slug}
  • Message format: Prepend "chore: " if type missing
  • Upstream: Suggest git push -u origin {branch}

See references/safety-checks.md for complete check logic. </safety_checks>

<anti_patterns> Avoid these mistakes:

1. Bundling multiple phases in one commit

bash
❌ BAD:
git commit -m "complete spec, plan, and tasks"

✅ GOOD:
git commit -m "docs(spec): create specification for user-messaging"
git commit -m "docs(plan): create implementation plan for user-messaging"
git commit -m "docs(tasks): create task breakdown for user-messaging"

2. Committing to main/master directly

bash
❌ BAD:
(on main) git commit -m "feat: add feature"

✅ GOOD:
git checkout -b feat/user-messaging
git commit -m "feat: add message model"

3. Vague commit messages

bash
❌ BAD:
git commit -m "fixes"
git commit -m "updates"
git commit -m "WIP"

✅ GOOD:
git commit -m "fix(api): correct message validation logic"
git commit -m "refactor: extract MessageService from controller"

4. Skipping commits between tasks

bash
❌ BAD:
# Implement T001, T002, T003
git commit -m "implement all tasks"

✅ GOOD:
# Implement T001
git commit -m "feat(green): T001 implement Message model"
# Implement T002
git commit -m "feat(green): T002 implement MessageService"
# Implement T003
git commit -m "feat(green): T003 add /messages endpoint"

5. Not checking for conflicts before commit

bash
❌ BAD:
git commit -m "fix: update model"
# Later: ❌ Push rejected, conflicts with remote

✅ GOOD:
git fetch
git merge origin/main
# Resolve any conflicts
git commit -m "fix: update model after merge"

</anti_patterns>

<success_criteria> Git workflow enforcement working when:

  • ✓ Uncommitted changes automatically committed after phase/task completion
  • ✓ Commit messages follow Conventional Commits format
  • ✓ Commits blocked on main/master (redirected to feature branch)
  • ✓ Merge conflicts detected and block commit
  • ✓ Branch naming conventions validated
  • ✓ Unpushed commits detected and warned
  • ✓ Working tree always clean between phases
  • ✓ Every task has dedicated commit with hash in NOTES.md
  • ✓ Rollback points available for every phase and task
  • ✓ Commit subject lines concise (<50 chars recommended)

Safety checks passing when:

  • Protected branches (main/master) have no direct commits
  • All commits follow type(scope): subject format
  • No unresolved merge conflict markers in codebase
  • Branches have upstream tracking configured
  • Clear rollback procedures available </success_criteria>

<reference_guides> For detailed templates, validation logic, and commit examples:

Didn't find tool you were looking for?

Be as detailed as possible for better results