Ever found yourself staring at git commit -m
wondering how to describe your changes? Let's build a script that uses OpenAI's GPT to generate meaningful commit messages from your git diffs. We'll explore two implementations: one in Bash and an improved version in Go.
High quality git commit messages are a great way to improve your workflow. They are important because allow you (or other developers working on your code) to quickly see what changes were made and why.
It can be quite time consuming to write a good commit message, and often times you may not remember exactly what you have changed.
I decided to see what could be done to make make it easier for myself.
The only hard requirement I gave myself is that it must be a single command that can be run from anywhere in my terminal, and should allow me to create a both a 'commit subject' and 'commit body' which is a multi-line commit messages.
Ideally we don't want any dependencies, so that as many people can depend on this as possible.
Implementations
Naive Bash Implementation
This was my first port of call. A simple bash script that mostly gets the job done and is a great way to wireframe out the underlying concept.
See the full version here.
Prerequisites
- An OpenAI API key
jq
installed for JSON parsing- zsh shell
- Basic understanding of git
Installation (Bash Version)
- Create a bin directory in your home folder if it doesn't exist:
mkdir -p ~/bin
-
Save this script as
smart-commit.zsh
in your bin directory: View the complete bash script -
Make it executable and add to your PATH:
chmod +x ~/bin/smart-commit.zsh
echo 'export PATH="$HOME/bin:$PATH"' >> ~/.zshrc
source ~/.zshrc
Limitations of Bash Version
While functional, the bash implementation has several limitations:
- Dependency on zsh shell
- Requires jq and curl to be installed
- Issues with parsing multiline responses from OpenAI
- Less robust error handling
Go Implementation
To address these limitations, I created an improved version in Go. Here's why it's better:
Advantages of Go Version
Dependency Reduction
- Eliminates the need for jq as JSON handling is native in Go
- Removes dependency on zsh shell
- No reliance on external shell commands
- More portable as it only requires Go runtime
Better Error Handling
- Type-safe error handling with Go's error system
- Structured error handling instead of shell exit codes
- Better stack traces when things go wrong
- Proper JSON parsing validation
Code Quality
- Strongly typed data structures for API requests/responses
- Better code organization with proper function separation
- More maintainable and testable code
- IDE support with code completion
Performance
- Native HTTP client instead of shell curl command
- More efficient JSON handling without process spawning
- Reduced system calls
- Better memory management
Installation (Go Version)
- Clone the repository:
git clone https://github.com/positonic/smart-commits
- Build the binary:
go build -o smart-commit
- Move to your bin directory:
mv smart-commit ~/bin/
- Set your OpenAI API key (add to your shell config for persistence):
echo 'export OPENAI_API_KEY="your-key-here"' >> ~/.zshrc
source ~/.zshrc
Technical Details
The Go version includes structured data handling:
type OpenAIRequest struct {
Model string `json:"model"`
Messages []Message `json:"messages"`
}
type Message struct {
Role string `json:"role"`
Content string `json:"content"`
}
And improved prompt engineering:
Content: "You are a helpful git commit message writer. Given a git diff, write a conventional commit message in this format:\n\n" +
"<type>: <subject>\n\n" +
"<detailed description>\n\n" +
"Rules:\n" +
"- First line (subject) must be 50 characters or less\n" +
"- Use conventional commit types (feat, fix, docs, style, refactor, test, chore)\n" +
"- Add a blank line between subject and description\n" +
"- Description should explain what and why, not how"
Usage (Both Versions)
Both versions work similarly:
- Navigate to your git project:
cd your-project
-
Make some changes to your files
-
Run the tool:
smart-commit # Go version
# or
smart-commit.zsh # Bash version
I use an alias in my zsh config to make it easier to run:
echo 'alias sc="smart-commit"' >> ~/.zshrc
source ~/.zshrc
and run it with sc
Example Output
$ smart-commit
Generating commit message...
Proposed commit message:
feat: implement user authentication system
Add OAuth2 authentication flow with Google provider.
Include user session management and secure cookie handling.
Do you want to proceed with this commit message? (y/n): y
Successfully committed!
Security Note
Important: Remember to never commit your OpenAI API key to version control! Always keep it in your local environment variables.
Source Code
Found this helpful? Follow me on X/Twitter or check out more of my work on GitHub.