package git import ( "errors" "fmt" "os/exec" "github.com/go-git/go-git/v5" "github.com/go-git/go-git/v5/config" ) func Fork(repoPath, source string) error { cloneCmd := exec.Command("git", "clone", "--bare", source, repoPath) if err := cloneCmd.Run(); err != nil { return fmt.Errorf("failed to bare clone repository: %w", err) } configureCmd := exec.Command("git", "-C", repoPath, "config", "receive.hideRefs", "refs/hidden") if err := configureCmd.Run(); err != nil { return fmt.Errorf("failed to configure hidden refs: %w", err) } return nil } func (g *GitRepo) Sync() error { branch := g.h.String() fetchOpts := &git.FetchOptions{ RefSpecs: []config.RefSpec{ config.RefSpec("+" + branch + ":" + branch), // +refs/heads/master:refs/heads/master }, } err := g.r.Fetch(fetchOpts) if errors.Is(git.NoErrAlreadyUpToDate, err) { return nil } else if err != nil { return fmt.Errorf("failed to fetch origin branch: %s: %w", branch, err) } return nil } // TrackHiddenRemoteRef tracks a hidden remote in the repository. For example, // if the feature branch on the fork (forkRef) is feature-1, and the remoteRef, // i.e. the branch we want to merge into, is main, this will result in a refspec: // // +refs/heads/main:refs/hidden/feature-1/main func (g *GitRepo) TrackHiddenRemoteRef(forkRef, remoteRef string) error { fetchOpts := &git.FetchOptions{ RefSpecs: []config.RefSpec{ config.RefSpec(fmt.Sprintf("+refs/heads/%s:refs/hidden/%s/%s", remoteRef, forkRef, remoteRef)), }, RemoteName: "origin", } err := g.r.Fetch(fetchOpts) if errors.Is(git.NoErrAlreadyUpToDate, err) { return nil } else if err != nil { return fmt.Errorf("failed to fetch hidden remote: %s: %w", forkRef, err) } return nil }