Skip to main content
hooksSource-backedReview first Safety Privacy

Git Auto Commit On Stop - Hooks

Automatically commits all changes with a summary when Claude Code session ends.

by JSONbored·added 2025-09-19·
Claude Code
HarnessClaude Code
Trigger:Stop
Review first review before installing

Open the source and read safety notes before installing.

Safety notes

  • Runs automatically at session end and stages all unignored repository changes with git add -A.
  • Creates a local commit when changes are present unless SKIP_AUTO_COMMIT=true is set.
  • Only warns on sensitive-looking filenames and does not block the commit by default.

Privacy notes

  • Reads git status, branch name, staged diff statistics, and changed file names to build the commit message.
  • Can commit newly created or modified local files, including private work, when they are not excluded by .gitignore.
  • Commit metadata uses the locally configured git user name and email.

Schema details

Install type
cli
Reading time
1 min
Difficulty score
0
Troubleshooting
Yes
Breaking changes
No
Runtime and command metadata
Trigger
Stop
Script language
bash
Script body
#!/usr/bin/env bash

echo "💾 Checking for changes to auto-commit..." >&2

# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
  echo "⚠️ Not in a git repository - skipping auto-commit" >&2
  exit 0
fi

# Check if git is configured
if ! git config user.email > /dev/null 2>&1 || ! git config user.name > /dev/null 2>&1; then
  echo "⚠️ Git user not configured - skipping auto-commit" >&2
  echo "💡 Run: git config --global user.email 'your@email.com'" >&2
  echo "💡 Run: git config --global user.name 'Your Name'" >&2
  exit 0
fi

# Get current timestamp
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
ISO_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date +"%Y-%m-%d %H:%M:%S UTC")

# Get current branch
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")

# Check for uncommitted changes
if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
  echo "✨ No changes to commit - repository is clean" >&2
  exit 0
fi

echo "📊 Analyzing changes for auto-commit..." >&2

# Get status information
UNTRACKED_FILES=$(git status --porcelain 2>/dev/null | grep '^??' | wc -l | xargs)
MODIFIED_FILES=$(git status --porcelain 2>/dev/null | grep '^.M' | wc -l | xargs)
ADDED_FILES=$(git status --porcelain 2>/dev/null | grep '^A' | wc -l | xargs)
DELETED_FILES=$(git status --porcelain 2>/dev/null | grep '^.D' | wc -l | xargs)
RENAMED_FILES=$(git status --porcelain 2>/dev/null | grep '^R' | wc -l | xargs)

echo "📋 Change summary:" >&2
echo "   Branch: $CURRENT_BRANCH" >&2
echo "   Untracked: $UNTRACKED_FILES files" >&2
echo "   Modified: $MODIFIED_FILES files" >&2
echo "   Added: $ADDED_FILES files" >&2
echo "   Deleted: $DELETED_FILES files" >&2
echo "   Renamed: $RENAMED_FILES files" >&2

# Check for sensitive files before committing
echo "🔒 Checking for sensitive files..." >&2
SENSITIVE_PATTERNS=(
  "\.env"
  "\.env\.*"
  "*secret*"
  "*password*"
  "*key*"
  "id_rsa"
  "id_ed25519"
  "*.pem"
  "*.p12"
  "*.pfx"
)

SENSITIVE_FOUND=false
for pattern in "${SENSITIVE_PATTERNS[@]}"; do
  if git status --porcelain 2>/dev/null | grep -q "$pattern"; then
    SENSITIVE_FOUND=true
    echo "⚠️ Potentially sensitive file detected: $pattern" >&2
  fi
done

# Check if .gitignore exists and is respected
if [ ! -f ".gitignore" ]; then
  echo "💡 Consider creating a .gitignore file to exclude unwanted files" >&2
fi

# Option to skip auto-commit if environment variable is set
if [ "$SKIP_AUTO_COMMIT" = "true" ]; then
  echo "⏭️ Auto-commit skipped (SKIP_AUTO_COMMIT=true)" >&2
  exit 0
fi

# Warn about sensitive files but don't block (user choice)
if [ "$SENSITIVE_FOUND" = true ]; then
  echo "⚠️ Sensitive files detected - proceeding with caution" >&2
  echo "💡 Set SKIP_AUTO_COMMIT=true to disable auto-commits" >&2
fi

# Add all changes (respecting .gitignore)
echo "📥 Staging changes for commit..." >&2
git add -A

