summaryrefslogtreecommitdiff
path: root/internal/git
diff options
context:
space:
mode:
authormo khan <mo@mokhan.ca>2026-01-30 23:42:28 -0700
committermo khan <mo@mokhan.ca>2026-01-30 23:42:28 -0700
commit1bbe5e40640b39b7a08e4b9bcf08f7fdbdbb2f0a (patch)
tree2e30ddd0cb8ad61059a6d8acd8307fa4f28d9050 /internal/git
parentbbcd6c6d62f3befb58feddfa16513a5cd4c00473 (diff)
refactor: return err instead of panic and use errgroup
Diffstat (limited to 'internal/git')
-rw-r--r--internal/git/git.go89
1 files changed, 30 insertions, 59 deletions
diff --git a/internal/git/git.go b/internal/git/git.go
index 96856c3..41031e4 100644
--- a/internal/git/git.go
+++ b/internal/git/git.go
@@ -11,14 +11,25 @@ import (
"time"
)
-func Branches(repoDir string) ([]Ref, error) {
- cmd := exec.Command("git", "for-each-ref", "--format=%(refname:short)", "refs/heads/")
+func gitCmd(repoDir string, args ...string) ([]byte, error) {
+ cmd := exec.Command("git", args...)
if repoDir != "" {
cmd.Dir = repoDir
}
out, err := cmd.Output()
if err != nil {
- return nil, fmt.Errorf("failed to list branches: %w", err)
+ if ee, ok := err.(*exec.ExitError); ok {
+ return nil, fmt.Errorf("git %s: %w: %s", args[0], err, ee.Stderr)
+ }
+ return nil, err
+ }
+ return out, nil
+}
+
+func Branches(repoDir string) ([]Ref, error) {
+ out, err := gitCmd(repoDir, "for-each-ref", "--format=%(refname:short)", "refs/heads/")
+ if err != nil {
+ return nil, err
}
lines := strings.Split(string(out), "\n")
branches := make([]Ref, 0, len(lines))
@@ -33,24 +44,19 @@ func Branches(repoDir string) ([]Ref, error) {
func Tags(repoDir string) ([]Tag, error) {
format := []string{
- "%(refname:short)", // tag name
- "%(creatordate:unix)", // creation date
- "%(objectname)", // commit hash for lightweight tags
- "%(*objectname)", // peeled object => commit hash
+ "%(refname:short)",
+ "%(creatordate:unix)",
+ "%(objectname)",
+ "%(*objectname)",
}
- args := []string{
+ out, err := gitCmd(repoDir,
"for-each-ref",
"--sort=-creatordate",
- "--format=" + strings.Join(format, "%00"),
+ "--format="+strings.Join(format, "%00"),
"refs/tags",
- }
- cmd := exec.Command("git", args...)
- if repoDir != "" {
- cmd.Dir = repoDir
- }
- out, err := cmd.Output()
+ )
if err != nil {
- return nil, fmt.Errorf("failed to list tags: %w", err)
+ return nil, err
}
lines := strings.Split(strings.TrimSpace(string(out)), "\n")
@@ -194,52 +200,22 @@ func BlobContent(ref Ref, path string, repoDir string) ([]byte, bool, error) {
if ref.IsEmpty() {
ref = NewRef("HEAD")
}
- // Use `git show ref:path` to get the blob content at that ref
- cmd := exec.Command("git", "show", ref.String()+":"+path)
- if repoDir != "" {
- cmd.Dir = repoDir
- }
- out, err := cmd.Output()
+ out, err := gitCmd(repoDir, "show", ref.String()+":"+path)
if err != nil {
- // include stderr if available
- if ee, ok := err.(*exec.ExitError); ok {
- return nil, false, fmt.Errorf("git show failed: %v: %s", err, string(ee.Stderr))
- }
- return nil, false, fmt.Errorf("git show failed: %w", err)
+ return nil, false, err
}
return out, IsBinary(out), nil
}
func Commits(ref Ref, repoDir string) ([]Commit, error) {
- format := []string{
- "%H", // commit hash
- "%h", // abbreviated commit hash
- "%s", // subject
- "%b", // body
- "%an", // author name
- "%ae", // author email
- "%ad", // author date
- "%cn", // committer name
- "%ce", // committer email
- "%cd", // committer date
- "%P", // parent hashes
- "%D", // ref names without the "(", ")" wrapping.
- }
-
- args := []string{
+ 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", // Separate the commits with NULs instead of newlines
+ "--pretty=format:"+strings.Join(format, "\x1F"),
+ "-z",
ref.String(),
- }
-
- cmd := exec.Command("git", args...)
- if repoDir != "" {
- cmd.Dir = repoDir
- }
-
- out, err := cmd.Output()
+ )
if err != nil {
return nil, err
}
@@ -347,12 +323,7 @@ func parseRefNames(refNames string) []RefName {
}
func CommitDiff(hash, repoDir string) (string, error) {
- // unified diff without a commit header
- cmd := exec.Command("git", "show", "--pretty=format:", "--patch", hash)
- if repoDir != "" {
- cmd.Dir = repoDir
- }
- out, err := cmd.Output()
+ out, err := gitCmd(repoDir, "show", "--pretty=format:", "--patch", hash)
if err != nil {
return "", err
}