Skip to content

Commit

Permalink
Merge pull request #266 from zachwhaley/shallow-tag-clone
Browse files Browse the repository at this point in the history
Let shallow clone work with any ref
  • Loading branch information
schmichael authored Oct 4, 2021
2 parents 95deff2 + d39dd15 commit 0821303
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 3 deletions.
24 changes: 21 additions & 3 deletions get_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ type GitGetter struct {
}

var defaultBranchRegexp = regexp.MustCompile(`\s->\sorigin/(.*)`)
var lsRemoteSymRefRegexp = regexp.MustCompile(`ref: refs/heads/([^\s]+).*`)

func (g *GitGetter) ClientMode(_ *url.URL) (ClientMode, error) {
return ClientModeDir, nil
Expand Down Expand Up @@ -114,7 +115,7 @@ func (g *GitGetter) Get(dst string, u *url.URL) error {
if err == nil {
err = g.update(ctx, dst, sshKeyFile, ref, depth)
} else {
err = g.clone(ctx, dst, sshKeyFile, u, depth)
err = g.clone(ctx, dst, sshKeyFile, u, ref, depth)
}
if err != nil {
return err
Expand Down Expand Up @@ -166,14 +167,17 @@ func (g *GitGetter) checkout(dst string, ref string) error {
return getRunCommand(cmd)
}

func (g *GitGetter) clone(ctx context.Context, dst, sshKeyFile string, u *url.URL, depth int) error {
func (g *GitGetter) clone(ctx context.Context, dst, sshKeyFile string, u *url.URL, ref string, depth int) error {
args := []string{"clone"}

if ref == "" {
ref = findRemoteDefaultBranch(u)
}
if depth > 0 {
args = append(args, "--depth", strconv.Itoa(depth))
}

args = append(args, u.String(), dst)
args = append(args, "--branch", ref, u.String(), dst)
cmd := exec.CommandContext(ctx, "git", args...)
setupGitEnv(cmd, sshKeyFile)
return getRunCommand(cmd)
Expand Down Expand Up @@ -236,6 +240,20 @@ func findDefaultBranch(dst string) string {
return matches[len(matches)-1]
}

// findRemoteDefaultBranch checks the remote repo's HEAD symref to return the remote repo's
// default branch. "master" is returned if no HEAD symref exists.
func findRemoteDefaultBranch(u *url.URL) string {
var stdoutbuf bytes.Buffer
cmd := exec.Command("git", "ls-remote", "--symref", u.String(), "HEAD")
cmd.Stdout = &stdoutbuf
err := cmd.Run()
matches := lsRemoteSymRefRegexp.FindStringSubmatch(stdoutbuf.String())
if err != nil || matches == nil {
return "master"
}
return matches[len(matches)-1]
}

// setupGitEnv sets up the environment for the given command. This is used to
// pass configuration data to git and ssh and enables advanced cloning methods.
func setupGitEnv(cmd *exec.Cmd, sshKeyFile string) {
Expand Down
50 changes: 50 additions & 0 deletions get_git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,56 @@ func TestGitGetter_shallowClone(t *testing.T) {
}
}

func TestGitGetter_shallowCloneWithTag(t *testing.T) {
if !testHasGit {
t.Log("git not found, skipping")
t.Skip()
}

g := new(GitGetter)
dst := tempDir(t)

repo := testGitRepo(t, "upstream")
repo.commitFile("v1.0.txt", "0")
repo.git("tag", "v1.0")
repo.commitFile("v1.1.txt", "1")

// Specifiy a clone depth of 1 with a tag
q := repo.url.Query()
q.Add("ref", "v1.0")
q.Add("depth", "1")
repo.url.RawQuery = q.Encode()

if err := g.Get(dst, repo.url); err != nil {
t.Fatalf("err: %s", err)
}

// Assert rev-list count is '1'
cmd := exec.Command("git", "rev-list", "HEAD", "--count")
cmd.Dir = dst
b, err := cmd.Output()
if err != nil {
t.Fatalf("err: %s", err)
}

out := strings.TrimSpace(string(b))
if out != "1" {
t.Fatalf("expected rev-list count to be '1' but got %v", out)
}

// Verify the v1.0 file exists
mainPath := filepath.Join(dst, "v1.0.txt")
if _, err := os.Stat(mainPath); err != nil {
t.Fatalf("err: %s", err)
}

// Verify the v1.1 file does not exists
mainPath = filepath.Join(dst, "v1.1.txt")
if _, err := os.Stat(mainPath); err == nil {
t.Fatalf("expected v1.1 file to not exist")
}
}

func TestGitGetter_branchUpdate(t *testing.T) {
if !testHasGit {
t.Skip("git not found, skipping")
Expand Down

0 comments on commit 0821303

Please sign in to comment.