@@ -142,6 +142,12 @@ export default class ReleasePromotion extends Session {
142142 const workingOnNewReleaseCommit = await this . setupForNextRelease ( ) ;
143143 cli . stopSpinner ( 'Successfully set up for next release' ) ;
144144
145+ const shouldRebaseStagingBranch = await cli . prompt (
146+ 'Rebase staging branch on top of the release commit?' , { defaultAnswer : true } ) ;
147+ const tipOfStagingBranch = shouldRebaseStagingBranch
148+ ? await this . rebaseStagingBranch ( workingOnNewReleaseCommit )
149+ : workingOnNewReleaseCommit ;
150+
145151 // Cherry pick release commit to master.
146152 const shouldCherryPick = await cli . prompt (
147153 'Cherry-pick release commit to the default branch?' , { defaultAnswer : true } ) ;
@@ -200,7 +206,7 @@ export default class ReleasePromotion extends Session {
200206 }
201207
202208 // Push to the remote the release tag, and default, release, and staging branch.
203- await this . pushToRemote ( workingOnNewReleaseCommit ) ;
209+ await this . pushToRemote ( workingOnNewReleaseCommit , tipOfStagingBranch ) ;
204210
205211 // Promote and sign the release builds.
206212 await this . promoteAndSignRelease ( ) ;
@@ -440,7 +446,7 @@ export default class ReleasePromotion extends Session {
440446 return workingOnNewReleaseCommit . trim ( ) ;
441447 }
442448
443- async pushToRemote ( workingOnNewReleaseCommit ) {
449+ async pushToRemote ( workingOnNewReleaseCommit , tipOfStagingBranch ) {
444450 const { cli, dryRun, version, versionComponents, stagingBranch } = this ;
445451 const releaseBranch = `v${ versionComponents . major } .x` ;
446452 const tagVersion = `v${ version } ` ;
@@ -454,8 +460,8 @@ export default class ReleasePromotion extends Session {
454460 cli . info ( `git push ${ this . upstream } ${
455461 this . defaultBranch } ${
456462 tagVersion } ${
457- workingOnNewReleaseCommit } :refs/heads/${ releaseBranch } ${
458- workingOnNewReleaseCommit } :refs/heads/${ stagingBranch } `) ;
463+ workingOnNewReleaseCommit } :refs/heads/${ releaseBranch } + ${
464+ tipOfStagingBranch } :refs/heads/${ stagingBranch } `) ;
459465 cli . warn ( 'Once pushed, you must not delete the local tag' ) ;
460466 prompt = 'Ready to continue?' ;
461467 }
@@ -471,7 +477,7 @@ export default class ReleasePromotion extends Session {
471477 cli . startSpinner ( 'Pushing to remote' ) ;
472478 await forceRunAsync ( 'git' , [ 'push' , this . upstream , this . defaultBranch , tagVersion ,
473479 `${ workingOnNewReleaseCommit } :refs/heads/${ releaseBranch } ` ,
474- `${ workingOnNewReleaseCommit } :refs/heads/${ stagingBranch } ` ] ,
480+ `+ ${ tipOfStagingBranch } :refs/heads/${ stagingBranch } ` ] ,
475481 { ignoreFailure : false } ) ;
476482 cli . stopSpinner ( `Pushed ${ tagVersion } , ${ this . defaultBranch } , ${
477483 releaseBranch } , and ${ stagingBranch } to remote`) ;
@@ -507,6 +513,21 @@ export default class ReleasePromotion extends Session {
507513 cli . stopSpinner ( 'Release has been signed and promoted' ) ;
508514 }
509515
516+ async rebaseStagingBranch ( workingOnNewReleaseCommit ) {
517+ const { cli, stagingBranch, upstream } = this ;
518+ cli . startSpinner ( 'Fetch staging branch' ) ;
519+ await forceRunAsync ( 'git' , [ 'fetch' , upstream , stagingBranch ] , { ignoreFailure : false } ) ;
520+ cli . updateSpinner ( 'Reset and rebase' ) ;
521+ await forceRunAsync ( 'git' , [ 'reset' , 'FETCH_HEAD' , '--hard' ] , { ignoreFailure : false } ) ;
522+ await forceRunAsync ( 'git' ,
523+ [ 'rebase' , workingOnNewReleaseCommit , ...this . gpgSign ] , { ignoreFailure : false } ) ;
524+ const tipOfStagingBranch = await forceRunAsync ( 'git' , [ 'rev-parse' , 'HEAD' ] ,
525+ { ignoreFailure : false , captureStdout : true } ) ;
526+ cli . stopSpinner ( 'Rebased successfully' ) ;
527+
528+ return tipOfStagingBranch . trim ( ) ;
529+ }
530+
510531 async cherryPickToDefaultBranch ( ) {
511532 this . defaultBranch ??= await this . getDefaultBranch ( ) ;
512533 const releaseCommitSha = this . releaseCommitSha ;
0 commit comments