package git import ( "fmt" "strconv" "strings" "time" ) func CompareDiff(base, head, repoDir string) (string, error) { out, err := gitCmd(repoDir, "diff", base+"..."+head) if err != nil { return "", err } return string(out), nil } func CompareCommits(base, head Ref, repoDir string) ([]Commit, error) { format := []string{"%H", "%h", "%s", "%b", "%an", "%ae", "%ad", "%cn", "%ce", "%cd", "%P", "%D"} out, err := gitCmd(repoDir, "log", "--date=unix", "--pretty=format:"+strings.Join(format, "\x1F"), "-z", base.String()+".."+head.String(), ) if err != nil { return nil, err } lines := strings.Split(string(out), "\x00") commits := make([]Commit, 0, len(lines)) for _, line := range lines { if line == "" { continue } parts := strings.Split(line, "\x1F") if len(parts) != len(format) { return nil, fmt.Errorf("unexpected commit format: %s", line) } full, short, subject, body, author, email, date := parts[0], parts[1], parts[2], parts[3], parts[4], parts[5], parts[6] committerName, committerEmail, committerDate, parents, refs := parts[7], parts[8], parts[9], parts[10], parts[11] timestampInt, err := strconv.Atoi(date) if err != nil { return nil, fmt.Errorf("failed to parse commit date: %w", err) } committerTimestampInt, err := strconv.Atoi(committerDate) if err != nil { return nil, fmt.Errorf("failed to parse committer date: %w", err) } commits = append(commits, Commit{ Hash: full, ShortHash: short, Subject: subject, Body: body, Author: author, Email: email, Date: time.Unix(int64(timestampInt), 0), CommitterName: committerName, CommitterEmail: committerEmail, CommitterDate: time.Unix(int64(committerTimestampInt), 0), Parents: strings.Fields(parents), RefNames: parseRefNames(refs), }) } return commits, nil }