@@ -171,7 +171,17 @@ func (r *Remote) PushContext(ctx context.Context, o *PushOptions) (err error) {
171171 }
172172 }
173173
174- rs , err := pushHashes (ctx , s , r .s , req , hashesToPush , r .useRefDeltas (ar ))
174+ if len (hashesToPush ) == 0 {
175+ allDelete = true
176+ for _ , command := range req .Commands {
177+ if command .Action () != packp .Delete {
178+ allDelete = false
179+ break
180+ }
181+ }
182+ }
183+
184+ rs , err := pushHashes (ctx , s , r .s , req , hashesToPush , r .useRefDeltas (ar ), allDelete )
175185 if err != nil {
176186 return err
177187 }
@@ -204,7 +214,7 @@ func (r *Remote) newReferenceUpdateRequest(
204214 }
205215 }
206216
207- if err := r .addReferencesToUpdate (o .RefSpecs , localRefs , remoteRefs , req ); err != nil {
217+ if err := r .addReferencesToUpdate (o .RefSpecs , localRefs , remoteRefs , req , o . Prune ); err != nil {
208218 return nil , err
209219 }
210220
@@ -392,6 +402,7 @@ func (r *Remote) addReferencesToUpdate(
392402 localRefs []* plumbing.Reference ,
393403 remoteRefs storer.ReferenceStorer ,
394404 req * packp.ReferenceUpdateRequest ,
405+ prune bool ,
395406) error {
396407 // This references dictionary will be used to search references by name.
397408 refsDict := make (map [string ]* plumbing.Reference )
@@ -401,14 +412,20 @@ func (r *Remote) addReferencesToUpdate(
401412
402413 for _ , rs := range refspecs {
403414 if rs .IsDelete () {
404- if err := r .deleteReferences (rs , remoteRefs , req ); err != nil {
415+ if err := r .deleteReferences (rs , remoteRefs , refsDict , req , false ); err != nil {
405416 return err
406417 }
407418 } else {
408419 err := r .addOrUpdateReferences (rs , localRefs , refsDict , remoteRefs , req )
409420 if err != nil {
410421 return err
411422 }
423+
424+ if prune {
425+ if err := r .deleteReferences (rs , remoteRefs , refsDict , req , true ); err != nil {
426+ return err
427+ }
428+ }
412429 }
413430 }
414431
@@ -444,7 +461,10 @@ func (r *Remote) addOrUpdateReferences(
444461}
445462
446463func (r * Remote ) deleteReferences (rs config.RefSpec ,
447- remoteRefs storer.ReferenceStorer , req * packp.ReferenceUpdateRequest ) error {
464+ remoteRefs storer.ReferenceStorer ,
465+ refsDict map [string ]* plumbing.Reference ,
466+ req * packp.ReferenceUpdateRequest ,
467+ prune bool ) error {
448468 iter , err := remoteRefs .IterReferences ()
449469 if err != nil {
450470 return err
@@ -455,8 +475,19 @@ func (r *Remote) deleteReferences(rs config.RefSpec,
455475 return nil
456476 }
457477
458- if rs .Dst ("" ) != ref .Name () {
459- return nil
478+ if prune {
479+ rs := rs .Reverse ()
480+ if ! rs .Match (ref .Name ()) {
481+ return nil
482+ }
483+
484+ if _ , ok := refsDict [rs .Dst (ref .Name ()).String ()]; ok {
485+ return nil
486+ }
487+ } else {
488+ if rs .Dst ("" ) != ref .Name () {
489+ return nil
490+ }
460491 }
461492
462493 cmd := & packp.Command {
@@ -1015,10 +1046,11 @@ func pushHashes(
10151046 req * packp.ReferenceUpdateRequest ,
10161047 hs []plumbing.Hash ,
10171048 useRefDeltas bool ,
1049+ allDelete bool ,
10181050) (* packp.ReportStatus , error ) {
10191051
10201052 rd , wr := io .Pipe ()
1021- req . Packfile = rd
1053+
10221054 config , err := s .Config ()
10231055 if err != nil {
10241056 return nil , err
@@ -1029,15 +1061,20 @@ func pushHashes(
10291061 // to the channel.
10301062 done := make (chan error , 1 )
10311063
1032- go func () {
1033- e := packfile .NewEncoder (wr , s , useRefDeltas )
1034- if _ , err := e .Encode (hs , config .Pack .Window ); err != nil {
1035- done <- wr .CloseWithError (err )
1036- return
1037- }
1064+ if ! allDelete {
1065+ req .Packfile = rd
1066+ go func () {
1067+ e := packfile .NewEncoder (wr , s , useRefDeltas )
1068+ if _ , err := e .Encode (hs , config .Pack .Window ); err != nil {
1069+ done <- wr .CloseWithError (err )
1070+ return
1071+ }
10381072
1039- done <- wr .Close ()
1040- }()
1073+ done <- wr .Close ()
1074+ }()
1075+ } else {
1076+ close (done )
1077+ }
10411078
10421079 rs , err := sess .ReceivePack (ctx , req )
10431080 if err != nil {
0 commit comments