import chalk from 'chalk' ; import { ExitFailedError } from '../lib/errors' ; import { currentBranchPrecondition } from '../lib/preconditions' ; import { getTrunk , logTip } from '../lib/utils' ; import { GitStackBuilder , Stack , StackNode } from '../wrapper-classes' ; import Branch from '../wrapper-classes/branch' ; function getStacks ( ) { const stacks = new GitStackBuilder ( { useMemoizedResults : true , } ) . allStacks ( ) ; const trunkStack = stacks . find ( ( s ) => s . source . branch . isTrunk ( ) ) ; if ( ! trunkStack ) { throw new ExitFailedError ( `Unable to find trunk stack` ) ; } const fallenStacks = [ ] ; const untrackedStacks = [ ] ; stacks . filter ( ( s ) => ! s . source . branch . isTrunk ( ) ) . forEach ( ( s ) => { if ( s . source . branch . getParentFromMeta ( ) ) { fallenStacks . push ( s ) ; } else { untrackedStacks . push ( s ) ; } } ) ; return { trunkStack , fallenStacks , untrackedStacks } ; } export async function logShortAction ( ) { const currentBranch = currentBranchPrecondition ( ) ; const stacks = getStacks ( ) ; const tips = printStackNode ( stacks . trunkStack . source , { indent : 0 , currentBranch : currentBranch , } ) ; stacks . fallenStacks . sort ( sortStacksByAge ) . forEach ( ( s ) => { printStackNode ( s . source , { indent : 0 , currentBranch , } ) ; } ) ; if ( tips . needsFix || stacks . fallenStacks . length > 0 ) { logRebaseTip ( ) ; } if ( stacks . untrackedStacks . length > 0 ) { console . log ( '\nuntracked (created without Graphite)' ) ; stacks . untrackedStacks . sort ( sortStacksByAge ) . forEach ( ( s ) => printStackNode ( s . source , { indent : 0 , currentBranch , } ) ) ; } if ( stacks . untrackedStacks . length > 0 || tips . untracked ) { logRegenTip ( ) ; } } function sortStacksByAge ( a , b ) { return a . source . branch . lastCommitTime ( ) > b . source . branch . lastCommitTime ( ) ? - 1 : 1 ; } function printStackNode ( node , opts ) { const metaParent = node . branch . getParentFromMeta ( ) ; let untracked = ! metaParent && ! node . branch . isTrunk ( ) ; let needsFix = ! ! metaParent && ( ! node . parent || metaParent . name !== node . parent . branch . name ) ; console . log ( [ `${ '  ' . repeat ( opts . indent ) }` , node . branch . name === opts . currentBranch . name ? chalk . cyan ( `↳ ${ node . branch . name }` ) : `↳ ${ node . branch . name }` , ... ( needsFix ? [ chalk . yellow ( `(off ${ metaParent ?. name })` ) ] : [ ] ) , ... ( untracked ? [ chalk . yellow ( `(untracked)` ) ] : [ ] ) , ] . join ( ' ' ) ) ; node . children . forEach ( ( c ) => { if ( ! c . branch . isTrunk ( ) ) { const tips = printStackNode ( c , { indent : opts . indent + 1 , currentBranch : opts . currentBranch , } ) ; untracked = tips . untracked || untracked ; needsFix = tips . needsFix || needsFix ; } } ) ; return { untracked , needsFix } ; } function logRebaseTip ( ) { logTip ( [ `Some branch merge-bases have fallen behind their parent branch's latest commit. Consider:` , `> gt branch checkout ${ getTrunk ( ) } && gt stack fix --rebase # fix all stacks` , `> gt branch checkout <branch> && gt stack fix --rebase # fix a specific stack` , `> gt branch checkout <branch> && gt upstack onto <parent> # fix a stack and update the parent` , ] . join ( '\n' ) ) ; } function logRegenTip ( ) { logTip ( [ 'Graphite does not know the parent of untracked branches. Consider:' , `> gt branch checkout <branch> && gt upstack onto <parent> # fix a stack and update the parent` , `> gt branch checkout <branch> && gt stack fix --regen # generate stack based on current commit tree` , `> gt repo ignored-branches --add <branch> # set branch to be ignored by Graphite` , `> git branch -D <branch> # delete branch from git` , ] . join ( '\n' ) ) ; }