@@ -460,20 +460,26 @@ func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference, seen map[plu
460
460
return nil
461
461
}
462
462
463
- func (d * DotGit ) openAndLockPackedRefs () (pr billy.File , err error ) {
463
+ func (d * DotGit ) openAndLockPackedRefs (doCreate bool ) (
464
+ pr billy.File , err error ) {
464
465
var f billy.File
465
466
defer func () {
466
467
if err != nil && f != nil {
467
468
ioutil .CheckClose (f , & err )
468
469
}
469
470
}()
470
471
472
+ openFlags := os .O_RDWR
473
+ if doCreate {
474
+ openFlags |= os .O_CREATE
475
+ }
476
+
471
477
// Keep trying to open and lock the file until we're sure the file
472
478
// didn't change between the open and the lock.
473
479
for {
474
- f , err = d .fs .Open (packedRefsPath )
480
+ f , err = d .fs .OpenFile (packedRefsPath , openFlags , 0600 )
475
481
if err != nil {
476
- if os .IsNotExist (err ) {
482
+ if os .IsNotExist (err ) && ! doCreate {
477
483
return nil , nil
478
484
}
479
485
@@ -507,31 +513,25 @@ func (d *DotGit) openAndLockPackedRefs() (pr billy.File, err error) {
507
513
}
508
514
509
515
func (d * DotGit ) rewritePackedRefsWithoutRef (name plumbing.ReferenceName ) (err error ) {
510
- pr , err := d .openAndLockPackedRefs ()
516
+ pr , err := d .openAndLockPackedRefs (false )
511
517
if err != nil {
512
518
return err
513
519
}
514
520
if pr == nil {
515
521
return nil
516
522
}
517
- doClosePR := true
518
- defer func () {
519
- if doClosePR {
520
- ioutil .CheckClose (pr , & err )
521
- }
522
- }()
523
+ defer ioutil .CheckClose (pr , & err )
523
524
524
525
// Creating the temp file in the same directory as the target file
525
526
// improves our chances for rename operation to be atomic.
526
527
tmp , err := d .fs .TempFile ("" , tmpPackedRefsPrefix )
527
528
if err != nil {
528
529
return err
529
530
}
530
- doCloseTmp := true
531
+ tmpName := tmp . Name ()
531
532
defer func () {
532
- if doCloseTmp {
533
- ioutil .CheckClose (tmp , & err )
534
- }
533
+ ioutil .CheckClose (tmp , & err )
534
+ _ = d .fs .Remove (tmpName ) // don't check err, we might have renamed it
535
535
}()
536
536
537
537
s := bufio .NewScanner (pr )
@@ -558,26 +558,10 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
558
558
}
559
559
560
560
if ! found {
561
- doCloseTmp = false
562
- ioutil .CheckClose (tmp , & err )
563
- if err != nil {
564
- return err
565
- }
566
- // Delete the temp file if nothing needed to be removed.
567
- return d .fs .Remove (tmp .Name ())
568
- }
569
-
570
- doClosePR = false
571
- if err := pr .Close (); err != nil {
572
- return err
573
- }
574
-
575
- doCloseTmp = false
576
- if err := tmp .Close (); err != nil {
577
- return err
561
+ return nil
578
562
}
579
563
580
- return d .fs . Rename (tmp . Name (), packedRefsPath )
564
+ return d .rewritePackedRefsWhileLocked (tmp , pr )
581
565
}
582
566
583
567
// process lines from a packed-refs file
@@ -691,20 +675,15 @@ func (d *DotGit) CountLooseRefs() (int, error) {
691
675
// packed, plus all tags.
692
676
func (d * DotGit ) PackRefs () (err error ) {
693
677
// Lock packed-refs, and create it if it doesn't exist yet.
694
- f , err := d .fs . OpenFile ( packedRefsPath , os . O_RDWR | os . O_CREATE , 0600 )
678
+ f , err := d .openAndLockPackedRefs ( true )
695
679
if err != nil {
696
680
return err
697
681
}
698
682
defer ioutil .CheckClose (f , & err )
699
683
700
- err = f .Lock ()
701
- if err != nil {
702
- return err
703
- }
704
-
705
684
// Gather all refs using addRefsFromRefDir and addRefsFromPackedRefs.
706
685
var refs []* plumbing.Reference
707
- var seen = make (map [plumbing.ReferenceName ]bool )
686
+ seen : = make (map [plumbing.ReferenceName ]bool )
708
687
if err := d .addRefsFromRefDir (& refs , seen ); err != nil {
709
688
return err
710
689
}
@@ -722,12 +701,12 @@ func (d *DotGit) PackRefs() (err error) {
722
701
if err != nil {
723
702
return err
724
703
}
725
- doCloseTmp := true
704
+ tmpName := tmp . Name ()
726
705
defer func () {
727
- if doCloseTmp {
728
- ioutil .CheckClose (tmp , & err )
729
- }
706
+ ioutil .CheckClose (tmp , & err )
707
+ _ = d .fs .Remove (tmpName ) // don't check err, we might have renamed it
730
708
}()
709
+
731
710
w := bufio .NewWriter (tmp )
732
711
for _ , ref := range refs {
733
712
_ , err := w .WriteString (ref .String () + "\n " )
@@ -741,11 +720,7 @@ func (d *DotGit) PackRefs() (err error) {
741
720
}
742
721
743
722
// Rename the temp packed-refs file.
744
- doCloseTmp = false
745
- if err := tmp .Close (); err != nil {
746
- return err
747
- }
748
- err = d .fs .Rename (tmp .Name (), packedRefsPath )
723
+ err = d .rewritePackedRefsWhileLocked (tmp , f )
749
724
if err != nil {
750
725
return err
751
726
}
0 commit comments