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.

Revisions

  1. inxilpro revised this gist Oct 15, 2025. No changes.
  2. inxilpro revised this gist Oct 14, 2025. 1 changed file with 32 additions and 11 deletions.
    43 changes: 32 additions & 11 deletions commit-msg.sh
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,7 @@ 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
    @@ -16,16 +17,11 @@ if [[ ! -f "$COMMIT_MSG_FILE" ]]; then
    exit 1
    fi

    # Read the commit message
    # Read the commit message, trim it, and convert to lowercase
    COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

    # Trim whitespace
    COMMIT_MSG=$(echo "$COMMIT_MSG" | xargs)

    # Convert to lowercase for case-insensitive comparison
    COMMIT_MSG_LOWER=$(echo "$COMMIT_MSG" | tr '[:upper:]' '[:lower:]')

    # Check if message needs generation
    SHOULD_GENERATE=false

    # Check if empty
    @@ -39,16 +35,26 @@ if [[ "$COMMIT_MSG_LOWER" == "wip" ]]; then
    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
    # Get list of changed files
    mapfile -t CHANGED_FILES < <(git diff --cached --name-only)
    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
    @@ -62,10 +68,15 @@ fi

    # Check if Claude CLI is available
    if ! command -v claude &> /dev/null; then
    # Claude not available, replace empty message with WIP
    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

    @@ -75,6 +86,11 @@ 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

    @@ -102,13 +118,18 @@ fi
    GENERATED_MSG=$(echo "$PROMPT" | claude 2>&1)
    CLAUDE_EXIT_CODE=$?

    # Check if Claude succeeded
    if [[ $CLAUDE_EXIT_CODE -eq 0 && -n "$GENERATED_MSG" ]]; then
    # Write generated message to commit file
    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
  3. inxilpro created this gist Oct 14, 2025.
    114 changes: 114 additions & 0 deletions commit-msg.sh
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,114 @@
    #!/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

    # 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
    COMMIT_MSG=$(cat "$COMMIT_MSG_FILE")

    # Trim whitespace
    COMMIT_MSG=$(echo "$COMMIT_MSG" | xargs)

    # Convert to lowercase for case-insensitive comparison
    COMMIT_MSG_LOWER=$(echo "$COMMIT_MSG" | tr '[:upper:]' '[:lower:]')

    # Check if message needs generation
    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
    if [[ ! $SHOULD_GENERATE == true ]]; then
    # Get list of changed files
    mapfile -t CHANGED_FILES < <(git diff --cached --name-only)

    # 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 [[ "$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
    # Claude not available, replace empty message with WIP
    if [[ -z "$COMMIT_MSG" ]]; then
    echo "WIP" > "$COMMIT_MSG_FILE"
    fi
    exit 0
    fi

    # Get staged changes
    DIFF=$(git diff --cached)

    if [[ -z "$DIFF" ]]; then
    # No changes, use WIP
    echo "WIP" > "$COMMIT_MSG_FILE"
    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=$?

    # Check if Claude succeeded
    if [[ $CLAUDE_EXIT_CODE -eq 0 && -n "$GENERATED_MSG" ]]; then
    # Write generated message to commit file
    echo "$GENERATED_MSG" > "$COMMIT_MSG_FILE"
    else
    # Claude failed, use WIP
    echo "WIP" > "$COMMIT_MSG_FILE"
    fi

    exit 0