1package git
2
3import (
4 "errors"
5 "fmt"
6 "os/exec"
7
8 "github.com/go-git/go-git/v5"
9 "github.com/go-git/go-git/v5/config"
10)
11
12func Fork(repoPath, source string) error {
13 _, err := git.PlainClone(repoPath, true, &git.CloneOptions{
14 URL: source,
15 SingleBranch: false,
16 })
17
18 if err != nil {
19 return fmt.Errorf("failed to bare clone repository: %w", err)
20 }
21
22 err = exec.Command("git", "-C", repoPath, "config", "receive.hideRefs", "refs/hidden").Run()
23 if err != nil {
24 return fmt.Errorf("failed to configure hidden refs: %w", err)
25 }
26
27 return nil
28}
29
30// TrackHiddenRemoteRef tracks a hidden remote in the repository. For example,
31// if the feature branch on the fork (forkRef) is feature-1, and the remoteRef,
32// i.e. the branch we want to merge into, is main, this will result in a refspec:
33//
34// +refs/heads/main:refs/hidden/feature-1/main
35func (g *GitRepo) TrackHiddenRemoteRef(forkRef, remoteRef string) error {
36 fetchOpts := &git.FetchOptions{
37 RefSpecs: []config.RefSpec{
38 config.RefSpec(fmt.Sprintf("+refs/heads/%s:refs/hidden/%s/%s", remoteRef, forkRef, remoteRef)),
39 },
40 RemoteName: "origin",
41 }
42
43 err := g.r.Fetch(fetchOpts)
44 if errors.Is(git.NoErrAlreadyUpToDate, err) {
45 return nil
46 } else if err != nil {
47 return fmt.Errorf("failed to fetch hidden remote: %s: %w", forkRef, err)
48 }
49 return nil
50}