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

Commit 4ee12ab

Browse files
authored
Merge pull request #498 from mcuadros/fix-push
remote: push, update remote refs on push
2 parents ef234e7 + 39ecae5 commit 4ee12ab

File tree

4 files changed

+152
-171
lines changed

4 files changed

+152
-171
lines changed

common_test.go

+11
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,14 @@ func (s *SuiteCommon) TestCountLines(c *C) {
169169
c.Assert(o, Equals, t.e, Commentf("subtest %d, input=%q", i, t.i))
170170
}
171171
}
172+
173+
func AssertReferences(c *C, r *Repository, expected map[string]string) {
174+
for name, target := range expected {
175+
expected := plumbing.NewReferenceFromStrings(name, target)
176+
177+
obtained, err := r.Reference(expected.Name(), true)
178+
c.Assert(err, IsNil)
179+
180+
c.Assert(obtained, DeepEquals, expected)
181+
}
182+
}

remote.go

+42-15
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,10 @@ func (r *Remote) String() string {
4848
return fmt.Sprintf("%s\t%s (fetch)\n%[1]s\t%[3]s (push)", r.c.Name, fetch, push)
4949
}
5050

51-
// Fetch fetches references from the remote to the local repository.
52-
// Returns nil if the operation is successful, NoErrAlreadyUpToDate if there are
53-
// no changes to be fetched and no local references to update, or an error.
54-
func (r *Remote) Fetch(o *FetchOptions) error {
55-
_, err := r.fetch(o)
56-
return err
57-
}
58-
5951
// Push performs a push to the remote. Returns NoErrAlreadyUpToDate if the
6052
// remote was already up-to-date.
61-
func (r *Remote) Push(o *PushOptions) (err error) {
53+
func (r *Remote) Push(o *PushOptions) error {
6254
// TODO: Sideband support
63-
64-
if o.RemoteName == "" {
65-
o.RemoteName = r.c.Name
66-
}
67-
6855
if err := o.Validate(); err != nil {
6956
return err
7057
}
@@ -141,7 +128,47 @@ func (r *Remote) Push(o *PushOptions) (err error) {
141128
return err
142129
}
143130

144-
return rs.Error()
131+
if err = rs.Error(); err != nil {
132+
return err
133+
}
134+
135+
return r.updateRemoteReferenceStorage(req, rs)
136+
}
137+
138+
func (r *Remote) updateRemoteReferenceStorage(
139+
req *packp.ReferenceUpdateRequest,
140+
result *packp.ReportStatus,
141+
) error {
142+
143+
for _, spec := range r.c.Fetch {
144+
for _, c := range req.Commands {
145+
if !spec.Match(c.Name) {
146+
continue
147+
}
148+
149+
local := spec.Dst(c.Name)
150+
ref := plumbing.NewHashReference(local, c.New)
151+
switch c.Action() {
152+
case packp.Create, packp.Update:
153+
if err := r.s.SetReference(ref); err != nil {
154+
return err
155+
}
156+
case packp.Delete:
157+
if err := r.s.RemoveReference(local); err != nil {
158+
return err
159+
}
160+
}
161+
}
162+
}
163+
164+
return nil
165+
}
166+
167+
// Fetch fetches references from the remote to the local repository.
168+
// no changes to be fetched and no local references to update, or an error.
169+
func (r *Remote) Fetch(o *FetchOptions) error {
170+
_, err := r.fetch(o)
171+
return err
145172
}
146173

147174
func (r *Remote) fetch(o *FetchOptions) (storer.ReferenceStorer, error) {

remote_test.go

+75-115
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ import (
55
"io"
66
"io/ioutil"
77
"os"
8-
"path/filepath"
9-
"strings"
108

119
"github.com/src-d/go-git-fixtures"
1210
"gopkg.in/src-d/go-git.v4/config"
@@ -305,13 +303,14 @@ func (s *RemoteSuite) TestString(c *C) {
305303
}
306304

307305
func (s *RemoteSuite) TestPushToEmptyRepository(c *C) {
306+
url := c.MkDir()
307+
server, err := PlainInit(url, true)
308+
c.Assert(err, IsNil)
309+
308310
srcFs := fixtures.Basic().One().DotGit()
309311
sto, err := filesystem.NewStorage(srcFs)
310312
c.Assert(err, IsNil)
311313

312-
dstFs := fixtures.ByTag("empty").One().DotGit()
313-
url := dstFs.Root()
314-
315314
r := newRemote(sto, &config.RemoteConfig{
316315
Name: DefaultRemoteName,
317316
URL: url,
@@ -323,140 +322,117 @@ func (s *RemoteSuite) TestPushToEmptyRepository(c *C) {
323322
})
324323
c.Assert(err, IsNil)
325324

326-
dstSto, err := filesystem.NewStorage(dstFs)
327-
c.Assert(err, IsNil)
328-
dstRepo, err := Open(dstSto, nil)
325+
iter, err := r.s.IterReferences()
329326
c.Assert(err, IsNil)
330327

331-
iter, err := sto.IterReferences()
332-
c.Assert(err, IsNil)
333-
err = iter.ForEach(func(ref *plumbing.Reference) error {
328+
expected := make(map[string]string)
329+
iter.ForEach(func(ref *plumbing.Reference) error {
334330
if !ref.IsBranch() {
335331
return nil
336332
}
337333

338-
dstRef, err := dstRepo.Reference(ref.Name(), true)
339-
c.Assert(err, IsNil, Commentf("ref: %s", ref.String()))
340-
c.Assert(dstRef, DeepEquals, ref)
341-
334+
expected[ref.Name().String()] = ref.Hash().String()
342335
return nil
343336
})
344337
c.Assert(err, IsNil)
338+
339+
AssertReferences(c, server, expected)
340+
345341
}
346342

347343
func (s *RemoteSuite) TestPushTags(c *C) {
348-
srcFs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit()
349-
sto, err := filesystem.NewStorage(srcFs)
344+
url := c.MkDir()
345+
server, err := PlainInit(url, true)
350346
c.Assert(err, IsNil)
351347

352-
dstFs := fixtures.ByTag("empty").One().DotGit()
353-
url := dstFs.Root()
348+
fs := fixtures.ByURL("https://github.com/git-fixtures/tags.git").One().DotGit()
349+
sto, err := filesystem.NewStorage(fs)
350+
c.Assert(err, IsNil)
354351

355352
r := newRemote(sto, &config.RemoteConfig{
356353
Name: DefaultRemoteName,
357354
URL: url,
358355
})
359356

360-
rs := config.RefSpec("refs/tags/*:refs/tags/*")
361357
err = r.Push(&PushOptions{
362-
RefSpecs: []config.RefSpec{rs},
358+
RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"},
363359
})
364360
c.Assert(err, IsNil)
365361

366-
dstSto, err := filesystem.NewStorage(dstFs)
367-
c.Assert(err, IsNil)
368-
dstRepo, err := Open(dstSto, nil)
369-
c.Assert(err, IsNil)
370-
371-
ref, err := dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/lightweight-tag"))
372-
c.Assert(err, IsNil)
373-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/lightweight-tag", "f7b877701fbf855b44c0a9e86f3fdce2c298b07f"))
374-
375-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/annotated-tag"))
376-
c.Assert(err, IsNil)
377-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/annotated-tag", "b742a2a9fa0afcfa9a6fad080980fbc26b007c69"))
378-
379-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/commit-tag"))
380-
c.Assert(err, IsNil)
381-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/commit-tag", "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc"))
382-
383-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/blob-tag"))
384-
c.Assert(err, IsNil)
385-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/blob-tag", "fe6cb94756faa81e5ed9240f9191b833db5f40ae"))
386-
387-
ref, err = dstRepo.Storer.Reference(plumbing.ReferenceName("refs/tags/tree-tag"))
388-
c.Assert(err, IsNil)
389-
c.Assert(ref, DeepEquals, plumbing.NewReferenceFromStrings("refs/tags/tree-tag", "152175bf7e5580299fa1f0ba41ef6474cc043b70"))
362+
AssertReferences(c, server, map[string]string{
363+
"refs/tags/lightweight-tag": "f7b877701fbf855b44c0a9e86f3fdce2c298b07f",
364+
"refs/tags/annotated-tag": "b742a2a9fa0afcfa9a6fad080980fbc26b007c69",
365+
"refs/tags/commit-tag": "ad7897c0fb8e7d9a9ba41fa66072cf06095a6cfc",
366+
"refs/tags/blob-tag": "fe6cb94756faa81e5ed9240f9191b833db5f40ae",
367+
"refs/tags/tree-tag": "152175bf7e5580299fa1f0ba41ef6474cc043b70",
368+
})
390369
}
391370

392371
func (s *RemoteSuite) TestPushNoErrAlreadyUpToDate(c *C) {
393-
f := fixtures.Basic().One()
394-
sto, err := filesystem.NewStorage(f.DotGit())
372+
fs := fixtures.Basic().One().DotGit()
373+
sto, err := filesystem.NewStorage(fs)
395374
c.Assert(err, IsNil)
396-
url := f.DotGit().Root()
375+
397376
r := newRemote(sto, &config.RemoteConfig{
398377
Name: DefaultRemoteName,
399-
URL: url,
378+
URL: fs.Root(),
400379
})
401380

402-
rs := config.RefSpec("refs/heads/*:refs/heads/*")
403381
err = r.Push(&PushOptions{
404-
RefSpecs: []config.RefSpec{rs},
382+
RefSpecs: []config.RefSpec{"refs/heads/*:refs/heads/*"},
405383
})
406384
c.Assert(err, Equals, NoErrAlreadyUpToDate)
407385
}
408386

409387
func (s *RemoteSuite) TestPushDeleteReference(c *C) {
410-
f := fixtures.Basic().One()
411-
sto, err := filesystem.NewStorage(f.DotGit())
388+
fs := fixtures.Basic().One().DotGit()
389+
sto, err := filesystem.NewStorage(fs)
412390
c.Assert(err, IsNil)
413391

414-
dstFs := f.DotGit()
415-
dstSto, err := filesystem.NewStorage(dstFs)
392+
r, err := PlainClone(c.MkDir(), true, &CloneOptions{
393+
URL: fs.Root(),
394+
})
416395
c.Assert(err, IsNil)
417-
prepareRepo(c, dstFs.Root())
418396

419-
url := dstFs.Root()
420-
r := newRemote(sto, &config.RemoteConfig{
421-
Name: DefaultRemoteName,
422-
URL: url,
423-
})
397+
remote, err := r.Remote(DefaultRemoteName)
398+
c.Assert(err, IsNil)
424399

425-
rs := config.RefSpec(":refs/heads/branch")
426-
err = r.Push(&PushOptions{
427-
RefSpecs: []config.RefSpec{rs},
400+
err = remote.Push(&PushOptions{
401+
RefSpecs: []config.RefSpec{":refs/heads/branch"},
428402
})
429403
c.Assert(err, IsNil)
430404

431-
_, err = dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
405+
_, err = sto.Reference(plumbing.ReferenceName("refs/heads/branch"))
406+
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
407+
408+
_, err = r.Storer.Reference(plumbing.ReferenceName("refs/heads/branch"))
432409
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
433410
}
434411

435412
func (s *RemoteSuite) TestPushRejectNonFastForward(c *C) {
436-
f := fixtures.Basic().One()
437-
sto, err := filesystem.NewStorage(f.DotGit())
413+
fs := fixtures.Basic().One().DotGit()
414+
server, err := filesystem.NewStorage(fs)
438415
c.Assert(err, IsNil)
439416

440-
dstFs := f.DotGit()
441-
dstSto, err := filesystem.NewStorage(dstFs)
417+
r, err := PlainClone(c.MkDir(), true, &CloneOptions{
418+
URL: fs.Root(),
419+
})
442420
c.Assert(err, IsNil)
443421

444-
url := dstFs.Root()
445-
r := newRemote(sto, &config.RemoteConfig{
446-
Name: DefaultRemoteName,
447-
URL: url,
448-
})
422+
remote, err := r.Remote(DefaultRemoteName)
423+
c.Assert(err, IsNil)
449424

450-
oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
425+
branch := plumbing.ReferenceName("refs/heads/branch")
426+
oldRef, err := server.Reference(branch)
451427
c.Assert(err, IsNil)
452428
c.Assert(oldRef, NotNil)
453429

454-
err = r.Push(&PushOptions{RefSpecs: []config.RefSpec{
455-
config.RefSpec("refs/heads/master:refs/heads/branch"),
430+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
431+
"refs/heads/master:refs/heads/branch",
456432
}})
457433
c.Assert(err, ErrorMatches, "non-fast-forward update: refs/heads/branch")
458434

459-
newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
435+
newRef, err := server.Reference(branch)
460436
c.Assert(err, IsNil)
461437
c.Assert(newRef, DeepEquals, oldRef)
462438
}
@@ -491,32 +467,35 @@ func (s *RemoteSuite) TestPushForce(c *C) {
491467
}
492468

493469
func (s *RemoteSuite) TestPushNewReference(c *C) {
494-
f := fixtures.Basic().One()
495-
sto, err := filesystem.NewStorage(f.DotGit())
496-
c.Assert(err, IsNil)
470+
fs := fixtures.Basic().One().DotGit()
471+
url := c.MkDir()
472+
server, err := PlainClone(url, true, &CloneOptions{
473+
URL: fs.Root(),
474+
})
497475

498-
dstFs := f.DotGit()
499-
dstSto, err := filesystem.NewStorage(dstFs)
476+
r, err := PlainClone(c.MkDir(), true, &CloneOptions{
477+
URL: url,
478+
})
500479
c.Assert(err, IsNil)
501480

502-
url := dstFs.Root()
503-
r := newRemote(sto, &config.RemoteConfig{
504-
Name: DefaultRemoteName,
505-
URL: url,
506-
})
481+
remote, err := r.Remote(DefaultRemoteName)
482+
c.Assert(err, IsNil)
507483

508-
oldRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch"))
484+
ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true)
509485
c.Assert(err, IsNil)
510-
c.Assert(oldRef, NotNil)
511486

512-
err = r.Push(&PushOptions{RefSpecs: []config.RefSpec{
513-
config.RefSpec("refs/heads/branch:refs/heads/branch2"),
487+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
488+
"refs/heads/master:refs/heads/branch2",
514489
}})
515490
c.Assert(err, IsNil)
516491

517-
newRef, err := dstSto.Reference(plumbing.ReferenceName("refs/heads/branch2"))
518-
c.Assert(err, IsNil)
519-
c.Assert(newRef.Hash(), Equals, oldRef.Hash())
492+
AssertReferences(c, server, map[string]string{
493+
"refs/heads/branch2": ref.Hash().String(),
494+
})
495+
496+
AssertReferences(c, r, map[string]string{
497+
"refs/remotes/origin/branch2": ref.Hash().String(),
498+
})
520499
}
521500

522501
func (s *RemoteSuite) TestPushInvalidEndpoint(c *C) {
@@ -532,7 +511,7 @@ func (s *RemoteSuite) TestPushNonExistentEndpoint(c *C) {
532511
}
533512

534513
func (s *RemoteSuite) TestPushInvalidSchemaEndpoint(c *C) {
535-
r := newRemote(nil, &config.RemoteConfig{Name: "foo", URL: "qux://foo"})
514+
r := newRemote(nil, &config.RemoteConfig{Name: "origin", URL: "qux://foo"})
536515
err := r.Push(&PushOptions{})
537516
c.Assert(err, ErrorMatches, ".*unsupported scheme.*")
538517
}
@@ -587,22 +566,3 @@ func (s *RemoteSuite) TestGetHaves(c *C) {
587566
c.Assert(err, IsNil)
588567
c.Assert(l, HasLen, 2)
589568
}
590-
591-
const bareConfig = `[core]
592-
repositoryformatversion = 0
593-
filemode = true
594-
bare = true`
595-
596-
func prepareRepo(c *C, path string) {
597-
// git-receive-pack refuses to update refs/heads/master on non-bare repo
598-
// so we ensure bare repo config.
599-
config := filepath.Join(path, "config")
600-
if _, err := os.Stat(config); err == nil {
601-
f, err := os.OpenFile(config, os.O_TRUNC|os.O_WRONLY, 0)
602-
c.Assert(err, IsNil)
603-
content := strings.NewReader(bareConfig)
604-
_, err = io.Copy(f, content)
605-
c.Assert(err, IsNil)
606-
c.Assert(f.Close(), IsNil)
607-
}
608-
}

0 commit comments

Comments
 (0)