package gitutil import ( "fmt" "os/exec" "strings" "time" "gitocean/internal/model" "gitocean/internal/validate" ) func Run(dir string, args ...string) error { cmd := exec.Command("git", args...) if dir != "" { cmd.Dir = dir } out, err := cmd.CombinedOutput() if err != nil { return fmt.Errorf("git %s failed: %s", strings.Join(args, " "), strings.TrimSpace(string(out))) } return nil } func InitBare(path string) error { if err := Run("", "init", "--bare", path); err != nil { return err } return Run("", "--git-dir", path, "symbolic-ref", "HEAD", "refs/heads/main") } func BranchExists(repoPath, branch string) bool { if !validate.Branch(branch) { return false } cmd := exec.Command("git", "--git-dir", repoPath, "rev-parse", "--verify", "refs/heads/"+branch) return cmd.Run() == nil } func Refs(repoPath, prefix string) ([]model.RefInfo, error) { cmd := exec.Command("git", "--git-dir", repoPath, "for-each-ref", "--format=%(refname:short)%00%(objectname)%00%(committerdate:iso8601)%00%(subject)", prefix) out, err := cmd.CombinedOutput() if err != nil { return nil, fmt.Errorf("git refs failed: %s", strings.TrimSpace(string(out))) } var refs []model.RefInfo for _, line := range strings.Split(strings.TrimSpace(string(out)), "\n") { if line == "" { continue } parts := strings.SplitN(line, "\x00", 4) if len(parts) < 4 { continue } date, _ := time.Parse("2006-01-02 15:04:05 -0700", parts[2]) refs = append(refs, model.RefInfo{Name: parts[0], Commit: parts[1], Date: date, Message: parts[3]}) } return refs, nil }