Build a Local Git Commit Assistant with LLM and Git Hooks

AI tutorial - IT technology blog
AI tutorial - IT technology blog

Stop Writing ‘Update code’ in Your Commits

Writing meaningful commit messages often feels like a chore, especially when you are deep in the zone and just want to push your changes. I have seen many developers (and I have been guilty of this too) resort to messages like “fix bugs,” “wip,” or the classic “update.” This habit makes debugging history a nightmare for the rest of the team.

In my real-world experience, this is one of the essential skills to master: maintaining a clean, descriptive, and professional git history. It saves hours during code reviews and helps when you need to revert a specific change months later. To solve this without constant manual effort, I built a local Git Commit Assistant using a Large Language Model (LLM) and Git Hooks. The best part? It runs entirely on your machine, so your proprietary code never leaves your local environment.

Quick Start (5 min)

You can get a basic version running in just a few minutes using Ollama and a simple shell script.

1. Install Ollama and a Model

Download Ollama from their official site and pull a lightweight model like Mistral or Llama 3. For commit messages, a small model is more than enough.

# Install the model
ollama pull mistral

2. Create the Git Hook

Navigate to your project’s root and create a file in the hooks directory. We will use the prepare-commit-msg hook, which triggers before the commit message editor opens.

# Create the hook file
touch .git/hooks/prepare-commit-msg
chmod +x .git/hooks/prepare-commit-msg

3. Add a Simple Automation Script

Paste this into .git/hooks/prepare-commit-msg:

#!/bin/bash

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

if [ -z "$DIFF" ]; then
  exit 0
fi

# Ask Ollama to generate a message
RESPONSE=$(curl -s -X POST http://localhost:11434/api/generate -d '{
  "model": "mistral",
  "prompt": "Write a short, professional git commit message for these changes. Use conventional commits format (feat:, fix:, etc.). Only return the message text: '"$DIFF"'',
  "stream": false
}' | jq -r '.response')

echo "$RESPONSE" > "$1"

Now, whenever you run git commit, the assistant automatically fills in the message based on your staged changes.

Deep Dive: How it Works

The solution relies on the synergy between Git’s internal lifecycle and local API calls. Git Hooks are scripts that run automatically every time a particular event occurs in a Git repository. To build a robust assistant, we need to handle the data flow carefully.

The Git Hook Pipeline

I prefer using Python for the logic because handling multi-line strings and JSON responses from the LLM is much cleaner than in Bash. Here is a more advanced structure for the prepare-commit-msg hook:

import subprocess
import requests
import sys

def get_git_diff():
    # Only get the staged changes
    return subprocess.check_output(["git", "diff", "--cached"]).decode("utf-8")

def generate_message(diff):
    url = "http://localhost:11434/api/generate"
    prompt = f"""Analyze the following git diff and write a concise commit message following Conventional Commits standards.
    
    Diff:
    {diff}
    
    Response format: <type>(<scope>): <description>"""
    
    payload = {"model": "mistral", "prompt": prompt, "stream": False}
    response = requests.post(url, json=payload)
    return response.json()["response"].strip()

if __name__ == "__main__":
    commit_msg_filepath = sys.argv[1]
    diff = get_git_diff()
    
    if diff:
        message = generate_message(diff)
        with open(commit_msg_filepath, "w") as f:
            f.write(message)

Why Local LLMs?

Privacy is the primary reason. If you are working on a corporate project, sending code snippets to an external API (like OpenAI) might violate security policies. By using Ollama or LocalAI, the data stays on your RAM. Furthermore, it works offline, which is great if you are working from a plane or a spotty cafe connection.

Advanced Usage: Adding Quality Checks

A true assistant doesn’t just write messages; it prevents bad code from being committed. We can use the pre-commit hook to perform quality checks using the LLM before the commit is even allowed to proceed.

Checking for Secrets or Debug Logs

I often add a check to ensure I haven’t left any console.log, print(), or hardcoded API keys in the code. You can prompt the LLM to look for these specifically.

def check_code_quality(diff):
    prompt = f"""Scan this diff for security risks like hardcoded passwords or forgotten debug statements (console.log, print). 
    If you find any, output 'REJECT: <reason>'. If it looks good, output 'PASS'.
    
    Diff:
    {diff}"""
    # ... logic to call LLM ...
    if "REJECT" in response:
        print(f"Commit blocked: {response}")
        sys.exit(1) # This stops the commit process

Handling Large Diffs

LLMs have context limits. If you stage 50 files at once, the diff will be too large for the model to process. I usually implement a character limit or summarize the diff per file. A good rule of thumb is to only send the first 2000 words of a diff to the LLM to keep the response time fast.

Practical Tips for Daily Use

  • Choose the right model: For commit messages, Mistral-7B or Llama-3-8B are excellent. If your machine is older, try Phi-3 Mini from Microsoft; it’s incredibly fast and surprisingly smart for its size.
  • Refine your prompt: If the model is too wordy, tell it: “Be extremely terse. Use at most 10 words.”
  • The ‘Edit’ workflow: The prepare-commit-msg hook still opens your editor (like Vim or VS Code). This is perfect because the LLM provides a draft, and you can quickly tweak it before saving. Never trust the AI 100%.
  • Global Hooks: If you want this assistant in every project, you can configure a global git hooks directory using git config --global core.hooksPath /path/to/your/global/hooks.

Setting this up takes about 15 minutes but pays off every single day. It forces you to look at your diffs and ensures your project history looks like it was written by a senior engineer, even on your most tired Mondays.

Share: