aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcus Watkins <marwatk@marcuswatkins.net>2021-05-12 14:39:49 -0600
committerGitHub <noreply@github.com>2021-05-12 22:39:49 +0200
commit320db9af8ba8b0046e833013504eb07c61a3573c (patch)
treec7b18c36c8f6a146b1e66fc705373f5632853a5f
parentdb2bc57350561c4368a8d32c42476699b48d2a09 (diff)
downloadgo-git-320db9af8ba8b0046e833013504eb07c61a3573c.tar.gz
git: Add support for deepening shallow clones (#311)
-rw-r--r--plumbing/transport/internal/common/common.go2
-rw-r--r--remote.go44
-rw-r--r--remote_test.go26
3 files changed, 70 insertions, 2 deletions
diff --git a/plumbing/transport/internal/common/common.go b/plumbing/transport/internal/common/common.go
index 75405c7..fdb148f 100644
--- a/plumbing/transport/internal/common/common.go
+++ b/plumbing/transport/internal/common/common.go
@@ -233,7 +233,7 @@ func (s *session) handleAdvRefDecodeError(err error) error {
// UploadPack performs a request to the server to fetch a packfile. A reader is
// returned with the packfile content. The reader must be closed after reading.
func (s *session) UploadPack(ctx context.Context, req *packp.UploadPackRequest) (*packp.UploadPackResponse, error) {
- if req.IsEmpty() {
+ if req.IsEmpty() && len(req.Shallows) == 0 {
return nil, transport.ErrEmptyUploadPackRequest
}
diff --git a/remote.go b/remote.go
index 47af638..ca82a3d 100644
--- a/remote.go
+++ b/remote.go
@@ -350,6 +350,13 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
return nil, err
}
+ if !req.Depth.IsZero() {
+ req.Shallows, err = r.s.Shallow()
+ if err != nil {
+ return nil, fmt.Errorf("existing checkout is not shallow")
+ }
+ }
+
req.Wants, err = getWants(r.s, refs)
if len(req.Wants) > 0 {
req.Haves, err = getHaves(localRefs, remoteRefs, r.s)
@@ -368,12 +375,42 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
}
if !updated {
+ updated, err = depthChanged(req.Shallows, r.s)
+ if err != nil {
+ return nil, fmt.Errorf("error checking depth change: %v", err)
+ }
+ }
+
+ if !updated {
return remoteRefs, NoErrAlreadyUpToDate
}
return remoteRefs, nil
}
+func depthChanged(before []plumbing.Hash, s storage.Storer) (bool, error) {
+ after, err := s.Shallow()
+ if err != nil {
+ return false, err
+ }
+
+ if len(before) != len(after) {
+ return true, nil
+ }
+
+ bm := make(map[plumbing.Hash]bool, len(before))
+ for _, b := range before {
+ bm[b] = true
+ }
+ for _, a := range after {
+ if _, ok := bm[a]; !ok {
+ return true, nil
+ }
+ }
+
+ return false, nil
+}
+
func newUploadPackSession(url string, auth transport.AuthMethod, insecure bool, cabundle []byte) (transport.UploadPackSession, error) {
c, ep, err := newClient(url, auth, insecure, cabundle)
if err != nil {
@@ -778,6 +815,11 @@ func doCalculateRefs(
}
func getWants(localStorer storage.Storer, refs memory.ReferenceStorage) ([]plumbing.Hash, error) {
+ shallow := false
+ if s, _ := localStorer.Shallow(); len(s) > 0 {
+ shallow = true
+ }
+
wants := map[plumbing.Hash]bool{}
for _, ref := range refs {
hash := ref.Hash()
@@ -786,7 +828,7 @@ func getWants(localStorer storage.Storer, refs memory.ReferenceStorage) ([]plumb
return nil, err
}
- if !exists {
+ if !exists || shallow {
wants[hash] = true
}
}
diff --git a/remote_test.go b/remote_test.go
index 2cd2a6e..1efc9da 100644
--- a/remote_test.go
+++ b/remote_test.go
@@ -233,6 +233,32 @@ func (s *RemoteSuite) TestFetchWithDepth(c *C) {
c.Assert(r.s.(*memory.Storage).Objects, HasLen, 18)
}
+func (s *RemoteSuite) TestFetchWithDepthChange(c *C) {
+ r := NewRemote(memory.NewStorage(), &config.RemoteConfig{
+ URLs: []string{s.GetBasicLocalRepositoryURL()},
+ })
+
+ s.testFetch(c, r, &FetchOptions{
+ Depth: 1,
+ RefSpecs: []config.RefSpec{
+ config.RefSpec("refs/heads/master:refs/heads/master"),
+ },
+ }, []*plumbing.Reference{
+ plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
+ })
+ c.Assert(r.s.(*memory.Storage).Commits, HasLen, 1)
+
+ s.testFetch(c, r, &FetchOptions{
+ Depth: 3,
+ RefSpecs: []config.RefSpec{
+ config.RefSpec("refs/heads/master:refs/heads/master"),
+ },
+ }, []*plumbing.Reference{
+ plumbing.NewReferenceFromStrings("refs/heads/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5"),
+ })
+ c.Assert(r.s.(*memory.Storage).Commits, HasLen, 3)
+}
+
func (s *RemoteSuite) testFetch(c *C, r *Remote, o *FetchOptions, expected []*plumbing.Reference) {
err := r.Fetch(o)
c.Assert(err, IsNil)