package git import ( "context" "errors" "fmt" "strings" "time" ) const HeadTimeout = 15 * time.Second func RemoteHead(ctx context.Context, runner CommandRunner, homeDir, proxyAddr, sourceURL string) (string, error) { ctx, cancel := context.WithTimeout(ctx, HeadTimeout) defer cancel() // the source host is caller-supplied, so the only guard on where ls-remote connects is the // connect proxy resolving it against the blocked ranges; empty askpass avoids hanging on prompts env := HardenedGitEnv(proxyAddr, "", homeDir, "", "") output, err := runner.Run(ctx, "", env, "git", "ls-remote", "--symref", sourceURL, "HEAD") if err != nil { return "", fmt.Errorf("ls-remote: %w", err) } return ParseSymrefHead(output) } func ParseSymrefHead(output string) (string, error) { for _, line := range strings.Split(output, "\n") { rest, ok := strings.CutPrefix(line, "ref: ") if !ok { continue } ref, head, ok := strings.Cut(rest, "\t") if !ok || head != "HEAD" { continue } branch, ok := strings.CutPrefix(ref, "refs/heads/") if !ok || branch == "" { return "", errors.New("remote HEAD does not point at a branch: " + ref) } return branch, nil } return "", errors.New("ls-remote output has no symref for HEAD") }