# Double-check that we have staged changes
if [ -z "$(git diff --cached --name-only)" ]; then
  echo "ℹ️ No changes staged after git add - nothing to commit" >&2
  exit 0
fi

# Calculate detailed statistics
echo "📊 Calculating commit statistics..." >&2

FILES_CHANGED=$(git diff --cached --numstat | wc -l | xargs)
INSERTIONS=0
DELETIONS=0

# Calculate insertions and deletions more reliably
if command -v awk &> /dev/null; then
  STATS=$(git diff --cached --numstat | awk '{insertions+=$1; deletions+=$2} END {print insertions " " deletions}')
  read -r INSERTIONS DELETIONS <<< "$STATS"
else
  # Fallback method
  INSERTIONS=$(git diff --cached --stat | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' | paste -sd+ | bc 2>/dev/null || echo '0')
  DELETIONS=$(git diff --cached --stat | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' | paste -sd+ | bc 2>/dev/null || echo '0')
fi

# Generate commit message
COMMIT_MSG="🤖 Claude Code auto-commit: Session ended"

# Add detailed commit body
COMMIT_BODY=$(cat <<EOF

Session Summary:
- Branch: $CURRENT_BRANCH
- Files changed: $FILES_CHANGED
- Insertions: +$INSERTIONS
- Deletions: -$DELETIONS
- Timestamp: $TIMESTAMP

Changes by type:
- Modified files: $MODIFIED_FILES
- New files: $UNTRACKED_FILES
- Deleted files: $DELETED_FILES
- Renamed files: $RENAMED_FILES

🤖 Generated with Claude Code
EOF
)

# Show what will be committed
echo "📝 Files to be committed:" >&2
git diff --cached --name-status | head -10 | while read status file; do
  case $status in
    A) echo "   ✅ Added: $file" >&2 ;;
    M) echo "   ✏️  Modified: $file" >&2 ;;
    D) echo "   ❌ Deleted: $file" >&2 ;;
    R*) echo "   🔄 Renamed: $file" >&2 ;;
    *) echo "   📄 $status: $file" >&2 ;;
  esac
done

if [ "$FILES_CHANGED" -gt 10 ]; then
  echo "   ... and $((FILES_CHANGED - 10)) more files" >&2
fi

echo "" >&2
echo "💾 Creating auto-commit..." >&2

# Create the commit
if echo "$COMMIT_BODY" | git commit -F -; then
  echo "✅ Auto-commit successful!" >&2
  
  # Show commit info
  COMMIT_HASH=$(git rev-parse --short HEAD)
  echo "📝 Commit: $COMMIT_HASH" >&2
  echo "🌿 Branch: $CURRENT_BRANCH" >&2
  
  # Check if we should push (optional)
  if [ "$AUTO_PUSH" = "true" ]; then
    echo "📤 Auto-pushing to remote..." >&2
    if git push 2>/dev/null; then
      echo "✅ Pushed to remote successfully" >&2
    else
      echo "⚠️ Push failed - commit created locally" >&2
      echo "💡 Run 'git push' manually when ready" >&2
    fi
  else
    echo "💡 Set AUTO_PUSH=true to automatically push commits" >&2
  fi
  
else
  echo "❌ Auto-commit failed" >&2
  echo "💡 You may need to resolve conflicts or check git status" >&2
  exit 1
fi

echo "" >&2
echo "📋 Auto-Commit Summary:" >&2
echo "   ✅ $FILES_CHANGED files committed" >&2
echo "   📈 +$INSERTIONS insertions, -$DELETIONS deletions" >&2
echo "   ⏰ $TIMESTAMP" >&2
echo "" >&2
echo "💡 Git Auto-Commit Tips:" >&2
echo "   • Set SKIP_AUTO_COMMIT=true to disable" >&2
echo "   • Set AUTO_PUSH=true to auto-push commits" >&2
echo "   • Review commits with 'git log --oneline'" >&2
echo "   • Use .gitignore to exclude sensitive files" >&2

exit 0
Full copyable content
{
  "hooks": {
    "stop": {
      "script": "./.claude/hooks/git-auto-commit-on-stop.sh"
    }
  }
}

About this resource

