Published on

Building a .NET-Powered Commit Message Generator: A Step-by-Step Guide

Authors

Building a .NET-Powered Commit Message Generator: A Step-by-Step Guide

In this guide, we'll learn how to:

  1. Set up a .NET console app and install required dependencies
  2. Integrate with the OpenAI API to generate commit messages
  3. Implement functions to retrieve git diffs and generate commit messages
  4. Run and test the commit message generator program

Why are commit messages important

If you ever tracked my commit messages they would ideally look something like this

Before automatic commit messages

Commit Message
Remove memoryCache
Add retry

But with the help of Commit message generator our commit messages will look like this:

After automatic commit messages

Commit MessageDetails
Add images to commit message generator documentationInclude before and after screenshots to illustrate the usage of the commit message generator tool.
Fix section numbering and improve method descriptionsUpdated the commit message generator guide to include an overview of key learning objectives, such as effective prompt creation and API usage for generating messages. Also clarified variable names in the code example for better readability.

The automatically generated commit messages are more detailed and informative, clearly conveying the purpose and changes of each commit. They follow best practices like using the imperative mood and referencing relevant issues. This results in a more organized and maintainable commit history that benefits the entire development team.

1. Set up a .NET console app

  1. Create a new .NET console app:

    dotnet new console -n CommitMessageGenerator
    cd CommitMessageGenerator  
    
  2. Install the required NuGet packages:

    dotnet add package CliWrap
    dotnet add package OpenAI --prerelease
    
    • CliWrap: For executing git commands from within the application.
    • OpenAI: For integrating with the OpenAI API to generate commit messages.
  3. Open the project in your preferred IDE or text editor:

    code .
    

2. Set up the OpenAI API key

  1. Obtain an API key from OpenAI by signing up for their service and creating a new API key Where do I find my OpenAI API Key?.
  2. Set the API key as an environment variable named OPENAI_API_KEY. This will allow your application to securely access the OpenAI API.
# OPENAI_API_KEY begins with `sk-`
export OPENAI_API_KEY=<your-key-here>

3. Implement the CreateGitMessage function

static async Task<ChatCompletion> CreateGitMessage(string gitDiff)
{
    string apiKeyCredential = Environment.GetEnvironmentVariable("OPENAI_API_KEY") ?? throw new ArgumentNullException("apiKeyCredential", "Missing OPENAI_API_KEY");
    ChatClient client = new(model: "gpt-4o-mini", apiKeyCredential);

    string createGitMessagePrompt = $"""
                                     You are a Git commit message generator. Analyze the following git diff and 
                                     produce a concise, informative commit message following standard Git commit message
                                     conventions. The commit message should have a brief subject line (50 characters
                                     or less) and, if necessary, a more detailed body separated by a blank line. Use
                                     the imperative mood and reference any relevant issue numbers. Respond only with
                                     the commit message itself, without any additional text or explanation. 
                                     <git_diff>{gitDiff}</git_diff>
                                     """;
                                     
    ChatCompletion commitMessage = await client.CompleteChatAsync(
    [
        new UserChatMessage(createGitMessagePrompt),  
    ]);
    return commitMessage;
}

Full breakdown of the method

  1. Raw String Literals for Prompt:
    string createGitMessagePrompt = $"""
                                     You are a Git commit message generator. Analyze the following git diff and
                                     produce a concise, informative commit message following standard Git commit message
                                     conventions. The commit message should have a brief subject line (50 characters
                                     or less) and, if necessary, a more detailed body separated by a blank line. Use
                                     the imperative mood and reference any relevant issue numbers. Respond only with
                                     the commit message itself, without any additional text or explanation. <git_diff>{gitDiff}</git_diff>
                                     """;
  • The method uses a raw string literal (denoted by """...""") to define the prompt. This approach offers several benefits:
    • Preserves formatting, including line breaks and indentation
    • Eliminates the need for escape characters for quotes or special characters
    • Allows easy embedding of variables (like {gitDiff}) without breaking the string
    • Improves readability, especially for multi-line prompts or those containing code snippets
  1. Choice of "gpt-4o-mini" Model:
ChatClient client = new(model: "gpt-4o-mini", apiKeyCredential);
  • The gpt-4o-mini model is dirt cheap, costing $0.15 per million input tokens
  • for 75 commits the cost was about $1
  • It's quick, suitable for tasks like generating commit messages
  1. The benefit of gpt4o-mini being so quick is we don't need to implement streaming and can use CompleteChatAsync() and simplify our code
ChatCompletion commitMessage = await client.CompleteChatAsync(
    [
        new UserChatMessage(createGitMessagePrompt),
    ]);

4. Implement the GetDiff function

async Task<string?> GetDiff(string? gitRepositoryPath = null)
{
    gitRepositoryPath ??= Environment.CurrentDirectory;
    try
    {
        BufferedCommandResult result = await Cli.Wrap("git") 
            .WithWorkingDirectory(gitRepositoryPath)
            .WithArguments("diff --cached")
            .ExecuteBufferedAsync();
            
        return result.StandardOutput;
    }
    catch (Exception ex)
    {
        Console.Write($"An error occurred while executing `git diff --cached`: {ex.Message}");
        return null;
    }
}

5. Implement the main program flow

string? diffMessage = await GetDiff();

if (string.IsNullOrWhiteSpace(diffMessage)) 
{
    Console.WriteLine("No changes to display.");
    return;
}

ChatCompletion gitCommitMessage = await CreateGitMessage(diffMessage);

Console.WriteLine(gitCommitMessage);

You can find the full code here

6. Run and test the commit message generator

  1. Stage some changes in your git repository.
  2. Run the program from the command line or your IDE.
  3. Review the generated commit message to ensure it accurately summarizes the changes.

By following this step-by-step guide, you should now have a functional commit message generator powered by C# and .NET. Feel free to extend and customize the generator to fit your specific needs and workflow.

Happy coding!