Skip to content

Instantly share code, notes, and snippets.

@inxilpro
Last active October 15, 2025 18:01
Show Gist options
  • Select an option

  • Save inxilpro/772fee110bb1c0a6d98593f8e5ac57e7 to your computer and use it in GitHub Desktop.

Select an option

Save inxilpro/772fee110bb1c0a6d98593f8e5ac57e7 to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
# Move into project root using git
REPO_ROOT=$(git rev-parse --show-toplevel)
cd "$REPO_ROOT" || exit
# Configuration
INCLUDE_COMMIT_HISTORY=true
COMMIT_HISTORY_COUNT=5
FAIL_ON_ERROR=false # Set to true to exit with error code for debugging
# Get commit message file path
COMMIT_MSG_FILE=$1
if [[ ! -f "$COMMIT_MSG_FILE" ]]; then
echo "Error: Commit message file not found"
exit 1
fi
# Read the commit message, trim it, and convert to lowercase
COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")
COMMIT_MSG=$(echo "$COMMIT_MSG" | xargs)
COMMIT_MSG_LOWER=$(echo "$COMMIT_MSG" | tr '[:upper:]' '[:lower:]')
SHOULD_GENERATE=false
# Check if empty
if [[ -z "$COMMIT_MSG" ]]; then
SHOULD_GENERATE=true
fi
# Check if WIP (case-insensitive)
if [[ "$COMMIT_MSG_LOWER" == "wip" ]]; then
SHOULD_GENERATE=true
fi
# Check if it's "Update [filename]" for a single-file change
# (This is the auto-generated format from GitHub Desktop for single file changes)
if [[ ! $SHOULD_GENERATE == true ]]; then
IFS=$'\n' read -r -d '' -a CHANGED_FILES < <(git diff --cached --name-only && printf '\0')
if [[ "$FAIL_ON_ERROR" = true ]]; then
echo "Debug: Found ${#CHANGED_FILES[@]} changed file(s)" >&2
echo "Debug: Commit message: '$COMMIT_MSG'" >&2
fi
# If only one file changed
if [[ ${#CHANGED_FILES[@]} -eq 1 ]]; then
FILE_BASENAME=$(basename "${CHANGED_FILES[0]}")
EXPECTED_MSG="update $FILE_BASENAME"
EXPECTED_MSG_LOWER=$(echo "$EXPECTED_MSG" | tr '[:upper:]' '[:lower:]')
if [[ "$FAIL_ON_ERROR" = true ]]; then
echo "Debug: Expected message: '$EXPECTED_MSG_LOWER'" >&2
echo "Debug: Actual message: '$COMMIT_MSG_LOWER'" >&2
fi
if [[ "$COMMIT_MSG_LOWER" == "$EXPECTED_MSG_LOWER" ]]; then
SHOULD_GENERATE=true
fi
fi
fi
# If message is fine, exit
if [[ ! $SHOULD_GENERATE == true ]]; then
exit 0
fi
# Check if Claude CLI is available
if ! command -v claude &> /dev/null; then
if [[ -z "$COMMIT_MSG" ]]; then
echo "WIP" > "$COMMIT_MSG_FILE"
fi
if [[ "$FAIL_ON_ERROR" = true ]]; then
echo "Error: Claude CLI not available" >&2
exit 1
fi
exit 0
fi
# Get staged changes
DIFF=$(git diff --cached)
if [[ -z "$DIFF" ]]; then
# No changes, use WIP
echo "WIP" > "$COMMIT_MSG_FILE"
if [[ "$FAIL_ON_ERROR" = true ]]; then
echo "Error: No staged changes to commit" >&2
exit 1
fi
exit 0
fi
# Build the prompt
PROMPT="Generate a concise commit message for these changes. Respond with only the commit message, no additional text or formatting. Focus on what other developers
would need to know about the commit. Do not include qualitative statements or speculate as to why the changes were made.
Staged changes:
\`\`\`
$DIFF
\`\`\`"
# Include commit history if configured
if [[ "$INCLUDE_COMMIT_HISTORY" = true ]]; then
HISTORY=$(git log -n "$COMMIT_HISTORY_COUNT" --format='%s')
PROMPT="$PROMPT
Recent commit messages for style reference:
\`\`\`
$HISTORY
\`\`\`"
fi
# Call Claude to generate commit message
GENERATED_MSG=$(echo "$PROMPT" | claude 2>&1)
CLAUDE_EXIT_CODE=$?
if [[ $CLAUDE_EXIT_CODE -eq 0 && -n "$GENERATED_MSG" ]]; then
echo "$GENERATED_MSG" > "$COMMIT_MSG_FILE"
else
# Claude failed, use WIP
echo "WIP" > "$COMMIT_MSG_FILE"
if [[ "$FAIL_ON_ERROR" = true ]]; then
echo "Error: Claude CLI failed to generate commit message" >&2
echo "Claude exit code: $CLAUDE_EXIT_CODE" >&2
echo "Claude output: $GENERATED_MSG" >&2
exit 1
fi
fi
exit 0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment