diff options
author | Marcus Watkins <marwatk@marcuswatkins.net> | 2021-05-12 14:39:49 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-12 22:39:49 +0200 |
commit | 320db9af8ba8b0046e833013504eb07c61a3573c (patch) | |
tree | c7b18c36c8f6a146b1e66fc705373f5632853a5f | |
parent | db2bc57350561c4368a8d32c42476699b48d2a09 (diff) | |
download | go-git-320db9af8ba8b0046e833013504eb07c61a3573c.tar.gz |
git: Add support for deepening shallow clones (#311)
-rw-r--r-- | plumbing/transport/internal/common/common.go | 2 | ||||
-rw-r--r-- | remote.go | 44 | ||||
-rw-r--r-- | remote_test.go | 26 |
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 } @@ -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) |