Skip to content

Commit 8092e09

Browse files
author
John Nelson
authored
fix: correctly deepen shallows (#19)
* feat: unshallow, manage shallow after fetch * stop fetching tags in some tests * undo some unnecessary changes * cache shallows before iterating, clarify logic * just use the presence of key to infer whether a commit is shallow * remove pruneShallow; use server response to manage shallow/unshallow * cleanup * cleanup
1 parent 7fb3891 commit 8092e09

File tree

3 files changed

+109
-24
lines changed

3 files changed

+109
-24
lines changed

remote.go

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -755,14 +755,28 @@ func doCalculateRefs(
755755

756756
func getWants(localStorer storage.Storer, refs memory.ReferenceStorage) ([]plumbing.Hash, error) {
757757
wants := map[plumbing.Hash]bool{}
758+
759+
shallows, err := localStorer.Shallow()
760+
if err != nil {
761+
return nil, err
762+
}
763+
shallowCommits := map[plumbing.Hash]bool{}
764+
for _, shallow := range shallows {
765+
shallowCommits[shallow] = true
766+
}
767+
758768
for _, ref := range refs {
759769
hash := ref.Hash()
760770
exists, err := objectExists(localStorer, ref.Hash())
761771
if err != nil {
762772
return nil, err
763773
}
764774

765-
if !exists {
775+
if exists {
776+
if _, isShallow := shallowCommits[hash]; isShallow {
777+
wants[hash] = true
778+
}
779+
} else {
766780
wants[hash] = true
767781
}
768782
}
@@ -1105,22 +1119,29 @@ func pushHashes(
11051119
}
11061120

11071121
func (r *Remote) updateShallow(o *FetchOptions, resp *packp.UploadPackResponse) error {
1108-
if o.Depth == 0 || len(resp.Shallows) == 0 {
1122+
if o.Depth == 0 || len(resp.Shallows)+len(resp.Unshallows) == 0 {
11091123
return nil
11101124
}
11111125

1112-
shallows, err := r.s.Shallow()
1126+
shallowUpdates := map[plumbing.Hash]bool{}
1127+
for _, s := range resp.Unshallows {
1128+
shallowUpdates[s] = false
1129+
}
1130+
1131+
currentShallows, err := r.s.Shallow()
11131132
if err != nil {
11141133
return err
11151134
}
11161135

1117-
outer:
1118-
for _, s := range resp.Shallows {
1119-
for _, oldS := range shallows {
1120-
if s == oldS {
1121-
continue outer
1122-
}
1136+
shallows := []plumbing.Hash{}
1137+
1138+
// filter out the SHAs that are unshallowed, and only include each
1139+
// shallow commit once
1140+
for _, s := range append(currentShallows, resp.Shallows...) {
1141+
if _, ok := shallowUpdates[s]; ok {
1142+
continue
11231143
}
1144+
shallowUpdates[s] = true
11241145
shallows = append(shallows, s)
11251146
}
11261147

remote_test.go

Lines changed: 78 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ func (s *RemoteSuite) TestFetchWithDepth(c *C) {
190190
plumbing.NewReferenceFromStrings("refs/tags/v1.0.0", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
191191
})
192192

193+
s.assertShallows(c, r, 2)
194+
193195
c.Assert(r.s.(*memory.Storage).Objects, HasLen, 18)
194196
}
195197

@@ -203,10 +205,13 @@ func (s *RemoteSuite) TestFetchWithHashes(c *C) {
203205
Hashes: []plumbing.Hash{
204206
plumbing.NewHash("6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
205207
},
208+
Tags: NoTags,
206209
}, nil)
207210

208211
commits := r.s.(*memory.Storage).Commits
209212
c.Assert(commits, HasLen, 1)
213+
214+
s.assertShallows(c, r, 1)
210215
}
211216

212217
func (s *RemoteSuite) TestFetchWithHashesInShallow(c *C) {
@@ -230,8 +235,11 @@ func (s *RemoteSuite) TestFetchWithHashesInShallow(c *C) {
230235
Hashes: []plumbing.Hash{
231236
headHash,
232237
},
238+
Tags: NoTags,
233239
}, nil)
234240

241+
s.assertShallows(c, r, 1)
242+
235243
// Control we did get it
236244
commits := r.s.(*memory.Storage).Commits
237245
c.Assert(commits, HasLen, 1)
@@ -241,19 +249,71 @@ func (s *RemoteSuite) TestFetchWithHashesInShallow(c *C) {
241249
// We now fetch an older SHA
242250
s.testFetch(c, r, &FetchOptions{
243251
Depth: 1,
244-
RefSpecs: []config.RefSpec{
245-
config.RefSpec("+refs/heads/master:refs/remotes/origin/master"),
246-
},
247252
Hashes: []plumbing.Hash{
248253
olderHash,
249254
},
255+
Tags: NoTags,
250256
}, nil)
251257

252258
// Control we did get it
253259
commits = r.s.(*memory.Storage).Commits
254260
c.Assert(commits, HasLen, 2)
255261
_, err = object.GetCommit(r.s, olderHash)
256262
c.Assert(err, IsNil)
263+
264+
// NOTE: the server doesn't emit an `unshallow` packet line in
265+
// this scenario, so it won't know to update the list of shallow
266+
// commits. This is consistent with git cli.
267+
s.assertShallows(c, r, 2)
268+
}
269+
270+
func (s *RemoteSuite) TestFetchShallowBranchHeadThenFetchUnshallowBranch(c *C) {
271+
r := NewRemote(memory.NewStorage(), &config.RemoteConfig{
272+
URLs: []string{s.GetBasicLocalRepositoryURL()},
273+
})
274+
275+
// We first need to set the right capabilities otherwise we can't fetch
276+
// the commit we want
277+
p := filepath.Join(r.c.URLs[0], "config")
278+
cfgCmd := exec.Command("git", "config", "--file", p, "--bool", "uploadpack.allowAnySHA1InWant", "true")
279+
err := cfgCmd.Run()
280+
c.Assert(err, IsNil)
281+
282+
headHash := plumbing.NewHash("e8d3ffab552895c19b9fcf7aa264d277cde33881")
283+
firstHash := plumbing.NewHash("b029517f6300c2da0f4b651b8642506cd6aaf45d")
284+
285+
// We start by fetching the HEAD
286+
s.testFetch(c, r, &FetchOptions{
287+
Depth: 1,
288+
Hashes: []plumbing.Hash{
289+
headHash,
290+
},
291+
}, nil)
292+
293+
// Control we did get it
294+
commits := r.s.(*memory.Storage).Commits
295+
c.Assert(commits, HasLen, 1)
296+
_, err = object.GetCommit(r.s, headHash)
297+
c.Assert(err, IsNil)
298+
299+
// Fetch the branch where our shallow commit is the head of the branch
300+
s.testFetch(c, r, &FetchOptions{
301+
Depth: 2147483647,
302+
RefSpecs: []config.RefSpec{
303+
config.RefSpec("+refs/heads/branch:refs/remotes/origin/branch"),
304+
},
305+
}, []*plumbing.Reference{
306+
plumbing.NewReferenceFromStrings("refs/remotes/origin/branch", headHash.String()),
307+
})
308+
309+
// Control we did get it
310+
commits = r.s.(*memory.Storage).Commits
311+
totalCommitsInBranch := 8 // SEE: https://github.com/git-fixtures/basic/commits/branch
312+
c.Assert(len(commits), Equals, totalCommitsInBranch)
313+
_, err = object.GetCommit(r.s, firstHash)
314+
c.Assert(err, IsNil)
315+
316+
s.assertShallows(c, r, 0)
257317
}
258318

259319
func (s *RemoteSuite) TestFetchWithHashesDepthOfTwo(c *C) {
@@ -268,6 +328,7 @@ func (s *RemoteSuite) TestFetchWithHashesDepthOfTwo(c *C) {
268328
Hashes: []plumbing.Hash{
269329
hash,
270330
},
331+
Tags: NoTags,
271332
}, nil)
272333

273334
commits := r.s.(*memory.Storage).Commits
@@ -291,6 +352,8 @@ func (s *RemoteSuite) TestFetchWithHashesDepthOfTwo(c *C) {
291352

292353
c.Assert(err, IsNil)
293354
c.Assert(output, DeepEquals, expected)
355+
356+
s.assertShallows(c, r, 1)
294357
}
295358

296359
func (s *RemoteSuite) TestFetchWithHashesAndReferences(c *C) {
@@ -334,27 +397,28 @@ func (s *RemoteSuite) TestFetchWithHashesButMissing(c *C) {
334397
})
335398

336399
c.Assert(err.Error(), Equals, "empty packfile")
400+
s.assertShallows(c, r, 0)
401+
}
402+
403+
func (s *RemoteSuite) assertShallows(c *C, r *Remote, expected int) {
404+
shallowCommits, err := r.s.Shallow()
405+
c.Assert(err, IsNil)
406+
407+
c.Assert(shallowCommits, HasLen, expected)
337408
}
338409

339410
func (s *RemoteSuite) testFetch(c *C, r *Remote, o *FetchOptions, expected []*plumbing.Reference) {
340411
err := r.Fetch(o)
341-
c.Assert(err, IsNil)
412+
if err != NoErrAlreadyUpToDate {
413+
c.Assert(err, IsNil)
414+
}
342415

343416
var refs int
344417
l, err := r.s.IterReferences()
345418
c.Assert(err, IsNil)
346419
l.ForEach(func(r *plumbing.Reference) error { refs++; return nil })
347420

348-
if o.Depth > 0 {
349-
shallowCommits, err := r.s.Shallow()
350-
c.Assert(err, IsNil)
351-
352-
// Only the depth-most parent of any given commit will be shallow.
353-
commits := len(r.s.(*memory.Storage).Commits) / o.Depth
354-
c.Assert(shallowCommits, HasLen, commits)
355-
} else {
356-
c.Assert(refs, Equals, len(expected))
357-
}
421+
c.Assert(refs, Equals, len(expected))
358422

359423
for _, exp := range expected {
360424
r, err := r.s.Reference(exp.Name())

repository_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2822,7 +2822,7 @@ func (s *RepositorySuite) TestBrokenMultipleShallowFetch(c *C) {
28222822

28232823
shallows, err = r.Storer.Shallow()
28242824
c.Assert(err, IsNil)
2825-
c.Assert(len(shallows), Equals, 3)
2825+
c.Assert(len(shallows), Equals, 2)
28262826

28272827
ref, err = r.Reference("refs/heads/master", true)
28282828
c.Assert(err, IsNil)

0 commit comments

Comments
 (0)