Created
March 7, 2025 14:03
-
-
Save vicendominguez/3eb49986627a378388dfa7e62acf38df to your computer and use it in GitHub Desktop.
AI git commit message and code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bytes" | |
"encoding/json" | |
"fmt" | |
"net/http" | |
"strings" | |
"time" | |
"github.com/go-git/go-git/v5" | |
"github.com/go-git/go-git/v5/config" | |
"github.com/go-git/go-git/v5/plumbing" | |
"github.com/go-git/go-git/v5/plumbing/object" | |
"github.com/pterm/pterm" | |
) | |
func main() { | |
// Open the current repository | |
repo, err := git.PlainOpen(".") | |
if err != nil { | |
pterm.Error.Printf("Error opening the repository: %v\n", err) | |
return | |
} | |
// Get the current branch name | |
branchName, err := getCurrentBranch(repo) | |
if err != nil { | |
pterm.Error.Printf("Error: %v\n", err) | |
pterm.Info.Println("Please create a branch first using 'git branch <branch-name>'.") | |
return | |
} | |
// Get the diff of changes in the staging area | |
diff, err := getGitDiffCached(repo) | |
if err != nil { | |
pterm.Error.Printf("Error getting the cached diff: %v\n", err) | |
return | |
} | |
// Generate the commit message using Ollama | |
commitMessage, err := generateCommitMessage(diff) | |
if err != nil { | |
pterm.Error.Printf("Error generating the commit message: %v\n", err) | |
return | |
} | |
// Add the branch name to the commit message | |
fullCommitMessage := fmt.Sprintf("[%s] %s", branchName, commitMessage) | |
// Create the commit | |
err = createGitCommit(repo, fullCommitMessage) | |
if err != nil { | |
pterm.Error.Printf("Error creating the commit: %v\n", err) | |
return | |
} | |
pterm.Success.Printf("Commit created successfully: %s\n", fullCommitMessage) | |
} | |
// Get the current branch name | |
func getCurrentBranch(repo *git.Repository) (string, error) { | |
ref, err := repo.Head() | |
if err != nil { | |
// Si el repositorio está vacío (no hay commits), devuelve un error | |
if err == plumbing.ErrReferenceNotFound { | |
return "", fmt.Errorf("no commits found (repository is empty)") | |
} | |
return "", err | |
} | |
// Verifica si HEAD apunta a una rama | |
if !ref.Name().IsBranch() { | |
return "", fmt.Errorf("HEAD is not pointing to a branch") | |
} | |
return ref.Name().Short(), nil | |
} | |
// Get the diff of changes in the staging area | |
func getGitDiffCached(repo *git.Repository) (string, error) { | |
worktree, err := repo.Worktree() | |
if err != nil { | |
return "", err | |
} | |
// Get the working tree status | |
status, err := worktree.Status() | |
if err != nil { | |
return "", err | |
} | |
// Simulate a diff (go-git does not have a direct method for `git diff --cached`) | |
var diffBuilder strings.Builder | |
for file, status := range status { | |
if status.Staging != git.Unmodified { | |
diffBuilder.WriteString(fmt.Sprintf("File: %s, Changes: %b\n", file, status.Staging)) | |
} | |
} | |
return diffBuilder.String(), nil | |
} | |
// Generate the commit message using Ollama | |
func generateCommitMessage(diff string) (string, error) { | |
// URL of the Ollama API (replace this with the correct URL) | |
apiURL := "http://localhost:11434/api/generate" | |
model := "llama3.1" | |
// Create the request body | |
requestBody, err := json.Marshal(map[string]interface{}{ | |
"model": model, | |
"prompt": "Analyze the following code diff and generate a summarized and concise commit message that describes the changes made. Include only the commit message itself, without any introduction or conclusion. Diff:\n" + diff, | |
"stream": false, | |
}) | |
if err != nil { | |
return "", fmt.Errorf("error creating the request body: %v", err) | |
} | |
// Send the HTTP POST request to Ollama | |
resp, err := http.Post(apiURL, "application/json", bytes.NewBuffer(requestBody)) | |
if err != nil { | |
return "", fmt.Errorf("error sending the request to Ollama: %v", err) | |
} | |
defer resp.Body.Close() | |
// Check the response status code | |
if resp.StatusCode != http.StatusOK { | |
return "", fmt.Errorf("unsuccessful response from Ollama: %s", resp.Status) | |
} | |
var result map[string]interface{} | |
err = json.NewDecoder(resp.Body).Decode(&result) | |
if err != nil { | |
return "", fmt.Errorf("error decoding the response from Ollama: %v", err) | |
} | |
// Get the generated commit message | |
commitMessage, ok := result["response"].(string) | |
if !ok { | |
return "", fmt.Errorf("the response from Ollama does not contain a commit message") | |
} | |
return commitMessage, nil | |
} | |
// Create the commit | |
func createGitCommit(repo *git.Repository, message string) error { | |
worktree, err := repo.Worktree() | |
if err != nil { | |
return err | |
} | |
// Add all changes to the staging area | |
_, err = worktree.Add(".") | |
if err != nil { | |
return err | |
} | |
// Obtener la configuración global y local | |
globalCfg, err := repo.ConfigScoped(config.GlobalScope) | |
if err != nil { | |
return fmt.Errorf("error reading global Git configuration: %v", err) | |
} | |
localCfg, err := repo.ConfigScoped(config.LocalScope) | |
if err != nil { | |
return fmt.Errorf("error reading local Git configuration: %v", err) | |
} | |
// Combinar las configuraciones: priorizar la configuración local sobre la global | |
userName := localCfg.User.Name | |
if userName == "" { | |
userName = globalCfg.User.Name | |
} | |
userEmail := localCfg.User.Email | |
if userEmail == "" { | |
userEmail = globalCfg.User.Email | |
} | |
if userName == "" || userEmail == "" { | |
return fmt.Errorf("user name or email not found in Git configuration") | |
} | |
now := time.Now() | |
// Create the commit | |
commit, err := worktree.Commit(message, &git.CommitOptions{ | |
Author: &object.Signature{ | |
Name: userName, | |
Email: userEmail, | |
When: now, | |
}, | |
}) | |
if err != nil { | |
return err | |
} | |
// Print the hash of the created commit | |
pterm.Info.Printf("Commit created with hash: %s\n", commit.String()) | |
return nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment