8000 remote: fetch, adds the prune option. Fixes #316 · go-git/go-git@f87e168 · GitHub
[go: up one dir, main page]

Skip to content

Commit f87e168

Browse files
juliensldez
andcommitted
remote: fetch, adds the prune option. Fixes #316
Co-authored-by: Ludovic Fernandez <ldez@users.noreply.github.com>
1 parent 686a0f7 commit f87e168

File tree

3 files changed

+147
-2
lines changed

3 files changed

+147
-2
lines changed

options.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ const (
166166
// AllTags fetch all tags from the remote (i.e., fetch remote tags
167167
// refs/tags/* into local tags with the same name)
168168
AllTags
169-
//NoTags fetch no tags from the remote at all
169+
// NoTags fetch no tags from the remote at all
170170
NoTags
171171
)
172172

@@ -198,6 +198,9 @@ type FetchOptions struct {
198198
CABundle []byte
199199
// ProxyOptions provides info required for connecting to a proxy.
200200
ProxyOptions transport.ProxyOptions
201+
// Prune specify that local refs that match given RefSpecs and that do
202+
// not exist remotely will be removed.
203+
Prune bool
201204
}
202205

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

remote.go

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,6 +470,14 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
470470
}
471471
}
472472

473+
var updatedPrune bool
474+
if o.Prune {
475+
updatedPrune, err = r.pruneRemotes(o.RefSpecs, localRefs, remoteRefs)
476+
if err != nil {
477+
return nil, err
478+
}
479+
}
480+
473481
updated, err := r.updateLocalReferenceStorage(o.RefSpecs, refs, remoteRefs, specToRefs, o.Tags, o.Force)
474482
if err != nil {
475483
return nil, err
@@ -482,7 +490,7 @@ func (r *Remote) fetch(ctx context.Context, o *FetchOptions) (sto storer.Referen
482490
}
483491
}
484492