Features

  • Automatic git commit creation when session ends with comprehensive change detection including untracked files, modified files, added files, deleted files, and renamed files with detailed status analysis
  • Detailed commit statistics (files changed, insertions, deletions) with accurate line count calculations using git diff --numstat and awk for reliable statistics across all file types including binary files
  • Smart commit message generation with timestamps including ISO 8601 timestamps, session summaries, branch information, file change breakdowns, and customizable commit message templates with environment variable support
  • Pre-commit validation and safety checks including sensitive file detection (.env, secrets, keys, certificates) with pattern matching, Git configuration validation (user.name, user.email), and repository state verification
  • Branch and repository state verification with current branch detection, Git repository validation, clean repository detection, and branch state checking before commit creation
  • Customizable commit message templates with environment variable overrides (SKIP_AUTO_COMMIT, AUTO_PUSH) and support for custom commit message formats with detailed session summaries and change breakdowns
  • Untracked file handling and gitignore respect with automatic .gitignore validation, untracked file detection, and proper handling of ignored files with recommendations for .gitignore creation when missing
  • Error handling with informative feedback including commit failure recovery, Git configuration error messages, repository state error handling, and push failure recovery with manual push recommendations

Use Cases

  • Automatic version control for development sessions providing seamless Git integration without manual commit creation and comprehensive session tracking with detailed change summaries
  • Backup and history preservation of work progress automatically preserving all development work with timestamped commits and detailed change tracking for progress recovery and session history
  • Collaborative development with session tracking enabling team members to track development sessions with automatic commits and detailed change summaries for collaboration and code review
  • CI/CD integration with automated commits automatically committing changes for CI/CD pipeline integration with detailed commit messages and statistics for build tracking and deployment automation
  • Project milestone and progress documentation providing automatic documentation of development milestones with timestamped commits and detailed change summaries for project progress tracking
  • Development workflow integration seamlessly integrating automatic Git commits into development workflows without manual Git operations or separate version control tools

Installation

  1. Create hooks directory: mkdir -p .claude/hooks
  2. Create hook file: touch .claude/hooks/git-auto-commit-on-stop.sh
  3. Make executable: chmod +x .claude/hooks/git-auto-commit-on-stop.sh
  4. Add configuration from Hook Configuration section above to .claude/settings.json or ~/.claude/settings.json
  5. Alternative: Use the interactive /hooks command in Claude Code

Config paths

  • Local (not committed): .claude/settings.local.json
  • User settings (global): ~/.claude/settings.json
  • Project-wide (committed): .claude/settings.json

Requirements

  • Claude Code CLI installed
  • Project directory initialized
  • Git repository initialized
  • Git configured (user.name and user.email)
  • Bash shell available
  • Standard Unix utilities: awk (for parsing git diff --numstat), grep (for sensitive file detection), and Git write access for commit and push operations

Hook Configuration

{
  "hooks": {
    "stop": {
      "script": "./.claude/hooks/git-auto-commit-on-stop.sh"
    }
  }
}

Hook Script

#!/usr/bin/env bash

echo "💾 Checking for changes to auto-commit..." >&2

# Check if we're in a git repository
if ! git rev-parse --git-dir > /dev/null 2>&1; then
  echo "⚠️ Not in a git repository - skipping auto-commit" >&2
  exit 0
fi

# Check if git is configured
if ! git config user.email > /dev/null 2>&1 || ! git config user.name > /dev/null 2>&1; then
  echo "⚠️ Git user not configured - skipping auto-commit" >&2
  echo "💡 Run: git config --global user.email 'your@email.com'" >&2
  echo "💡 Run: git config --global user.name 'Your Name'" >&2
  exit 0
fi

# Get current timestamp
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
ISO_TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ" 2>/dev/null || date +"%Y-%m-%d %H:%M:%S UTC")

# Get current branch
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")

# Check for uncommitted changes
if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
  echo "✨ No changes to commit - repository is clean" >&2
  exit 0
fi

echo "📊 Analyzing changes for auto-commit..." >&2

# Get status information
UNTRACKED_FILES=$(git status --porcelain 2>/dev/null | grep '^??' | wc -l | xargs)
MODIFIED_FILES=$(git status --porcelain 2>/dev/null | grep '^.M' | wc -l | xargs)
ADDED_FILES=$(git status --porcelain 2>/dev/null | grep '^A' | wc -l | xargs)
DELETED_FILES=$(git status --porcelain 2>/dev/null | grep '^.D' | wc -l | xargs)
RENAMED_FILES=$(git status --porcelain 2>/dev/null | grep '^R' | wc -l | xargs)

