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

Commit c2e64a2

Browse files
committed
add Prune option to PushOptions
1 parent 60033b8 commit c2e64a2

File tree

5 files changed

+103
-6
lines changed

5 files changed

+103
-6
lines changed

config/refspec.go

+7
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,13 @@ func (s RefSpec) Dst(n plumbing.ReferenceName) plumbing.ReferenceName {
127127
return plumbing.ReferenceName(dst[0:wd] + match + dst[wd+1:])
128128
}
129129

130+
func (s RefSpec) Reverse() RefSpec {
131+
spec := string(s)
132+
separator := strings.Index(spec, refSpecSeparator)
133+
134+
return RefSpec(spec[separator+1:] + refSpecSeparator + spec[:separator])
135+
}
136+
130137
func (s RefSpec) String() string {
131138
return string(s)
132139
}

config/refspec_test.go

+9
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,15 @@ func (s *RefSpecSuite) TestRefSpecDstBlob(c *C) {
116116
"refs/remotes/origin/foo",
117117
)
118118
}
119+
120+
func (s *RefSpecSuite) TestRefSpecReverse(c *C) {
121+
spec := RefSpec("refs/heads/*:refs/remotes/origin/*")
122+
c.Assert(
123+
spec.Reverse(), Equals,
124+
RefSpec("refs/remotes/origin/*:refs/heads/*"),
125+
)
126+
}
127+
119128
func (s *RefSpecSuite) TestMatchAny(c *C) {
120129
specs := []RefSpec{
121130
"refs/heads/bar:refs/remotes/origin/foo",

options.go

+3
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ type PushOptions struct {
186186
// Progress is where the human readable information sent by the server is
187187
// stored, if nil nothing is stored.
188188
Progress sideband.Progress
189+
// Prune specify that remote refs that match given RefSpecs and that do
190+
// not exist locally will be removed.
191+
Prune bool
189192
}
190193

191194
// Validate validates the fields and sets the default values.

remote.go

+26-5
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ func (r *Remote) newReferenceUpdateRequest(
201201
}
202202
}
203203

204-
if err := r.addReferencesToUpdate(o.RefSpecs, localRefs, remoteRefs, req); err != nil {
204+
if err := r.addReferencesToUpdate(o.RefSpecs, localRefs, remoteRefs, req, o.Prune); err != nil {
205205
return nil, err
206206
}
207207

@@ -389,6 +389,7 @@ func (r *Remote) addReferencesToUpdate(
389389
localRefs []*plumbing.Reference,
390390
remoteRefs storer.ReferenceStorer,
391391
req *packp.ReferenceUpdateRequest,
392+
prune bool,
392393
) error {
393394
// This references dictionary will be used to search references by name.
394395
refsDict := make(map[string]*plumbing.Reference)
@@ -398,14 +399,20 @@ func (r *Remote) addReferencesToUpdate(
398399

399400
for _, rs := range refspecs {
400401
if rs.IsDelete() {
401-
if err := r.deleteReferences(rs, remoteRefs, req); err != nil {
402+
if err := r.deleteReferences(rs, remoteRefs, refsDict, req, false); err != nil {
402403
return err
403404
}
404405
} else {
405406
err := r.addOrUpdateReferences(rs, localRefs, refsDict, remoteRefs, req)
406407
if err != nil {
407408
return err
408409
}
410+
411+
if prune {
412+
if err := r.deleteReferences(rs, remoteRefs, refsDict, req, true); err != nil {
413+
return err
414+
}
415+
}
409416
}
410417
}
411418

@@ -441,7 +448,10 @@ func (r *Remote) addOrUpdateReferences(
441448
}
442449

443450
func (r *Remote) deleteReferences(rs config.RefSpec,
444-
remoteRefs storer.ReferenceStorer, req *packp.ReferenceUpdateRequest) error {
451+
remoteRefs storer.ReferenceStorer,
452+
refsDict map[string]*plumbing.Reference,
453+
req *packp.ReferenceUpdateRequest,
454+
prune bool) error {
445455
iter, err := remoteRefs.IterReferences()
446456
if err != nil {
447457
return err
@@ -452,8 +462,19 @@ func (r *Remote) deleteReferences(rs config.RefSpec,
452462
return nil
453463
}
454464

455-
if rs.Dst("") != ref.Name() {
456-
return nil
465+
if prune {
466+
rs := rs.Reverse()
467+
if !rs.Match(ref.Name()) {
468+
return nil
469+
}
470+
471+
if _, ok := refsDict[rs.Dst(ref.Name()).String()]; ok {
472+
return nil
473+
}
474+
} else {
475+
if rs.Dst("") != ref.Name() {
476+
return nil
477+
}
457478
}
458479

459480
cmd := &packp.Command{

remote_test.go

+58-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import (
2121

2222
. "gopkg.in/check.v1"
2323
"gopkg.in/src-d/go-billy.v4/osfs"
24-
"gopkg.in/src-d/go-git-fixtures.v3"
24+
fixtures "gopkg.in/src-d/go-git-fixtures.v3"
2525
)
2626

2727
type RemoteSuite struct {
@@ -583,6 +583,63 @@ func (s *RemoteSuite) TestPushForce(c *C) {
583583
c.Assert(newRef, Not(DeepEquals), oldRef)
584584
}
585585

586+
func (s *RemoteSuite) TestPushPrune(c *C) {
587+
fs := fixtures.Basic().One().DotGit()
588+
url := c.MkDir()
589+
server, err := PlainClone(url, true, &CloneOptions{
590+
URL: fs.Root(),
591+
})
592+
c.Assert(err, IsNil)
593+
594+
r, err := PlainClone(c.MkDir(), true, &CloneOptions{
595+
URL: url,
596+
})
597+
c.Assert(err, IsNil)
598+
599+
tag, err := r.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true)
600+
c.Assert(err, IsNil)
601+
602+
err = r.DeleteTag("v1.0.0")
603+
c.Assert(err, IsNil)
604+
605+
remote, err := r.Remote(DefaultRemoteName)
606+
c.Assert(err, IsNil)
607+
608+
ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true)
609+
c.Assert(err, IsNil)
610+
611+
err = remote.Push(&PushOptions{
612+
RefSpecs: []config.RefSpec{
613+
config.RefSpec("refs/heads/*:refs/heads/*"),
614+
},
615+
Prune: true,
616+
})
617+
c.Assert(err, Equals, NoErrAlreadyUpToDate)
618+
619+
AssertReferences(c, server, map[string]string{
620+
"refs/tags/v1.0.0": tag.Hash().String(),
621+
})
622+
623+
err = remote.Push(&PushOptions{
624+
RefSpecs: []config.RefSpec{
625+
config.RefSpec("*:*"),
626+
},
627+
Prune: true,
628+
})
629+
c.Assert(err, IsNil)
630+
631+
AssertReferences(c, server, map[string]string{
632+
"refs/remotes/origin/master": ref.Hash().String(),
633+
})
634+
635+
AssertReferences(c, server, map[string]string{
636+
"refs/remotes/origin/master": ref.Hash().String(),
637+
})
638+
639+
ref, err = server.Reference(plumbing.ReferenceName("refs/tags/v1.0.0"), true)
640+
c.Assert(err, Equals, plumbing.ErrReferenceNotFound)
641+
}
642+
586643
func (s *RemoteSuite) TestPushNewReference(c *C) {
587644
fs := fixtures.Basic().One().DotGit()
588645
url := c.MkDir()

0 commit comments

Comments
 (0)