@@ -142,6 +142,12 @@ export default class ReleasePromotion extends Session {
142
142
const workingOnNewReleaseCommit = await this . setupForNextRelease ( ) ;
143
143
cli . stopSpinner ( 'Successfully set up for next release' ) ;
144
144
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
+
145
151
// Cherry pick release commit to master.
146
152
const shouldCherryPick = await cli . prompt (
147
153
'Cherry-pick release commit to the default branch?' , { defaultAnswer : true } ) ;
@@ -200,7 +206,7 @@ export default class ReleasePromotion extends Session {
200
206
}
201
207
202
208
// Push to the remote the release tag, and default, release, and staging branch.
203
- await this . pushToRemote ( workingOnNewReleaseCommit ) ;
209
+ await this . pushToRemote ( workingOnNewReleaseCommit , tipOfStagingBranch ) ;
204
210
205
211
// Promote and sign the release builds.
206
212
await this . promoteAndSignRelease ( ) ;
@@ -440,7 +446,7 @@ export default class ReleasePromotion extends Session {
440
446
return workingOnNewReleaseCommit . trim ( ) ;
441
447
}
442
448
443
- async pushToRemote ( workingOnNewReleaseCommit ) {
449
+ async pushToRemote ( workingOnNewReleaseCommit , tipOfStagingBranch ) {
444
450
const { cli, dryRun, version, versionComponents, stagingBranch } = this ;
445
451
const releaseBranch = `v${ versionComponents . major } .x` ;
446
452
const tagVersion = `v${ version } ` ;
@@ -454,8 +460,8 @@ export default class ReleasePromotion extends Session {
454
460
cli . info ( `git push ${ this . upstream } ${
455
461
this . defaultBranch } ${
456
462
tagVersion } ${
457
- workingOnNewReleaseCommit } :refs/heads/${ releaseBranch } ${
458
- workingOnNewReleaseCommit } :refs/heads/${ stagingBranch } `) ;
463
+ workingOnNewReleaseCommit } :refs/heads/${ releaseBranch } + ${
464
+ tipOfStagingBranch } :refs/heads/${ stagingBranch } `) ;
459
465
cli . warn ( 'Once pushed, you must not delete the local tag' ) ;
460
466
prompt = 'Ready to continue?' ;
461
467
}
@@ -471,7 +477,7 @@ export default class ReleasePromotion extends Session {
471
477
cli . startSpinner ( 'Pushing to remote' ) ;
472
478
await forceRunAsync ( 'git' , [ 'push' , this . upstream , this . defaultBranch , tagVersion ,
473
479
`${ workingOnNewReleaseCommit } :refs/heads/${ releaseBranch } ` ,
474
- `${ workingOnNewReleaseCommit } :refs/heads/${ stagingBranch } ` ] ,
480
+ `+ ${ tipOfStagingBranch } :refs/heads/${ stagingBranch } ` ] ,
475
481
{ ignoreFailure : false } ) ;
476
482
cli . stopSpinner ( `Pushed ${ tagVersion } , ${ this . defaultBranch } , ${
477
483
releaseBranch } , and ${ stagingBranch } to remote`) ;
@@ -507,6 +513,21 @@ export default class ReleasePromotion extends Session {
507
513
cli . stopSpinner ( 'Release has been signed and promoted' ) ;
508
514
}
509
515
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
+
510
531
async cherryPickToDefaultBranch ( ) {
511
532
this . defaultBranch ??= await this . getDefaultBranch ( ) ;
512
533
const releaseCommitSha = this . releaseCommitSha ;
0 commit comments