echo "📋 Change summary:" >&2
echo "   Branch: $CURRENT_BRANCH" >&2
echo "   Untracked: $UNTRACKED_FILES files" >&2
echo "   Modified: $MODIFIED_FILES files" >&2
echo "   Added: $ADDED_FILES files" >&2
echo "   Deleted: $DELETED_FILES files" >&2
echo "   Renamed: $RENAMED_FILES files" >&2

# Check for sensitive files before committing
echo "🔒 Checking for sensitive files..." >&2
SENSITIVE_PATTERNS=(
  "\.env"
  "\.env\.*"
  "*secret*"
  "*password*"
  "*key*"
  "id_rsa"
  "id_ed25519"
  "*.pem"
  "*.p12"
  "*.pfx"
)

SENSITIVE_FOUND=false
for pattern in "${SENSITIVE_PATTERNS[@]}"; do
  if git status --porcelain 2>/dev/null | grep -q "$pattern"; then
    SENSITIVE_FOUND=true
    echo "⚠️ Potentially sensitive file detected: $pattern" >&2
  fi
done

# Check if .gitignore exists and is respected
if [ ! -f ".gitignore" ]; then
  echo "💡 Consider creating a .gitignore file to exclude unwanted files" >&2
fi

# Option to skip auto-commit if environment variable is set
if [ "$SKIP_AUTO_COMMIT" = "true" ]; then
  echo "⏭️ Auto-commit skipped (SKIP_AUTO_COMMIT=true)" >&2
  exit 0
fi

# Warn about sensitive files but don't block (user choice)
if [ "$SENSITIVE_FOUND" = true ]; then
  echo "⚠️ Sensitive files detected - proceeding with caution" >&2
  echo "💡 Set SKIP_AUTO_COMMIT=true to disable auto-commits" >&2
fi

# Add all changes (respecting .gitignore)
echo "📥 Staging changes for commit..." >&2
git add -A

# Double-check that we have staged changes
if [ -z "$(git diff --cached --name-only)" ]; then
  echo "ℹ️ No changes staged after git add - nothing to commit" >&2
  exit 0
fi

# Calculate detailed statistics
echo "📊 Calculating commit statistics..." >&2

FILES_CHANGED=$(git diff --cached --numstat | wc -l | xargs)
INSERTIONS=0
DELETIONS=0

# Calculate insertions and deletions more reliably
if command -v awk &> /dev/null; then
  STATS=$(git diff --cached --numstat | awk '{insertions+=$1; deletions+=$2} END {print insertions " " deletions}')
  read -r INSERTIONS DELETIONS <<< "$STATS"
else
  # Fallback method
  INSERTIONS=$(git diff --cached --stat | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' | paste -sd+ | bc 2>/dev/null || echo '0')
  DELETIONS=$(git diff --cached --stat | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' | paste -sd+ | bc 2>/dev/null || echo '0')
fi

# Generate commit message
COMMIT_MSG="🤖 Claude Code auto-commit: Session ended"

# Add detailed commit body
COMMIT_BODY=$(cat <<EOF

Session Summary:
- Branch: $CURRENT_BRANCH
- Files changed: $FILES_CHANGED
- Insertions: +$INSERTIONS
- Deletions: -$DELETIONS
- Timestamp: $TIMESTAMP

Changes by type:
- Modified files: $MODIFIED_FILES
- New files: $UNTRACKED_FILES
- Deleted files: $DELETED_FILES
- Renamed files: $RENAMED_FILES

🤖 Generated with Claude Code
EOF
)

# Show what will be committed
echo "📝 Files to be committed:" >&2
git diff --cached --name-status | head -10 | while read status file; do
  case $status in
    A) echo "   ✅ Added: $file" >&2 ;;
    M) echo "   ✏️  Modified: $file" >&2 ;;
    D) echo "   ❌ Deleted: $file" >&2 ;;
    R*) echo "   🔄 Renamed: $file" >&2 ;;
    *) echo "   📄 $status: $file" >&2 ;;
  esac
done

if [ "$FILES_CHANGED" -gt 10 ]; then
  echo "   ... and $((FILES_CHANGED - 10)) more files" >&2
fi

echo "" >&2
echo "💾 Creating auto-commit..." >&2

# Create the commit
if echo "$COMMIT_BODY" | git commit -F -; then
  echo "✅ Auto-commit successful!" >&2

  # Show commit info
  COMMIT_HASH=$(git rev-parse --short HEAD)
  echo "📝 Commit: $COMMIT_HASH" >&2
  echo "🌿 Branch: $CURRENT_BRANCH" >&2

  # Check if we should push (optional)
  if [ "$AUTO_PUSH" = "true" ]; then
    echo "📤 Auto-pushing to remote..." >&2
    if git push 2>/dev/null; then
      echo "✅ Pushed to remote successfully" >&2
    else
      echo "⚠️ Push failed - commit created locally" >&2
      echo "💡 Run 'git push' manually when ready" >&2
    fi
  else
    echo "💡 Set AUTO_PUSH=true to automatically push commits" >&2
  fi

