@@ -387,17 +387,7 @@ func (d *DotGit) Ref(name plumbing.ReferenceName) (*plumbing.Reference, error) {
387387 return d .packedRef (name )
388388}
389389
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 ) {
401391 s := bufio .NewScanner (f )
402392 var refs []* plumbing.Reference
403393 for s .Scan () {
@@ -414,6 +404,19 @@ func (d *DotGit) findPackedRefs() ([]*plumbing.Reference, error) {
414404 return refs , s .Err ()
415405}
416406
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+
417420func (d * DotGit ) packedRef (name plumbing.ReferenceName ) (* plumbing.Reference , error ) {
418421 refs , err := d .findPackedRefs ()
419422 if err != nil {
@@ -460,20 +463,41 @@ func (d *DotGit) addRefsFromPackedRefs(refs *[]*plumbing.Reference, seen map[plu
460463 return nil
461464}
462465
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 ) {
464483 var f billy.File
465484 defer func () {
466485 if err != nil && f != nil {
467486 ioutil .CheckClose (f , & err )
468487 }
469488 }()
470489
490+ openFlags := os .O_RDWR
491+ if doCreate {
492+ openFlags |= os .O_CREATE
493+ }
494+
471495 // Keep trying to open and lock the file until we're sure the file
472496 // didn't change between the open and the lock.
473497 for {
474- f , err = d .fs .Open (packedRefsPath )
498+ f , err = d .fs .OpenFile (packedRefsPath , openFlags , 0600 )
475499 if err != nil {
476- if os .IsNotExist (err ) {
500+ if os .IsNotExist (err ) && ! doCreate {
477501 return nil , nil
478502 }
479503
@@ -507,31 +531,25 @@ func (d *DotGit) openAndLockPackedRefs() (pr billy.File, err error) {
507531}
508532
509533func (d * DotGit ) rewritePackedRefsWithoutRef (name plumbing.ReferenceName ) (err error ) {
510- pr , err := d .openAndLockPackedRefs ()
534+ pr , err := d .openAndLockPackedRefs (false )
511535 if err != nil {
512536 return err
513537 }
514538 if pr == nil {
515539 return nil
516540 }
517- doClosePR := true
518- defer func () {
519- if doClosePR {
520- ioutil .CheckClose (pr , & err )
521- }
522- }()
541+ defer ioutil .CheckClose (pr , & err )
523542
524543 // Creating the temp file in the same directory as the target file
525544 // improves our chances for rename operation to be atomic.
526545 tmp , err := d .fs .TempFile ("" , tmpPackedRefsPrefix )
527546 if err != nil {
528547 return err
529548 }
530- doCloseTmp := true
549+ tmpName := tmp . Name ()
531550 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
535553 }()
536554
537555 s := bufio .NewScanner (pr )
@@ -558,26 +576,10 @@ func (d *DotGit) rewritePackedRefsWithoutRef(name plumbing.ReferenceName) (err e
558576 }
559577
560578 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
578580 }
579581
580- return d .fs . Rename (tmp . Name (), packedRefsPath )
582+ return d .rewritePackedRefsWhileLocked (tmp , pr )
581583}
582584
583585// process lines from a packed-refs file
@@ -691,20 +693,15 @@ func (d *DotGit) CountLooseRefs() (int, error) {
691693// packed, plus all tags.
692694func (d * DotGit ) PackRefs () (err error ) {
693695 // 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 )
695697 if err != nil {
696698 return err
697699 }
698700 defer ioutil .CheckClose (f , & err )
699701
700- err = f .Lock ()
701- if err != nil {
702- return err
703- }
704-
705702 // Gather all refs using addRefsFromRefDir and addRefsFromPackedRefs.
706703 var refs []* plumbing.Reference
707- var seen = make (map [plumbing.ReferenceName ]bool )
704+ seen : = make (map [plumbing.ReferenceName ]bool )
708705 if err := d .addRefsFromRefDir (& refs , seen ); err != nil {
709706 return err
710707 }
@@ -713,7 +710,7 @@ func (d *DotGit) PackRefs() (err error) {
713710 return nil
714711 }
715712 numLooseRefs := len (refs )
716- if err := d .addRefsFromPackedRefs (& refs , seen ); err != nil {
713+ if err := d .addRefsFromPackedRefsFile (& refs , f , seen ); err != nil {
717714 return err
718715 }
719716
@@ -722,12 +719,12 @@ func (d *DotGit) PackRefs() (err error) {
722719 if err != nil {
723720 return err
724721 }
725- doCloseTmp := true
722+ tmpName := tmp . Name ()
726723 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
730726 }()
727+
731728 w := bufio .NewWriter (tmp )
732729 for _ , ref := range refs {
733730 _ , err := w .WriteString (ref .String () + "\n " )
@@ -741,11 +738,7 @@ func (d *DotGit) PackRefs() (err error) {
741738 }
742739
743740 // 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 )
749742 if err != nil {
750743 return err
751744 }
0 commit comments