package git import ( "context" "fmt" "strings" ) // PrepareTaggedCheckout fetches one explicit tag ref, checks its peeled commit // against expectedCommit, and checks out that commit detached. func PrepareTaggedCheckout(ctx context.Context, repositoryDir, version, remote, expectedCommit string) error { if !validVersionRef(version) || !validObjectID(expectedCommit) { return fmt.Errorf("invalid tagged checkout identity %q at %q", expectedCommit, version) } ref := "refs/tags/" + version if _, err := run(ctx, repositoryDir, nil, "fetch", "--no-tags", remote, ref+":"+ref); err != nil { return fmt.Errorf("fetch tag %s from remote %s: %w", version, remote, err) } source, err := InspectTaggedSource(ctx, repositoryDir, version) if err != nil { return err } if !strings.EqualFold(source.TagCommit, expectedCommit) { return fmt.Errorf("tag %s resolves to commit %s, expected %s", version, source.TagCommit, expectedCommit) } if _, err := run(ctx, repositoryDir, nil, "checkout", "--detach", source.TagCommit); err != nil { return fmt.Errorf("check out tag %s at %s: %w", version, source.TagCommit, err) } head, err := run(ctx, repositoryDir, nil, "rev-parse", "--verify", "HEAD^{commit}") if err != nil { return fmt.Errorf("verify prepared checkout HEAD: %w", err) } if !strings.EqualFold(strings.TrimSpace(head), expectedCommit) { return fmt.Errorf("prepared checkout HEAD is %s, expected %s", strings.TrimSpace(head), expectedCommit) } return nil }