Skip to content

Commit 0821303

Browse files
authored
Merge pull request #266 from zachwhaley/shallow-tag-clone
Let shallow clone work with any ref
2 parents 95deff2 + d39dd15 commit 0821303

File tree

2 files changed

+71
-3
lines changed

2 files changed

+71
-3
lines changed

get_git.go

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type GitGetter struct {
2727
}
2828

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

3132
func (g *GitGetter) ClientMode(_ *url.URL) (ClientMode, error) {
3233
return ClientModeDir, nil
@@ -114,7 +115,7 @@ func (g *GitGetter) Get(dst string, u *url.URL) error {
114115
if err == nil {
115116
err = g.update(ctx, dst, sshKeyFile, ref, depth)
116117
} else {
117-
err = g.clone(ctx, dst, sshKeyFile, u, depth)
118+
err = g.clone(ctx, dst, sshKeyFile, u, ref, depth)
118119
}
119120
if err != nil {
120121
return err
@@ -166,14 +167,17 @@ func (g *GitGetter) checkout(dst string, ref string) error {
166167
return getRunCommand(cmd)
167168
}
168169

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

173+
if ref == "" {
174+
ref = findRemoteDefaultBranch(u)
175+
}
172176
if depth > 0 {
173177
args = append(args, "--depth", strconv.Itoa(depth))
174178
}
175179

176-
args = append(args, u.String(), dst)
180+
args = append(args, "--branch", ref, u.String(), dst)
177181
cmd := exec.CommandContext(ctx, "git", args...)
178182
setupGitEnv(cmd, sshKeyFile)
179183
return getRunCommand(cmd)
@@ -236,6 +240,20 @@ func findDefaultBranch(dst string) string {
236240
return matches[len(matches)-1]
237241
}
238242

243+
// findRemoteDefaultBranch checks the remote repo's HEAD symref to return the remote repo's
244+
// default branch. "master" is returned if no HEAD symref exists.
245+
func findRemoteDefaultBranch(u *url.URL) string {
246+
var stdoutbuf bytes.Buffer
247+
cmd := exec.Command("git", "ls-remote", "--symref", u.String(), "HEAD")
248+
cmd.Stdout = &stdoutbuf
249+
err := cmd.Run()
250+
matches := lsRemoteSymRefRegexp.FindStringSubmatch(stdoutbuf.String())
251+
if err != nil || matches == nil {
252+
return "master"
253+
}
254+
return matches[len(matches)-1]
255+
}
256+
239257
// setupGitEnv sets up the environment for the given command. This is used to
240258
// pass configuration data to git and ssh and enables advanced cloning methods.
241259
func setupGitEnv(cmd *exec.Cmd, sshKeyFile string) {

get_git_test.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,56 @@ func TestGitGetter_shallowClone(t *testing.T) {
162162
}
163163
}
164164

165+
func TestGitGetter_shallowCloneWithTag(t *testing.T) {
166+
if !testHasGit {
167+
t.Log("git not found, skipping")
168+
t.Skip()
169+
}
170+
171+
g := new(GitGetter)
172+
dst := tempDir(t)
173+
174+
repo := testGitRepo(t, "upstream")
175+
repo.commitFile("v1.0.txt", "0")
176+
repo.git("tag", "v1.0")
177+
repo.commitFile("v1.1.txt", "1")
178+
179+
// Specifiy a clone depth of 1 with a tag
180+
q := repo.url.Query()
181+
q.Add("ref", "v1.0")
182+
q.Add("depth", "1")
183+
repo.url.RawQuery = q.Encode()
184+
185+
if err := g.Get(dst, repo.url); err != nil {
186+
t.Fatalf("err: %s", err)
187+
}
188+
189+
// Assert rev-list count is '1'
190+
cmd := exec.Command("git", "rev-list", "HEAD", "--count")
191+
cmd.Dir = dst
192+
b, err := cmd.Output()
193+
if err != nil {
194+
t.Fatalf("err: %s", err)
195+
}
196+
197+
out := strings.TrimSpace(string(b))
198+
if out != "1" {
199+
t.Fatalf("expected rev-list count to be '1' but got %v", out)
200+
}
201+
202+
// Verify the v1.0 file exists
203+
mainPath := filepath.Join(dst, "v1.0.txt")
204+
if _, err := os.Stat(mainPath); err != nil {
205+
t.Fatalf("err: %s", err)
206+
}
207+
208+
// Verify the v1.1 file does not exists
209+
mainPath = filepath.Join(dst, "v1.1.txt")
210+
if _, err := os.Stat(mainPath); err == nil {
211+
t.Fatalf("expected v1.1 file to not exist")
212+
}
213+
}
214+
165215
func TestGitGetter_branchUpdate(t *testing.T) {
166216
if !testHasGit {
167217
t.Skip("git not found, skipping")

0 commit comments

Comments
 (0)