@@ -59,28 +59,27 @@ impl State {
5959 current_upstream : Option < String > ,
6060 branch_name : String ,
6161 ) -> Result < ( ) > {
62+ let trunk = git_trunk ( ) ?;
63+ // Ensure the main branch is in the git-stack tree for this repo if we haven't
64+ // added it yet.
65+ self . trees
66+ . entry ( repo. to_string ( ) )
67+ . or_insert_with ( || Branch :: new ( trunk. main_branch . clone ( ) , None ) ) ;
68+ save_state ( self ) ?;
69+
6270 let branch_exists_in_tree = self . branch_exists_in_tree ( repo, & branch_name) ;
63- let current_branch_exists_in_tree = self . branch_exists_in_tree ( repo, & current_branch) ;
6471
6572 if git_branch_exists ( & branch_name) {
6673 if !branch_exists_in_tree {
6774 tracing:: warn!(
6875 "Branch {branch_name} exists in the git repo but is not tracked by git-stack. \
69- If you'd like to add it to the git-stack, please checkout the desired parent \
70- branch, and then run `git-stack add {branch_name}` to stack {branch_name} on \
71- top of the parent branch.",
76+ If you'd like to add it to the git-stack, please run `git-stack mount \
77+ <parent-branch>` to stack {branch_name} on top of the parent branch.",
7278 ) ;
7379 }
7480 run_git ( & [ "checkout" , & branch_name] ) ?;
7581 return Ok ( ( ) ) ;
7682 }
77- let trunk = git_trunk ( ) ?;
78-
79- // Ensure the main branch is in the git-stack tree for this repo if we haven't
80- // added it yet.
81- self . trees
82- . entry ( repo. to_string ( ) )
83- . or_insert_with ( || Branch :: new ( trunk. main_branch . clone ( ) , None ) ) ;
8483
8584 let branch = self
8685 . get_tree_branch_mut ( repo, & current_branch)
@@ -139,17 +138,16 @@ impl State {
139138 let trunk = git_trunk ( ) ?;
140139 // Find all the descendents of the starting branch.
141140 // Traverse the tree from the starting branch to the root,
142- let mut path: Vec < & str > = vec ! [ ] ;
141+ let mut path: Vec < & Branch > = vec ! [ ] ;
143142 if !get_path ( self . trees . get ( repo) . unwrap ( ) , starting_branch, & mut path) {
144143 bail ! ( "Branch {starting_branch} not found in the git-stack tree." ) ;
145144 }
146- path. insert ( 0 , & trunk. remote_main ) ;
147145 Ok ( path
148146 . iter ( )
149147 . zip ( path. iter ( ) . skip ( 1 ) )
150148 . map ( |( parent, child) | RebaseStep {
151- parent : parent. to_string ( ) ,
152- branch : child. to_string ( ) ,
149+ parent : parent. name . to_string ( ) ,
150+ branch : child,
153151 } )
154152 . collect :: < Vec < _ > > ( ) )
155153 }
@@ -179,21 +177,25 @@ impl State {
179177 branch_name : & str ,
180178 parent_branch : Option < String > ,
181179 ) -> Result < ( ) > {
180+ let trunk = git_trunk ( ) ?;
181+ if trunk. main_branch == branch_name {
182+ bail ! (
183+ "Branch {branch_name} cannot be stacked on anything else." ,
184+ branch_name = branch_name. red( )
185+ ) ;
186+ }
187+
182188 let parent_branch = match parent_branch {
183189 Some ( parent_branch) => parent_branch,
184190 None => {
185191 tracing:: info!( "No parent branch specified, using main branch." ) ;
186192 // The branch might not exist in git, let's create it, and add it to the tree.
187- let remote_main = git_remote_main ( DEFAULT_REMOTE ) ?;
188- let main_branch = after_text ( & remote_main, format ! ( "{DEFAULT_REMOTE}/" ) )
189- . ok_or ( anyhow ! ( "no branch?" ) ) ?
190- . to_string ( ) ;
191193 // Ensure the main branch is in the git-stack tree for this repo if we haven't
192194 // added it yet.
193195 self . trees
194196 . entry ( repo. to_string ( ) )
195- . or_insert_with ( || Branch :: new ( main_branch. clone ( ) , None ) ) ;
196- main_branch
197+ . or_insert_with ( || Branch :: new ( trunk . main_branch . clone ( ) , None ) ) ;
198+ trunk . main_branch
197199 }
198200 } ;
199201
@@ -266,23 +268,31 @@ impl State {
266268 tracing:: debug!( "Refreshing lkgs for all branches..." ) ;
267269 let trunk = git_trunk ( ) ?;
268270
269- let mut parent_lkgs: HashMap < String , String > = HashMap :: default ( ) ;
271+ let mut parent_lkgs: HashMap < String , Option < String > > = HashMap :: default ( ) ;
270272
271- // Traverse the tree from the root to the leaves, and update the lkgs as we go.
273+ // BFS Traverse the tree from the root to the leaves, and update the lkgs as we go.
272274 let mut queue: VecDeque < ( Option < String > , String ) > = VecDeque :: new ( ) ;
273275 queue. push_back ( ( None , trunk. main_branch . clone ( ) ) ) ;
274276 while let Some ( ( parent, branch) ) = queue. pop_front ( ) {
275277 if let Some ( parent) = parent {
278+ let tree_branch = self . get_tree_branch ( repo, & branch) . unwrap ( ) ;
279+ if let Some ( lkg_parent) = tree_branch. lkg_parent . as_deref ( ) {
280+ if is_ancestor ( lkg_parent, & branch) ? {
281+ parent_lkgs. insert ( tree_branch. name . clone ( ) , Some ( lkg_parent. to_string ( ) ) ) ;
282+ } else {
283+ parent_lkgs. insert ( tree_branch. name . clone ( ) , None ) ;
284+ }
285+ }
276286 if is_ancestor ( & parent, & branch) . unwrap_or ( false ) {
277- if let Ok ( lkg_parent ) = git_sha ( & parent) {
287+ if let Ok ( new_lkg_parent ) = git_sha ( & parent) {
278288 tracing:: debug!(
279- ? lkg_parent,
289+ lkg_parent = ?new_lkg_parent ,
280290 "Branch {} is a descendent of {}" ,
281291 branch. yellow( ) ,
282292 parent. yellow( ) ,
283293 ) ;
284294 // Save the LKG parent for the branch.
285- parent_lkgs. insert ( branch. clone ( ) , lkg_parent ) ;
295+ parent_lkgs. insert ( branch. clone ( ) , Some ( new_lkg_parent ) ) ;
286296 }
287297 }
288298 }
@@ -297,31 +307,31 @@ impl State {
297307 let branch = self
298308 . get_tree_branch_mut ( repo, & branch)
299309 . ok_or_else ( || anyhow ! ( "Branch {branch} not found in the git-stack tree." ) ) ?;
300- branch. lkg_parent = Some ( lkg_parent) ;
310+ branch. lkg_parent = lkg_parent;
301311 }
302312 save_state ( self ) ?;
303313 Ok ( ( ) )
304314 }
305315}
306316
307- fn get_path < ' a > ( branch : & ' a Branch , target_branch : & str , path : & mut Vec < & ' a str > ) -> bool {
317+ fn get_path < ' a > ( branch : & ' a Branch , target_branch : & str , path : & mut Vec < & ' a Branch > ) -> bool {
308318 if branch. name == target_branch {
309- path. insert ( 0 , & branch. name ) ;
319+ path. insert ( 0 , branch) ;
310320 return true ;
311321 }
312322 for child_branch in & branch. branches {
313323 if get_path ( child_branch, target_branch, path) {
314- path. insert ( 0 , & branch. name ) ;
324+ path. insert ( 0 , branch) ;
315325 return true ;
316326 }
317327 }
318328 false
319329}
320330
321331#[ derive( Debug ) ]
322- pub ( crate ) struct RebaseStep {
332+ pub ( crate ) struct RebaseStep < ' a > {
323333 pub ( crate ) parent : String ,
324- pub ( crate ) branch : String ,
334+ pub ( crate ) branch : & ' a Branch ,
325335}
326336
327337fn find_branch_by_name < ' a > ( tree : & ' a Branch , name : & str ) -> Option < & ' a Branch > {
0 commit comments