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

Commit ce78ccb

Browse files
authored
repository: fix pull when fetch returns up-to-date (#207)
1 parent 053124d commit ce78ccb

File tree

2 files changed

+93
-26
lines changed

2 files changed

+93
-26
lines changed

repository.go

Lines changed: 64 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,7 @@ func (r *Repository) Clone(o *CloneOptions) error {
178178
return err
179179
}
180180

181-
if err := r.createReferences(c.Fetch, o.ReferenceName, head); err != nil {
181+
if _, err := r.updateReferences(c.Fetch, o.ReferenceName, head); err != nil {
182182
return err
183183
}
184184

@@ -239,31 +239,42 @@ func (r *Repository) updateRemoteConfig(remote *Remote, o *CloneOptions,
239239
return r.s.SetConfig(cfg)
240240
}
241241

242-
func (r *Repository) createReferences(spec []config.RefSpec,
243-
headName plumbing.ReferenceName, resolvedHead *plumbing.Reference) error {
242+
func (r *Repository) updateReferences(spec []config.RefSpec,
243+
headName plumbing.ReferenceName, resolvedHead *plumbing.Reference) (updated bool, err error) {
244244

245245
if !resolvedHead.IsBranch() {
246246
// Detached HEAD mode
247247
head := plumbing.NewHashReference(plumbing.HEAD, resolvedHead.Hash())
248-
return r.s.SetReference(head)
248+
return updateReferenceStorerIfNeeded(r.s, head)
249249
}
250250

251-
// Create local reference for the resolved head
252-
if err := r.s.SetReference(resolvedHead); err != nil {
253-
return err
251+
refs := []*plumbing.Reference{
252+
// Create local reference for the resolved head
253+
resolvedHead,
254+
// Create local symbolic HEAD
255+
plumbing.NewSymbolicReference(plumbing.HEAD, resolvedHead.Name()),
254256
}
255257

256-
// Create local symbolic HEAD
257-
head := plumbing.NewSymbolicReference(plumbing.HEAD, resolvedHead.Name())
258-
if err := r.s.SetReference(head); err != nil {
259-
return err
258+
refs = append(refs, r.calculateRemoteHeadReference(spec, resolvedHead)...)
259+
260+
for _, ref := range refs {
261+
u, err := updateReferenceStorerIfNeeded(r.s, ref)
262+
if err != nil {
263+
return updated, err
264+
}
265+
266+
if u {
267+
updated = true
268+
}
260269
}
261270

262-
return r.createRemoteHeadReference(spec, resolvedHead)
271+
return
263272
}
264273

265-
func (r *Repository) createRemoteHeadReference(spec []config.RefSpec,
266-
resolvedHead *plumbing.Reference) error {
274+
func (r *Repository) calculateRemoteHeadReference(spec []config.RefSpec,
275+
resolvedHead *plumbing.Reference) []*plumbing.Reference {
276+
277+
var refs []*plumbing.Reference
267278

268279
// Create resolved HEAD reference with remote prefix if it does not
269280
// exist. This is needed when using single branch and HEAD.
@@ -276,20 +287,31 @@ func (r *Repository) createRemoteHeadReference(spec []config.RefSpec,
276287
name = rs.Dst(name)
277288
_, err := r.s.Reference(name)
278289
if err == plumbing.ErrReferenceNotFound {
279-
ref := plumbing.NewHashReference(name, resolvedHead.Hash())
280-
if err := r.s.SetReference(ref); err != nil {
281-
return err
282-
}
283-
284-
continue
290+
refs = append(refs, plumbing.NewHashReference(name, resolvedHead.Hash()))
285291
}
292+
}
286293

287-
if err != nil {
288-
return err
294+
return refs
295+
}
296+
297+
func updateReferenceStorerIfNeeded(
298+
s storer.ReferenceStorer, r *plumbing.Reference) (updated bool, err error) {
299+
300+
p, err := s.Reference(r.Name())
301+
if err != nil && err != plumbing.ErrReferenceNotFound {
302+
return false, err
303+
}
304+
305+
// we use the string method to compare references, is the easiest way
306+
if err == plumbing.ErrReferenceNotFound || r.String() != p.String() {
307+
if err := s.SetReference(r); err != nil {
308+
return false, err
289309
}
310+
311+
return true, nil
290312
}
291313

292-
return nil
314+
return false, nil
293315
}
294316

295317
// IsEmpty returns true if the repository is empty
@@ -322,7 +344,11 @@ func (r *Repository) Pull(o *PullOptions) error {
322344
remoteRefs, err := remote.fetch(&FetchOptions{
323345
Depth: o.Depth,
324346
})
325-
if err != nil {
347+
348+
updated := true
349+
if err == NoErrAlreadyUpToDate {
350+
updated = false
351+
} else if err != nil {
326352
return err
327353
}
328354

@@ -331,7 +357,20 @@ func (r *Repository) Pull(o *PullOptions) error {
331357
return err
332358
}
333359

334-
return r.createReferences(remote.c.Fetch, o.ReferenceName, head)
360+
refsUpdated, err := r.updateReferences(remote.c.Fetch, o.ReferenceName, head)
361+
if err != nil {
362+
return err
363+
}
364+
365+
if refsUpdated {
366+
updated = refsUpdated
367+
}
368+
369+
if !updated {
370+
return NoErrAlreadyUpToDate
371+
}
372+
373+
return nil
335374
}
336375

337376
// Fetch fetches changes from a remote repository.

repository_test.go

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,34 @@ func (s *RepositorySuite) TestCloneDetachedHEAD(c *C) {
266266
c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
267267
}
268268

269+
func (s *RepositorySuite) TestPullUpdateReferencesIfNeeded(c *C) {
270+
r := NewMemoryRepository()
271+
r.CreateRemote(&config.RemoteConfig{
272+
Name: DefaultRemoteName,
273+
URL: s.GetBasicLocalRepositoryURL(),
274+
})
275+
276+
err := r.Fetch(&FetchOptions{})
277+
c.Assert(err, IsNil)
278+
279+
_, err = r.Reference("refs/heads/master", false)
280+
c.Assert(err, NotNil)
281+
282+
err = r.Pull(&PullOptions{})
283+
c.Assert(err, IsNil)
284+
285+
head, err := r.Reference(plumbing.HEAD, true)
286+
c.Assert(err, IsNil)
287+
c.Assert(head.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
288+
289+
branch, err := r.Reference("refs/heads/master", false)
290+
c.Assert(err, IsNil)
291+
c.Assert(branch.Hash().String(), Equals, "6ecf0ef2c2dffb796033e5a02219af86ec6584e5")
292+
293+
err = r.Pull(&PullOptions{})
294+
c.Assert(err, Equals, NoErrAlreadyUpToDate)
295+
}
296+
269297
func (s *RepositorySuite) TestPullSingleBranch(c *C) {
270298
r := NewMemoryRepository()
271299
err := r.Clone(&CloneOptions{
@@ -289,7 +317,7 @@ func (s *RepositorySuite) TestPullSingleBranch(c *C) {
289317
c.Assert(storage.Objects, HasLen, 28)
290318
}
291319

292-
func (s *RepositorySuite) TestPullA(c *C) {
320+
func (s *RepositorySuite) TestPullAdd(c *C) {
293321
path := fixtures.Basic().One().Worktree().Base()
294322

295323
r := NewMemoryRepository()

0 commit comments

Comments
 (0)