else
  echo "❌ Auto-commit failed" >&2
  echo "💡 You may need to resolve conflicts or check git status" >&2
  exit 1
fi

echo "" >&2
echo "📋 Auto-Commit Summary:" >&2
echo "   ✅ $FILES_CHANGED files committed" >&2
echo "   📈 +$INSERTIONS insertions, -$DELETIONS deletions" >&2
echo "   ⏰ $TIMESTAMP" >&2
echo "" >&2
echo "💡 Git Auto-Commit Tips:" >&2
echo "   • Set SKIP_AUTO_COMMIT=true to disable" >&2
echo "   • Set AUTO_PUSH=true to auto-push commits" >&2
echo "   • Review commits with 'git log --oneline'" >&2
echo "   • Use .gitignore to exclude sensitive files" >&2

exit 0

Examples

Git Auto Commit On Stop Hook Script

Complete hook script that performs automatic Git commit when development session ends

#!/usr/bin/env bash
echo "💾 Checking for changes to auto-commit..." >&2
if ! git rev-parse --git-dir > /dev/null 2>&1; then
  echo "⚠️ Not in a git repository - skipping auto-commit" >&2
  exit 0
fi
if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
  echo "✨ No changes to commit - repository is clean" >&2
  exit 0
fi
TIMESTAMP=$(date +"%Y-%m-%d %H:%M:%S")
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
git add -A
FILES_CHANGED=$(git diff --cached --numstat | wc -l | xargs)
COMMIT_MSG="🤖 Claude Code auto-commit: Session ended at $TIMESTAMP"
if git commit -m "$COMMIT_MSG" -m "Branch: $CURRENT_BRANCH" -m "Files changed: $FILES_CHANGED"; then
  echo "✅ Auto-commit successful!" >&2
else
  echo "❌ Auto-commit failed" >&2
  exit 1
fi
exit 0

Sensitive File Detection and Skip Control

Enhanced hook script for sensitive file detection and environment variable skip control

#!/usr/bin/env bash
if [ "$SKIP_AUTO_COMMIT" = "true" ]; then
  echo "⏭️ Auto-commit skipped (SKIP_AUTO_COMMIT=true)" >&2
  exit 0
fi
if ! git rev-parse --git-dir > /dev/null 2>&1; then
  exit 0
fi
if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
  exit 0
fi
SENSITIVE_PATTERNS=(".env" ".env.*" "*secret*" "*password*" "*key*" "id_rsa" "id_ed25519" "*.pem")
SENSITIVE_FOUND=false
for pattern in "${SENSITIVE_PATTERNS[@]}"; do
  if git status --porcelain 2>/dev/null | grep -q "$pattern"; then
    SENSITIVE_FOUND=true
    echo "⚠️ Potentially sensitive file detected: $pattern" >&2
  fi
done
if [ "$SENSITIVE_FOUND" = true ]; then
  echo "⚠️ Sensitive files detected - proceeding with caution" >&2
  echo "💡 Set SKIP_AUTO_COMMIT=true to disable auto-commits" >&2
fi
git add -A
git commit -m "Auto-commit: $(date +'%Y-%m-%d %H:%M:%S')"
exit 0

Detailed Commit Statistics

Enhanced hook script for detailed commit statistics with accurate line count calculations

#!/usr/bin/env bash
if ! git rev-parse --git-dir > /dev/null 2>&1; then
  exit 0
fi
if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
  exit 0
fi
FILES_CHANGED=$(git status --porcelain 2>/dev/null | wc -l | xargs)
MODIFIED_FILES=$(git status --porcelain 2>/dev/null | grep '^.M' | wc -l | xargs)
ADDED_FILES=$(git status --porcelain 2>/dev/null | grep '^A' | wc -l | xargs)
DELETED_FILES=$(git status --porcelain 2>/dev/null | grep '^.D' | wc -l | xargs)
if command -v awk &> /dev/null; then
  STATS=$(git diff --cached --numstat 2>/dev/null | awk '{insertions+=$1; deletions+=$2} END {print insertions " " deletions}')
  read -r INSERTIONS DELETIONS <<< "$STATS"
