package git import ( "fmt" "os/exec" "path/filepath" "strings" ) type RepoInfo struct { Root string DefaultBranch string Remote string } func Inspect(path string) (RepoInfo, error) { abs, err := filepath.Abs(path) if err != nil { return RepoInfo{}, err } root, err := run(abs, "rev-parse", "--show-toplevel") if err != nil { return RepoInfo{}, err } root, err = filepath.EvalSymlinks(root) if err != nil { return RepoInfo{}, err } abs, err = filepath.EvalSymlinks(abs) if err != nil { return RepoInfo{}, err } if root != abs { return RepoInfo{}, fmt.Errorf("%s is inside the repo at %s; register the repo root", abs, root) } branch, err := run(root, "symbolic-ref", "--short", "HEAD") if err != nil { return RepoInfo{}, err } remote, err := run(root, "remote", "get-url", "origin") if err != nil { return RepoInfo{}, err } return RepoInfo{Root: root, DefaultBranch: branch, Remote: remote}, nil } func AddWorktree(repo, path, branch, base string) (string, error) { sha, err := run(repo, "rev-parse", "--verify", base+"^{commit}") if err != nil { return "", err } _, err = run(repo, "worktree", "add", "-b", branch, path, sha) if err != nil { return "", err } return sha, nil } func RemoveWorktree(repo, path, branch string) error { _, err := run(repo, "worktree", "remove", "--force", path) if err != nil { return err } _, err = run(repo, "branch", "-D", branch) return err } func run(dir string, args ...string) (string, error) { cmd := exec.Command("git", args...) cmd.Dir = dir out, err := cmd.CombinedOutput() if err != nil { return "", fmt.Errorf("git %s: %w: %s", strings.Join(args, " "), err, strings.TrimSpace(string(out))) } return strings.TrimSpace(string(out)), nil }