@@ -387,17 +387,7 @@ func (d *DotGit) Ref(name plumbing.ReferenceName) (*plumbing.Reference, error) {
387
387
return d .packedRef (name )
388
388
}
389
389
390
- func (d * DotGit ) findPackedRefs () ([]* plumbing.Reference , error ) {
391
- f , err := d .fs .Open (packedRefsPath )
392
- if err != nil {
393
- if os .IsNotExist (err ) {
394
- return nil , nil
395
- }
396
- return nil , err
397
- }
398
-
399
- defer ioutil .CheckClose (f , & err )
400
-
390
+ func (d * DotGit ) findPackedRefsInFile (f billy.File ) ([]* plumbing.Reference , error ) {
401
391
s := bufio .NewScanner (f )
402
392
var refs []* plumbing.Reference
403
393
for s .Scan () {
@@ -414,6 +404,19 @@ func (d *DotGit) findPackedRefs() ([]*plumbing.Reference, error) {
414
404
return refs , s .Err ()
415
405
}
416
406
407
+ func (d * DotGit ) findPackedRefs () ([]* plumbing.Reference , error ) {
408
+ f , err := d .fs .Open (packedRefsPath )
409
+ if err != nil {
410
+ if os .IsNotExist (err ) {
411
+ return nil , nil
412
+ }
413
+ return nil , err
414
+ }
415
+
416
+ defer ioutil .CheckClose (f , & err )
417
+ return d .findPackedRefsInFile (f )
418
+ }
419
+
417
420
func (d * DotGit ) packedRef (name plumbing.ReferenceName ) (* plumbing.Reference , error ) {
418
421
refs , err := d .findPackedRefs ()
419
422
if err != nil {
@@ -460,20 +463,41 @@ func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference, seen map[plu
460
463
return nil
461
464
}
462
465
463
- func (d * DotGit ) openAndLockPackedRefs () (pr billy.File , err error ) {
466
+ func (d * DotGit ) addRefsFromPackedRefsFile (refs * []* plumbing.Reference , f billy.File , seen map [plumbing.ReferenceName ]bool ) (err error ) {
467
+ packedRefs , err := d .findPackedRefsInFile (f )
468
+ if err != nil {
469
+ return err
470
+ }
471
+
472
+ for _ , ref := range packedRefs {
473
+ if ! seen [ref .Name ()] {
474
+ * refs = append (* refs , ref )
475
+ seen [ref .Name ()] = true
476
+ }
477
+ }
478
+ return nil
479
+ }
480
+
481
+ func (d * DotGit ) openAndLockPackedRefs (doCreate bool ) (
482
+ pr billy.File , err error ) {
464
483
var f billy.File
465
484
defer func () {
466
485
if err != nil && f != nil {
467
486
ioutil .CheckClose (f , & err )
468
487
}
469
488
}()
470
489
490
+ openFlags := os .O_RDWR
491
+ if doCreate {
492
+ openFlags |= os .O_CREATE
493
+ }
494
+
471
495
// Keep trying to open and lock the file until we're sure the file
472
496
// didn't change between the open and the lock.
473
497
for {
474
- f , err = d .fs .Open (packedRefsPath )
498
+ f , err = d .fs .OpenFile (packedRefsPath , openFlags , 0600 )
475
499
if err != nil {
476
- if os .IsNotExist (err ) {
500
+ if os .IsNotExist (err ) && ! doCreate {
477
501
return nil , nil
478
502
}
479
503
@@ -507,31 +531,25 @@ func (d *DotGit) openAndLockPackedRefs() (pr billy.File, err error) {
507
531
}
508
532
509
533
func (d * DotGit ) rewritePackedRefsWithoutRef (name plumbing.ReferenceName ) (err error ) {
510
- pr , err := d .openAndLockPackedRefs ()
534
+ pr , err := d .openAndLockPackedRefs (false )
511
535
if err != nil {
512
536
return err
513
537
}
514
538
if pr == nil {
515
539
return nil
516
540
}
517
- doClosePR := true
518
- defer func () {
519
- if doClosePR {
520
- ioutil .CheckClose (pr , & err )
521
- }
522
- }()
541
+ defer ioutil .CheckClose (pr , & err )
523
542
524
543
// Creating the temp file in the same directory as the target file
525
544
// improves our chances for rename operation to be atomic.
526
545
tmp , err := d .fs .TempFile ("" , tmpPackedRefsPrefix )
527
546
if err != nil {
528
547
return err
529
548
}
530
- doCloseTmp := true
549
+ tmpName := tmp . Name ()
531
550
defer func () {
532
- if doCloseTmp {
533
- ioutil .CheckClose (tmp , & err )
534
- }
551
+ ioutil .CheckClose (tmp , & err )
552
+ _ = d .fs .Remove (tmpName ) // don't check err, we might have renamed it
535
553
}()
536
554
537
555
s := bufio .NewScanner (pr )
@@ -558,26 +576,10 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
558
576
}
559
577
560
578
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
579
+ return nil
578
580
}
579
581
580
- return d .fs . Rename (tmp . Name (), packedRefsPath )
582
+ return d .rewritePackedRefsWhileLocked (tmp , pr )
581
583
}
582
584
583
585
// process lines from a packed-refs file
@@ -691,20 +693,15 @@ func (d *DotGit) CountLooseRefs() (int, error) {
691
693
// packed, plus all tags.
692
694
func (d * DotGit ) PackRefs () (err error ) {
693
695
// 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 )
696
+ f , err := d .openAndLockPackedRefs ( true )
695
697
if err != nil {
696
698
return err
697
699
}
698
700
defer ioutil .CheckClose (f , & err )
699
701
700
- err = f .Lock ()
701
- if err != nil {
702
- return err
703
- }
704
-
705
702
// Gather all refs using addRefsFromRefDir and addRefsFromPackedRefs.
706
703
var refs []* plumbing.Reference
707
- var seen = make (map [plumbing.ReferenceName ]bool )
704
+ seen : = make (map [plumbing.ReferenceName ]bool )
708
705
if err := d .addRefsFromRefDir (& refs , seen ); err != nil {
709
706
return err
710
707
}
@@ -713,7 +710,7 @@ func (d *DotGit) PackRefs() (err error) {
713
710
return nil
714
711
}
715
712
numLooseRefs := len (refs )
716
- if err := d .addRefsFromPackedRefs (& refs , seen ); err != nil {
713
+ if err := d .addRefsFromPackedRefsFile (& refs , f , seen ); err != nil {
717
714
return err
718
715
}
719
716
@@ -722,12 +719,12 @@ func (d *DotGit) PackRefs() (err error) {
722
719
if err != nil {
723
720
return err
724
721
}
725
- doCloseTmp := true
722
+ tmpName := tmp . Name ()
726
723
defer func () {
727
- if doCloseTmp {
728
- ioutil .CheckClose (tmp , & err )
729
- }
724
+ ioutil .CheckClose (tmp , & err )
725
+ _ = d .fs .Remove (tmpName ) // don't check err, we might have renamed it
730
726
}()
727
+
731
728
w := bufio .NewWriter (tmp )
732
729
for _ , ref := range refs {
733
730
_ , err := w .WriteString (ref .String () + "\n " )
@@ -741,11 +738,7 @@ func (d *DotGit) PackRefs() (err error) {
741
738
}
742
739
743
740
// 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 )
741
+ err = d .rewritePackedRefsWhileLocked (tmp , f )
749
742
if err != nil {
750
743
return err
751
744
}
0 commit comments