Skip to content
This repository was archived by the owner on Sep 11, 2020. It is now read-only.

Commit 78c539a

Browse files
committed
Update local remote references during fetch even if no pack needs to be received
1 parent 65bf694 commit 78c539a

File tree

2 files changed

+69
-25
lines changed

2 files changed

+69
-25
lines changed

remote.go

+45-25
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func (r *Remote) String() string {
4747

4848
// Fetch fetches references from the remote to the local repository.
4949
// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
50-
// no changes to be fetched, or an error.
50+
// no changes to be fetched and no local references to update, or an error.
5151
func (r *Remote) Fetch(o *FetchOptions) error {
5252
_, err := r.fetch(o)
5353
return err
@@ -156,24 +156,26 @@ func (r *Remote) fetch(o *FetchOptions) (refs storer.ReferenceStorer, err error)
156156
}
157157

158158
req.Wants, err = getWants(o.RefSpecs, r.s, remoteRefs)
159-
if len(req.Wants) == 0 {
160-
return remoteRefs, NoErrAlreadyUpToDate
161-
}
159+
if len(req.Wants) > 0 {
160+
req.Haves, err = getHaves(r.s)
161+
if err != nil {
162+
return nil, err
163+
}
162164

163-
req.Haves, err = getHaves(r.s)
164-
if err != nil {
165-
return nil, err
165+
if err := r.fetchPack(o, s, req); err != nil {
166+
return nil, err
167+
}
166168
}
167169

168-
if err := r.fetchPack(o, s, req); err != nil {
170+
err = r.updateLocalReferenceStorage(o.RefSpecs, remoteRefs)
171+
if err != nil && err != NoErrAlreadyUpToDate {
169172
return nil, err
170173
}
171174

172-
if err := r.updateLocalReferenceStorage(o.RefSpecs, remoteRefs); err != nil {
173-
return nil, err
175+
if len(req.Wants) == 0 {
176+
return remoteRefs, err
174177
}
175-
176-
return remoteRefs, err
178+
return remoteRefs, nil
177179
}
178180

179181
func newUploadPackSession(url string, auth transport.AuthMethod) (transport.UploadPackSession, error) {
@@ -473,6 +475,7 @@ func buildSidebandIfSupported(l *capability.List, reader io.Reader, p sideband.P
473475
}
474476

475477
func (r *Remote) updateLocalReferenceStorage(specs []config.RefSpec, refs memory.ReferenceStorage) error {
478+
updated := false
476479
for _, spec := range specs {
477480
for _, ref := range refs {
478481
if !spec.Match(ref.Name()) {
@@ -484,38 +487,55 @@ func (r *Remote) updateLocalReferenceStorage(specs []config.RefSpec, refs memory
484487
}
485488

486489
name := spec.Dst(ref.Name())
487-
n := plumbing.NewHashReference(name, ref.Hash())
488-
if err := r.s.SetReference(n); err != nil {
490+
sref, err := r.s.Reference(name)
491+
if err != nil && err != plumbing.ErrReferenceNotFound {
489492
return err
490493
}
494+
if err == plumbing.ErrReferenceNotFound || sref.Hash() != ref.Hash() {
495+
n := plumbing.NewHashReference(name, ref.Hash())
496+
if err := r.s.SetReference(n); err != nil {
497+
return err
498+
}
499+
updated = true
500+
}
491501
}
492502
}
493503

494-
return r.buildFetchedTags(refs)
495-
}
496-
497-
func (r *Remote) buildFetchedTags(refs storer.ReferenceStorer) error {
498-
iter, err := refs.IterReferences()
499-
if err != nil {
504+
if err := r.buildFetchedTags(refs); err != nil {
500505
return err
501506
}
502507

503-
return iter.ForEach(func(ref *plumbing.Reference) error {
508+
if !updated {
509+
return NoErrAlreadyUpToDate
510+
}
511+
return nil
512+
}
513+
514+
func (r *Remote) buildFetchedTags(refs memory.ReferenceStorage) error {
515+
updated := false
516+
for _, ref := range refs {
504517
if !ref.IsTag() {
505-
return nil
518+
continue
506519
}
507520

508521
_, err := r.s.EncodedObject(plumbing.AnyObject, ref.Hash())
509522
if err == plumbing.ErrObjectNotFound {
510-
return nil
523+
continue
511524
}
512525

513526
if err != nil {
514527
return err
515528
}
516529

517-
return r.s.SetReference(ref)
518-
})
530+
if err = r.s.SetReference(ref); err != nil {
531+
return err
532+
}
533+
updated = true
534+
}
535+
if !updated {
536+
return NoErrAlreadyUpToDate
537+
}
538+
return nil
519539
}
520540

521541
func objectsToPush(commands []*packp.Command) ([]plumbing.Hash, error) {

remote_test.go

+24
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,30 @@ func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDate(c *C) {
174174
s.doTestFetchNoErrAlreadyUpToDate(c, url)
175175
}
176176

177+
func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateButStillUpdateLocalRemoteRefs(c *C) {
178+
url := s.GetBasicLocalRepositoryURL()
179+
180+
sto := memory.NewStorage()
181+
r := newRemote(sto, &config.RemoteConfig{Name: "foo", URL: url})
182+
183+
refspec := config.RefSpec("+refs/heads/*:refs/remotes/origin/*")
184+
o := &FetchOptions{
185+
RefSpecs: []config.RefSpec{refspec},
186+
}
187+
188+
err := r.Fetch(o)
189+
c.Assert(err, IsNil)
190+
191+
// Simulate an out of date remote ref even though we have the new commit locally
192+
sto.SetReference(plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "918c48b83bd081e863dbe1b80f8998f058cd8294"))
193+
194+
err = r.Fetch(o)
195+
c.Assert(err, IsNil)
196+
exp := plumbing.NewReferenceFromStrings("refs/remotes/origin/master", "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
197+
ref, _ := sto.Reference("refs/remotes/origin/master")
198+
c.Assert(exp.String(), Equals, ref.String())
199+
}
200+
177201
func (s *RemoteSuite) TestFetchNoErrAlreadyUpToDateWithNonCommitObjects(c *C) {
178202
fixture := fixtures.ByTag("tags").One()
179203
url := s.GetLocalRepositoryURL(fixture)

0 commit comments

Comments
 (0)