Skip to main content

% 16k.es

Using Ai to Generate Meaningful Commit Messages

I have a couple of tasks / pet-projects where a task in the background is taking care of commiting to git and pushing to github.

Needless to say, 99% of my all-life commits used to be just “fix typo” or “update readme” or “add missing semicolon”. With the commits being automatic it is even worse: now everything is “automatic commit from laptop-foobar”. Meh.

Gemini AI logo

Most times it is not very important what the commit message is, but sometimes it is. At the end of the day, that’s why git commit requires a message!

I wish I could take a quick glance at the diff and summarize it in a very short message to pass it to the commit script. Of course, the automation would no longer be automatic. Shame!

But wait, reading a short text and summarizing it is not exactly what AI can do? Why not try? Could a simple script look at the changes and generate a commit message?

# which model to use?

Easy question. Since OpenAI no longer offers a 100% free tier, I chose the Gemini API as it is currently free. Yes, I know 👹 I might try later with a local model, but not today.

The code to achive this is really trivial. Btw, at first I wanted to use Go, but the Debian laptop I’m using runs go-1.19 and at least 1.21 is needed so I used Python instead.

All you need is the google-generativeai package:

python3 -m venv ai-commit
cd ai-commit
source bin/activate
python3 -m pip install --upgrade google-generativeai

The overall idea is that the background process writes the diff to a file and then calls the python script. This one reads the diff, generates a commit message and returns it to the background process which will use it to commit to git.

As simple ini file is used to store the API key and the model to use.

These are the basic steps:

# import the Gemini stuff
import google.generativeai as genai

# read config, parse arguments and that stuff...
# [...]

# setup model
model = genai.GenerativeModel(generative_model)
genai.configure(api_key = api_key)

# create prompt
prompt = "create a short commit message (less than 80 characters long) from this diff:"

# read diff from file
with open(f, "r") as f:
    diff = f.read()
prompt = prompt + diff
text = generate_commit_msg(prompt)
print("{}".format(text))

…and the function called is just:

def generate_commit_msg(prompt):
    try:
        response = model.generate_content(prompt)
        return(response.text.rstrip('\n'))
    except:
        print("Sorry, I could not get a response")
        raise
        sys.exit(1)

(code available here)

## Example

I’m writing the agenda for a future talk in a school. This is a short git diff output:

diff --git a/events/daw 2024/daw 2024 topics.md b/events/daw 2024/daw 2024 topics.md
index cea35f6..782c8c1 100644
--- a/events/daw 2024/daw 2024 topics.md
+++ b/events/daw 2024/daw 2024 topics.md
@@ -7,0 +8,3 @@
+- OWASP top 10
+- OWASP top 10 mobile

Note: I’m using:

git diff --minimal --ignore-submodules --no-color --unified=0

to generate the diff.

The output is written to a file and then the python script is called:

source /path/.../Projects/ai-commit/bin/activate
/path/.../Projects/ai-commit/ai-commit.py /tmp/foobar.diff

And the result is:

Add OWASP Top 10 topics to DAW 2024 agenda

which will be the commit message:

git log --oneline
2a4cc72 (HEAD -> main, origin/main, origin/HEAD) Add OWASP Top 10 topics to DAW 2024 agenda
03e2617 auto-commit from old laptop
f392d10 auto-commit from old laptop
0352b1a auto-commit from old laptop
a3b2b11 auto-commit from old laptop
93b2a10 auto-commit from old laptop

Cool!, isn’t it? 😄