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

Commit 6dda959

Browse files
authored
Merge pull request #666 from keybase/strib/delete-from-packed-ref
dotgit: handle refs that exist in both packed-refs and a loose ref file
2 parents 147a1b7 + 9c80677 commit 6dda959

File tree

2 files changed

+76
-6
lines changed

2 files changed

+76
-6
lines changed

storage/filesystem/internal/dotgit/dotgit.go

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ func (d *DotGit) Refs() ([]*plumbing.Reference, error) {
268268
return nil, err
269269
}
270270

271-
if err := d.addRefsFromPackedRefs(&refs); err != nil {
271+
if err := d.addRefsFromPackedRefs(&refs, seen); err != nil {
272272
return nil, err
273273
}
274274

@@ -336,7 +336,8 @@ func (d *DotGit) RemoveRef(name plumbing.ReferenceName) error {
336336
path := d.fs.Join(".", name.String())
337337
_, err := d.fs.Stat(path)
338338
if err == nil {
339-
return d.fs.Remove(path)
339+
err = d.fs.Remove(path)
340+
// Drop down to remove it from the packed refs file, too.
340341
}
341342

342343
if err != nil && !os.IsNotExist(err) {
@@ -346,13 +347,18 @@ func (d *DotGit) RemoveRef(name plumbing.ReferenceName) error {
346347
return d.rewritePackedRefsWithoutRef(name)
347348
}
348349

349-
func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference) (err error) {
350+
func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference, seen map[plumbing.ReferenceName]bool) (err error) {
350351
packedRefs, err := d.findPackedRefs()
351352
if err != nil {
352353
return err
353354
}
354355

355-
*refs = append(*refs, packedRefs...)
356+
for _, ref := range packedRefs {
357+
if !seen[ref.Name()] {
358+
*refs = append(*refs, ref)
359+
seen[ref.Name()] = true
360+
}
361+
}
356362
return nil
357363
}
358364

@@ -365,13 +371,30 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
365371

366372
return err
367373
}
374+
doCloseF := true
375+
defer func() {
376+
if doCloseF {
377+
ioutil.CheckClose(f, &err)
378+
}
379+
}()
380+
381+
err = f.Lock()
382+
if err != nil {
383+
return err
384+
}
368385

369386
// Creating the temp file in the same directory as the target file
370387
// improves our chances for rename operation to be atomic.
371388
tmp, err := d.fs.TempFile("", tmpPackedRefsPrefix)
372389
if err != nil {
373390
return err
374391
}
392+
doCloseTmp := true
393+
defer func() {
394+
if doCloseTmp {
395+
ioutil.CheckClose(tmp, &err)
396+
}
397+
}()
375398

376399
s := bufio.NewScanner(f)
377400
found := false
@@ -397,14 +420,21 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
397420
}
398421

399422
if !found {
400-
return nil
423+
doCloseTmp = false
424+
ioutil.CheckClose(tmp, &err)
425+
if err != nil {
426+
return err
427+
}
428+
// Delete the temp file if nothing needed to be removed.
429+
return d.fs.Remove(tmp.Name())
401430
}
402431

432+
doCloseF = false
403433
if err := f.Close(); err != nil {
404-
ioutil.CheckClose(tmp, &err)
405434
return err
406435
}
407436

437+
doCloseTmp = false
408438
if err := tmp.Close(); err != nil {
409439
return err
410440
}

storage/filesystem/internal/dotgit/dotgit_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,46 @@ func (s *SuiteDotGit) TestRemoveRefFromPackedRefs(c *C) {
184184
"e8d3ffab552895c19b9fcf7aa264d277cde33881 refs/remotes/origin/branch\n")
185185
}
186186

187+
func (s *SuiteDotGit) TestRemoveRefFromReferenceFileAndPackedRefs(c *C) {
188+
fs := fixtures.Basic().ByTag(".git").One().DotGit()
189+
dir := New(fs)
190+
191+
// Make a ref file for a ref that's already in `packed-refs`.
192+
err := dir.SetRef(plumbing.NewReferenceFromStrings(
193+
"refs/remotes/origin/branch",
194+
"e8d3ffab552895c19b9fcf7aa264d277cde33881",
195+
))
196+
197+
// Make sure it only appears once in the refs list.
198+
refs, err := dir.Refs()
199+
c.Assert(err, IsNil)
200+
found := false
201+
for _, ref := range refs {
202+
if ref.Name() == "refs/remotes/origin/branch" {
203+
c.Assert(found, Equals, false)
204+
found = true
205+
}
206+
}
207+
208+
name := plumbing.ReferenceName("refs/remotes/origin/branch")
209+
err = dir.RemoveRef(name)
210+
c.Assert(err, IsNil)
211+
212+
b, err := ioutil.ReadFile(filepath.Join(fs.Root(), packedRefsPath))
213+
c.Assert(err, IsNil)
214+
215+
c.Assert(string(b), Equals, ""+
216+
"# pack-refs with: peeled fully-peeled \n"+
217+
"6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/heads/master\n"+
218+
"6ecf0ef2c2dffb796033e5a02219af86ec6584e5 refs/remotes/origin/master\n")
219+
220+
refs, err = dir.Refs()
221+
c.Assert(err, IsNil)
222+
223+
ref := findReference(refs, string(name))
224+
c.Assert(ref, IsNil)
225+
}
226+
187227
func (s *SuiteDotGit) TestRemoveRefNonExistent(c *C) {
188228
fs := fixtures.Basic().ByTag(".git").One().DotGit()
189229
dir := New(fs)

0 commit comments

Comments
 (0)