Something went wrong. Try again.
A command-line interface for tangled, the decentralized Git collaboration platform built on the AT Protocol. eric-wien.tngl.io/tng-cli
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132package git
import ( "bytes" "fmt" "os/exec" "strings")
// Client wraps git CLI operations.type Client struct { // Path to the git binary. GitPath string // Working directory for git commands. RepoDir string}
// NewClient creates a git client for the current directory.func NewClient() *Client { return &Client{ GitPath: "git", RepoDir: ".", }}
// CurrentBranch returns the name of the current HEAD branch.func (c *Client) CurrentBranch() (string, error) { out, err := c.run("rev-parse", "--abbrev-ref", "HEAD") if err != nil { return "", err } branch := strings.TrimSpace(out) if branch == "HEAD" { return "", fmt.Errorf("not on any branch (detached HEAD)") } return branch, nil}
// Remotes returns the list of configured remotes with their URLs.func (c *Client) Remotes() ([]Remote, error) { out, err := c.run("remote", "-v") if err != nil { return nil, err } return ParseRemotes(out), nil}
// Config reads a git config value.func (c *Client) Config(key string) (string, error) { out, err := c.run("config", "--get", key) if err != nil { return "", err } return strings.TrimSpace(out), nil}
// Clone clones a repository. Options go before the "--" separator so a URL or// directory starting with "-" can't be parsed as a git flag.func (c *Client) Clone(url string, dir string, args ...string) error { cmdArgs := append([]string{"clone"}, args...) cmdArgs = append(cmdArgs, "--", url) if dir != "" { cmdArgs = append(cmdArgs, dir) } _, err := c.runGlobal(cmdArgs...) return err}
// IsInsideWorkTree returns true if the current directory is inside a git repo.func (c *Client) IsInsideWorkTree() bool { out, err := c.run("rev-parse", "--is-inside-work-tree") return err == nil && strings.TrimSpace(out) == "true"}
// TopLevelDir returns the root directory of the git repo.func (c *Client) TopLevelDir() (string, error) { out, err := c.run("rev-parse", "--show-toplevel") if err != nil { return "", err } return strings.TrimSpace(out), nil}
func (c *Client) run(args ...string) (string, error) { cmd := exec.Command(c.GitPath, args...) cmd.Dir = c.RepoDir var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { return "", fmt.Errorf("git %s: %w\n%s", args[0], err, stderr.String()) } return stdout.String(), nil}
// FormatPatch generates a format-patch from the given base ref to HEAD.func (c *Client) FormatPatch(base string) ([]byte, error) { // The base ref lands in git argv; reject flag-like values (argument injection). if strings.HasPrefix(base, "-") { return nil, fmt.Errorf("invalid base ref %q", base) } cmd := exec.Command(c.GitPath, "format-patch", "--stdout", base+"..HEAD") cmd.Dir = c.RepoDir var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { return nil, fmt.Errorf("git format-patch: %w\n%s", err, stderr.String()) } return stdout.Bytes(), nil}
// RevParse returns the SHA for a given ref.func (c *Client) RevParse(ref string) (string, error) { out, err := c.run("rev-parse", ref) if err != nil { return "", err } return strings.TrimSpace(out), nil}
func (c *Client) runGlobal(args ...string) (string, error) { cmd := exec.Command(c.GitPath, args...) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr if err := cmd.Run(); err != nil { return "", fmt.Errorf("git %s: %w\n%s", args[0], err, stderr.String()) } return stdout.String(), nil}