else
  INSERTIONS=0
  DELETIONS=0
fi
COMMIT_MSG="Auto-commit: $(date +'%Y-%m-%d %H:%M:%S')"
COMMIT_BODY="Files changed: $FILES_CHANGED
Modified: $MODIFIED_FILES
Added: $ADDED_FILES
Deleted: $DELETED_FILES
Insertions: +$INSERTIONS
Deletions: -$DELETIONS"
git add -A
git commit -m "$COMMIT_MSG" -m "$COMMIT_BODY"
exit 0

Automatic Push to Remote

Enhanced hook script for automatic push to remote repository with error handling

#!/usr/bin/env bash
if ! git rev-parse --git-dir > /dev/null 2>&1; then
  exit 0
fi
if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
  exit 0
fi
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
git add -A
git commit -m "Auto-commit: $(date +'%Y-%m-%d %H:%M:%S')" -m "Branch: $CURRENT_BRANCH"
if [ "$AUTO_PUSH" = "true" ]; then
  echo "📤 Auto-pushing to remote..." >&2
  if git push 2>/dev/null; then
    echo "✅ Pushed to remote successfully" >&2
  else
    echo "⚠️ Push failed - commit created locally" >&2
    echo "💡 Run 'git push' manually when ready" >&2
  fi
fi
exit 0

Troubleshooting

Hook creates commits even when no meaningful changes made

git status --porcelain check shows temp files. Update .gitignore excluding: '.DS_Store', '.swp', 'node_modules/'. Or add file count threshold: 'if [ "$MODIFIED_FILES" -lt 2 ]; then exit 0; fi'. Verify .gitignore patterns match temporary files. Use git status --ignored to check ignored files.

Sensitive files (.env) committed despite pattern detection warnings

Pattern match non-blocking by design. Add hard block: 'if [ "$SENSITIVE_FOUND" = true ]; then exit 1; fi' before git add. Or use git-secrets: 'git secrets --scan' pre-commit. Update .gitignore to exclude sensitive file patterns. Use git-secrets or similar tools for automatic detection.

Auto-commit fails with empty commit message or malformed body

COMMIT_BODY uses cat with EOF delimiter requiring proper quoting. Replace with: 'git commit -m "Auto-commit: $TIMESTAMP" -m "Files: $FILES_CHANGED" -m "Branch: $CURRENT_BRANCH"' avoiding heredoc issues. Verify commit message variables are not empty. Use git commit with multiple -m flags for multi-line messages.

SKIP_AUTO_COMMIT environment variable ignored when set

Variable not exported to subprocess. Use: 'export SKIP_AUTO_COMMIT=true' before Claude session. Or add to shell profile: 'echo "export SKIP_AUTO_COMMIT=true" >> ~/.bashrc'. Verify: 'env | grep SKIP'. Check environment variable is set in correct shell context. Use export command to ensure variable is available to subprocesses.

Statistics show zero insertions/deletions despite file changes

git diff --stat fails on binary files or first commit. Add: '--ignore-all-space --ignore-blank-lines' flags. Or use: 'git diff --numstat | awk "{add+=$1; del+=$2} END {print add, del}"' for accurate counts. Verify files are staged before calculating statistics. Check for binary file detection issues.

Auto-commit fails on detached HEAD state

Hook doesn't check for detached HEAD. Add check: 'if git symbolic-ref -q HEAD > /dev/null 2>&1; then echo "On branch"; else echo "Detached HEAD - skipping commit"; exit 0; fi'. Verify repository is on a valid branch before committing. Use git checkout to switch to a branch if needed.

AUTO_PUSH fails with authentication errors

Git push requires authentication. Configure Git credentials: 'git config --global credential.helper store'. Or use SSH keys: 'ssh-keygen -t ed25519 -C "your@email.com"'. Verify remote URL is correct: 'git remote -v'. Check SSH key is added to Git provider. Use credential helper for HTTPS authentication.

Commit messages don't include expected information

Verify commit message generation logic. Check timestamp format: 'date +"%Y-%m-%d %H:%M:%S"'. Verify branch detection: 'git branch --show-current'. Check file statistics calculation. Use git commit with multiple -m flags for structured commit messages. Verify all variables are properly set before commit creation.

#git#version-control#stop-hook#automation#commit

Source citations

Signals

Loading live community signals…

More like this, weekly

A short, calm digest of reviewed Claude resources. Unsubscribe any time.