@@ -61,7 +61,7 @@ export default class BackportSession extends Session {
6161 cli . stopSpinner ( `${ file } does not exist in current working tree` ,
6262 cli . SPINNER_STATUS . WARN ) ;
6363 continue ;
64- } ;
64+ }
6565 if ( ancestors . length === 0 ) {
6666 cli . stopSpinner ( `Cannot find ancestor commits of ${ file } ` ,
6767 cli . SPINNER_STATUS . INFO ) ;
@@ -155,12 +155,33 @@ export default class BackportSession extends Session {
155155 cli . log ( ` - ${ commit . sha } ${ commit . title } ` ) ;
156156 }
157157
158+ if ( ! this . isLocalBranchExists ( this . stagingBranch ) ) {
159+ const shouldCreateStagingBranch = await cli . prompt (
160+ `It seems like ${ this . stagingBranch } is missing locally, ` +
161+ 'do you want to create it locally to get ready for backporting?' , {
162+ defaultAnswer : true
163+ } ) ;
164+
165+ if ( shouldCreateStagingBranch ) {
166+ this . syncBranchWithUpstream ( this . stagingBranch ) ;
167+ }
168+ } else if ( ! this . isBranchUpToDateWithUpstream ( this . stagingBranch ) ) {
169+ const shouldSyncBranch = await cli . prompt (
170+ `It seems like your ${ this . stagingBranch } is behind the ${ this . upstream } remote` +
171+ 'do you want to sync it?' , { defaultAnswer : true } ) ;
172+
173+ if ( shouldSyncBranch ) {
174+ this . syncBranchWithUpstream ( this . stagingBranch ) ;
175+ }
176+ }
177+
158178 const newBranch = `backport-${ this . prid } -to-${ this . target } ` ;
159179 const shouldCheckout = await cli . prompt (
160180 `Do you want to checkout to a new branch \`${ newBranch } \`` +
161181 ' to start backporting?' , { defaultAnswer : false } ) ;
182+
162183 if ( shouldCheckout ) {
163- await runAsync ( 'git' , [ 'checkout' , '-b' , newBranch ] ) ;
184+ await runAsync ( 'git' , [ 'checkout' , '-b' , newBranch , this . stagingBranch ] ) ;
164185 }
165186
166187 const shouldAnalyze = await cli . prompt (
@@ -226,4 +247,56 @@ export default class BackportSession extends Session {
226247 } ;
227248 } ) ;
228249 }
250+
251+ getCurrentBranch ( ) {
252+ return runSync ( 'git' ,
253+ [ 'rev-parse' , '--abbrev-ref' , 'HEAD' ]
254+ ) . trim ( ) ;
255+ }
256+
257+ updateUpstreamRefs ( branchName ) {
258+ runSync ( 'git' ,
259+ [ 'fetch' , this . upstream , branchName ]
260+ ) ;
261+ }
262+
263+ getBranchCommit ( branch ) {
264+ return runSync ( 'git' ,
265+ [ 'rev-parse' , branch ]
266+ ) . trim ( ) ;
267+ }
268+
269+ isBranchUpToDateWithUpstream ( branch ) {
270+ this . updateUpstreamRefs ( branch ) ;
271+
272+ const localCommit = this . getBranchCommit ( branch ) ;
273+ const upstreamCommit = this . getBranchCommit ( `${ this . upstream } /${ branch } ` ) ;
274+
275+ return localCommit === upstreamCommit ;
276+ } ;
277+
278+ isLocalBranchExists ( branch ) {
279+ try {
280+ // will exit with code 1 if branch does not exist
281+ runSync ( 'git' ,
282+ [ 'rev-parse' , '--verify' , '--quiet' , branch ]
283+ ) ;
284+ return true ;
285+ } catch ( e ) {
286+ return false ;
287+ }
288+ }
289+
290+ syncBranchWithUpstream ( branch ) {
291+ const currentBranch = this . getCurrentBranch ( ) ;
292+
293+ runSync ( 'git' ,
294+ [
295+ currentBranch !== branch ? 'fetch' : 'pull' ,
296+ this . upstream ,
297+ `${ branch } :${ branch } ` ,
298+ '-f'
299+ ]
300+ ) ;
301+ }
229302}
0 commit comments