485-
if !updated {
493+
if !updated && !updatedPrune {
486494
return remoteRefs, NoErrAlreadyUpToDate
487495
}
488496

@@ -574,6 +582,27 @@ func (r *Remote) fetchPack(ctx context.Context, o *FetchOptions, s transport.Upl
574582
return err
575583
}
576584

585+
func (r *Remote) pruneRemotes(specs []config.RefSpec, localRefs []*plumbing.Reference, remoteRefs memory.ReferenceStorage) (bool, error) {
586+
var updatedPrune bool
587+
for _, spec := range specs {
588+
rev := spec.Reverse()
589+
for _, ref := range localRefs {
590+
if !rev.Match(ref.Name()) {
591+
continue
592+
}
593+
_, err := remoteRefs.Reference(rev.Dst(ref.Name()))
594+
if errors.Is(err, plumbing.ErrReferenceNotFound) {
595+
updatedPrune = true
596+
err := r.s.RemoveReference(ref.Name())
597+
if err != nil {
598+
return false, err
599+
}
600+
}
601+
}
602+
}
603+
return updatedPrune, nil
604+
}
605+
577606
func (r *Remote) addReferencesToUpdate(
578607
refspecs []config.RefSpec,
579608
localRefs []*plumbing.Reference,

remote_test.go

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1444,6 +1444,119 @@ func (s *RemoteSuite) TestPushRequireRemoteRefs(c *C) {
14441444
c.Assert(newRef, Not(DeepEquals), oldRef)
14451445
}
14461446

1447+
func (s *RemoteSuite) TestFetchPrune(c *C) {
1448+
fs := fixtures.Basic().One().DotGit()
1449+
1450+
url, clean := s.TemporalDir()
1451+
defer clean()
1452+
1453+
_, err := PlainClone(url, true, &CloneOptions{
1454+
URL: fs.Root(),
1455+
})
1456+
c.Assert(err, IsNil)
1457+
1458+
dir, clean := s.TemporalDir()
1459+
defer clean()
1460+
1461+
r, err := PlainClone(dir, true, &CloneOptions{
1462+
URL: url,
1463+
})
1464+
c.Assert(err, IsNil)
1465+
1466+
remote, err := r.Remote(DefaultRemoteName)
1467+
c.Assert(err, IsNil)
1468+
1469+
ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true)
1470+
c.Assert(err, IsNil)
1471+
1472+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
1473+
"refs/heads/master:refs/heads/branch",
1474+
}})
1475+
c.Assert(err, IsNil)
1476+
1477+
dirSave, clean := s.TemporalDir()
1478+
defer clean()
1479+
1480+
rSave, err := PlainClone(dirSave, true, &CloneOptions{
1481+
URL: url,
1482+
})
1483+
c.Assert(err, IsNil)
1484+
1485+
AssertReferences(c, rSave, map[string]string{
1486+
"refs/remotes/origin/branch": ref.Hash().String(),
1487+
})
1488+
1489+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
1490+
":refs/heads/branch",
1491+
}})
1492+
1493+
AssertReferences(c, rSave, map[string]string{
1494+
"refs/remotes/origin/branch": ref.Hash().String(),
1495+
})
1496+
1497+
err = rSave.Fetch(&FetchOptions{Prune: true})
1498+
c.Assert(err, IsNil)
1499+
1500+
_, err = rSave.Reference("refs/remotes/origin/branch", true)
1501+
c.Assert(err, ErrorMatches, "reference not found")
1502+
}
1503+
1504+
func (s *RemoteSuite) TestFetchPruneTags(c *C) {
1505+
fs := fixtures.Basic().One().DotGit()
1506+
1507+
url, clean := s.TemporalDir()
1508+
defer clean()
1509+
1510+
_, err := PlainClone(url, true, &CloneOptions{
1511+
URL: fs.Root(),
1512+
})
1513+
c.Assert(err, IsNil)
1514+
1515+
dir, clean := s.TemporalDir()
1516+
defer clean()
1517+
1518+
r, err := PlainClone(dir, true, &CloneOptions{
1519+
URL: url,
1520+
})
1521+
c.Assert(err, IsNil)
1522+
1523+
remote, err := r.Remote(DefaultRemoteName)
1524+
c.Assert(err, IsNil)
1525+
1526+
ref, err := r.Reference(plumbing.ReferenceName("refs/heads/master"), true)
1527+
c.Assert(err, IsNil)
1528+
1529+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
1530+
"refs/heads/master:refs/tags/v1",
1531+
}})
1532+
c.Assert(err, IsNil)
1533+
1534+
dirSave, clean := s.TemporalDir()
1535+
defer clean()
1536+
1537+
rSave, err := PlainClone(dirSave, true, &CloneOptions{
1538+
URL: url,
1539+
})
1540+
c.Assert(err, IsNil)
1541+
1542+
AssertReferences(c, rSave, map[string]string{
1543+
"refs/tags/v1": ref.Hash().String(),
1544+
})
1545+
1546+
err = remote.Push(&PushOptions{RefSpecs: []config.RefSpec{
1547+
":refs/tags/v1",
1548+
}})
1549+
1550+
AssertReferences(c, rSave, map[string]string{
1551+
"refs/tags/v1": ref.Hash().String(),
1552+
})
1553+
1554+
err = rSave.Fetch(&FetchOptions{Prune: true, RefSpecs: []config.RefSpec{"refs/tags/*:refs/tags/*"}})
1555+
c.Assert(err, IsNil)
1556+
1557+
_, err = rSave.Reference("refs/tags/v1", true)
1558+
c.Assert(err, ErrorMatches, "reference not found")
1559+
}
14471560
func (s *RemoteSuite) TestCanPushShasToReference(c *C) {
14481561
d, err := os.MkdirTemp("", "TestCanPushShasToReference")
14491562
c.Assert(err, IsNil)

0 commit comments

Comments
 (0)
0