@@ -56,6 +56,10 @@ enum Command {
5656 } ,
5757 /// Launch interactive TUI mode for branch navigation and checkout.
5858 Interactive ,
59+ /// Move up the stack to the parent branch.
60+ Up ,
61+ /// Move down the stack to a child branch (only if there's exactly one child).
62+ Down ,
5963 /// Open the git-stack state file in an editor for manual editing.
6064 Edit ,
6165 /// Restack your active branch onto its parent branch.
@@ -370,6 +374,14 @@ fn inner_main() -> Result<()> {
370374 state. try_auto_mount ( & git_repo, & repo, & current_branch) ?;
371375 interactive ( & git_repo, state, & repo, & current_branch, args. verbose )
372376 }
377+ Some ( Command :: Up ) => {
378+ state. try_auto_mount ( & git_repo, & repo, & current_branch) ?;
379+ navigate_up ( & state, & repo, & current_branch)
380+ }
381+ Some ( Command :: Down ) => {
382+ state. try_auto_mount ( & git_repo, & repo, & current_branch) ?;
383+ navigate_down ( & state, & repo, & current_branch)
384+ }
373385 Some ( Command :: Delete { branch_name } ) => state. delete_branch ( & repo, & branch_name) ,
374386 Some ( Command :: Cleanup { dry_run, all } ) => {
375387 state. cleanup_missing_branches ( & git_repo, & repo, dry_run, all)
@@ -592,6 +604,60 @@ fn interactive(
592604 Ok ( ( ) )
593605}
594606
607+ /// Navigate up the stack to the parent branch.
608+ fn navigate_up ( state : & State , repo : & str , current_branch : & str ) -> Result < ( ) > {
609+ let parent = state. get_parent_branch_of ( repo, current_branch) ;
610+
611+ match parent {
612+ Some ( parent_branch) => {
613+ run_git ( & [ "checkout" , & parent_branch. name ] ) ?;
614+ Ok ( ( ) )
615+ }
616+ None => {
617+ bail ! (
618+ "Branch '{}' has no parent in the stack (already at root)." ,
619+ current_branch. yellow( )
620+ ) ;
621+ }
622+ }
623+ }
624+
625+ /// Navigate down the stack to a child branch.
626+ fn navigate_down ( state : & State , repo : & str , current_branch : & str ) -> Result < ( ) > {
627+ let branch = state. get_tree_branch ( repo, current_branch) ;
628+
629+ match branch {
630+ Some ( branch) => {
631+ let children = & branch. branches ;
632+ match children. len ( ) {
633+ 0 => {
634+ bail ! (
635+ "Branch '{}' has no children in the stack." ,
636+ current_branch. yellow( )
637+ ) ;
638+ }
639+ 1 => {
640+ run_git ( & [ "checkout" , & children[ 0 ] . name ] ) ?;
641+ Ok ( ( ) )
642+ }
643+ n => {
644+ bail ! (
645+ "Branch '{}' has {} children. Use `git stack interactive` to choose." ,
646+ current_branch. yellow( ) ,
647+ n
648+ ) ;
649+ }
650+ }
651+ }
652+ None => {
653+ bail ! (
654+ "Branch '{}' not found in the stack." ,
655+ current_branch. yellow( )
656+ ) ;
657+ }
658+ }
659+ }
660+
595661/// Get concatenated commit messages between ancestor and branch tip.
596662fn get_concatenated_commit_messages ( branch : & str , ancestor : & str ) -> Result < String > {
597663 let output = run_git ( & [
0 commit comments