Using AI To Generate Git Commit Message For Free

Overview

Do you love writing commit messages? If so, you can return to your development now 😛

For those of us who doesn’t enjoy writing commit messages very much, there is a solution.

Let me walk you through how to commit without you writing the commit message but let the AI do that.

I posted a video version of this post here, check it out if you are more of a visual type:

Step by step to configure auto commit message

Step 1: Create a Groq account and API key

First, head to https://console.groq.com/ and register an account

Next, go to https://console.groq.com/keys to generate your keys

Save your key some where safe, Groq doesn’t show it again to you.

Step 2: Configure your GROQ_API_KEY environment variable

On mac/linux, run

export GROQ_API_KEY=YOUR_KEY_HERE

To save the key permanently, edit your ~/.zshrc or ~/.bashrc and enter the above line

On windows, you can do this:

$env:GROQ_API_KEY="YOUR_KEY_HERE"

To store it permanently, you can set the environment variable in the windows (check this out https://docs.oracle.com/cd/E83411_01/OREAD/creating-and-modifying-environment-variables-on-windows.htm)

Step 3: Create the script for prepare-commit-msg hook

Create the following file .git/hooks/prepare-commit-msg and make it executable. On windows, you can open git bash to run the following commands

touch .git/hooks/prepare-commit-msg
chmod +x .git/hooks/prepare-commit-msg

Now, here is the content of that file:

#!/bin/bash

# File where the commit message will be written
COMMIT_MSG_FILE=$1

# Log file for debugging purposes
LOG_FILE=".git/groq_api_debug.log"

# Check if the API key environment variable is set
if [ -z "$GROQ_API_KEY" ]; then
  echo "Error: GROQ_API_KEY is not set. Please set it in your environment."
  exit 1
fi

# Function to escape JSON safely across platforms using Python
escape_json() {
    printf '%s' "$1" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))'
}

# Function to check if the commit message contains "skip llm"
check_skip_llm() {
    # Read the user-provided commit message
    local user_commit_message=$(cat "$COMMIT_MSG_FILE")

    # Check if the commit message contains "skip llm" (case insensitive)
    if echo "$user_commit_message" | grep -qi "skip llm"; then
        # Remove the "skip llm" phrase (case insensitive)
        local cleaned_message=$(echo "$user_commit_message" | sed 's/skip llm//Ig')

        # Log that the user message is being used
        echo "User-provided commit message with 'skip llm' detected. Using user message." >> "$LOG_FILE"

        # Write the cleaned message to the commit message file
        echo "$cleaned_message" > "$COMMIT_MSG_FILE"

        # Exit the script, skipping the LLM generation
        exit 0
    fi
}

# Function to generate a commit message from Groq API using Llama3 8b
generate_commit_message() {
    # Capture the Git diff of staged changes
    local git_diff=$(git diff --cached)

    # If there's no diff, exit early
    if [ -z "$git_diff" ]; then
        echo "No changes detected. Using default commit message." >> "$LOG_FILE"
        exit 0
    fi

    # Escape the git diff to make it JSON-safe (handling double quotes, newlines, etc.)
    local git_diff_escaped=$(echo "$git_diff" | sed 's/"/\\"/g')

    # Define the prompt with the Git changes
    local prompt="Generate a detailed commit message for the following changes without any extra explanations: $git_diff_escaped"

    # Escape the entire prompt to ensure it's JSON safe
    local prompt_escaped=$(escape_json "$prompt")

    # Log the prompt
    echo "==== INPUT to Groq API ====" >> "$LOG_FILE"
    echo "$prompt_escaped" >> "$LOG_FILE"

    # Example payload for the Groq API with the Git diff included
    local payload=$(cat <<EOF
{
    "messages": [
        {
            "role": "user",
            "content": $prompt_escaped
        }
    ],
    "model": "llama3-groq-70b-8192-tool-use-preview",
    "temperature": 1,
    "max_tokens": 1024,
    "top_p": 1,
    "stream": false,
    "stop": null
}
EOF
)

    # Log the payload being sent
    echo "==== Payload to Groq API ====" >> "$LOG_FILE"
    echo "$payload" >> "$LOG_FILE"

    # Make a POST request to the Groq API using the API key and store the response in a variable
    local response=$(curl -s -X POST "https://api.groq.com/openai/v1/chat/completions" \
        -H "Content-Type: application/json" \
        -H "Authorization: Bearer $GROQ_API_KEY" \
        -d "$payload")

    # Log the full API response
    echo "==== API Response ====" >> "$LOG_FILE"
    echo "$response" >> "$LOG_FILE"

    # Use Python to parse the response and extract the commit message
    local commit_message=$(echo "$response" | python3 -c 'import json,sys; response = json.load(sys.stdin); print(response["choices"][0]["message"]["content"] if "choices" in response else "null")')

    # Log the extracted commit message
    echo "==== Extracted Commit Message ====" >> "$LOG_FILE"
    echo "$commit_message" >> "$LOG_FILE"

    # If the API returned null, log an error and exit
    if [ -z "$commit_message" ] || [ "$commit_message" == "null" ]; then
        echo "Error: No commit message generated by Groq API." >> "$LOG_FILE"
        exit 1
    fi

    # Write the generated commit message to the commit message file
    echo "$commit_message" > "$COMMIT_MSG_FILE"
}
check_skip_llm
# Call the function to generate the commit message
generate_commit_message

exit 0

The script basically calls GROQ to get the commit messages based on your changes.

Skipping LLM

There are times you want to skip calling the LLM for commit messages (you are commit package-lock.json for example), in such case, you can prepend the message with “skip llm” to use your literal message.

Of course, you can change the prefix to something else, just modify the script.

and that’s it!

Oh, by the way, you need to have python3 installed on your system

Conclusion

That’s how you free yourself from writing commit message. Have fun!

Leave a Comment