@@ -7,9 +7,9 @@ use anyhow::{Context, Result, anyhow, bail, ensure};
77use clap:: { Parser , Subcommand } ;
88use git:: {
99 DEFAULT_REMOTE , GitBranchStatus , after_text, git_branch_status, git_checkout_main, git_fetch,
10- git_remote_main, git_sha, is_ancestor, run_git_status, shas_match,
10+ git_get_upstream , git_remote_main, git_sha, is_ancestor, run_git_status, shas_match,
1111} ;
12- use state:: { Branch , RebaseStep , load_state , save_state } ;
12+ use state:: { Branch , RebaseStep } ;
1313use std:: env;
1414use std:: fs:: canonicalize;
1515use tracing:: level_filters:: LevelFilter ;
@@ -36,20 +36,28 @@ struct Args {
3636#[ derive( Subcommand ) ]
3737enum Command {
3838 /// Show the status of the git-stack tree in the current repo. This is the default command when
39- /// a command is omitted. (ie: `git stack` is the same as `git stack status`)
40- Status ,
39+ /// one is omitted. (ie: `git stack` is the same as `git stack status`)
40+ Status {
41+ /// Whether to fetch the latest changes from the remote before showing the status.
42+ #[ arg( long, short, default_value_t = false ) ]
43+ fetch : bool ,
44+ } ,
4145 /// Restack your active branch and all branches in its related stack.
4246 Restack {
4347 /// The name of the branch to restack.
4448 #[ arg( long, short) ]
4549 branch : Option < String > ,
50+ /// Push any changes up to the remote after restacking.
51+ #[ arg( long, short) ]
52+ push : bool ,
4653 } ,
4754 /// Shows the log between the given branch and its parent (git-stack tree) branch.
4855 Log {
4956 /// Specifies the branch whose log should be shown. If omitted, the current branch will
5057 /// be used.
5158 branch : Option < String > ,
5259 } ,
60+ /// Show or edit per-branch notes.
5361 Note {
5462 #[ arg( long, short, default_value_t = false ) ]
5563 edit : bool ,
@@ -96,7 +104,12 @@ fn inner_main() -> Result<()> {
96104
97105 tracing_subscriber:: registry ( )
98106 // We don't need timestamps in the logs.
99- . with ( tracing_subscriber:: fmt:: layer ( ) . without_time ( ) )
107+ . with (
108+ tracing_subscriber:: fmt:: layer ( )
109+ . with_file ( true )
110+ . with_line_number ( true )
111+ . without_time ( ) ,
112+ )
100113 // Allow usage of RUST_LOG environment variable to set the log level.
101114 . with (
102115 tracing_subscriber:: EnvFilter :: builder ( )
@@ -112,7 +125,7 @@ fn inner_main() -> Result<()> {
112125 . into_string ( )
113126 . map_err ( |error| anyhow ! ( "Invalid git directory: '{}'" , error. to_string_lossy( ) ) ) ?;
114127
115- let mut state = load_state ( ) . context ( "loading state" ) ?;
128+ let mut state = State :: load_state ( ) . context ( "loading state" ) ?;
116129 state. refresh_lkgs ( & repo) ?;
117130
118131 tracing:: debug!( "Current directory: {}" , repo) ;
@@ -121,22 +134,20 @@ fn inner_main() -> Result<()> {
121134 let current_branch = run_git ( & [ "rev-parse" , "--abbrev-ref" , "HEAD" ] ) ?
122135 . output ( )
123136 . ok_or ( anyhow ! ( "No current branch?" ) ) ?;
124- let current_upstream = run_git ( & [ "rev-parse" , "--abbrev-ref" , "@{upstream}" ] )
125- . ok ( )
126- . and_then ( |out| out. output ( ) ) ;
137+ let current_upstream = git_get_upstream ( "" ) ;
127138 tracing:: debug!( run_version, current_branch, current_upstream) ;
128139
129140 match args. command {
130141 Some ( Command :: Checkout { branch_name } ) => {
131142 state. checkout ( & repo, current_branch, current_upstream, branch_name)
132143 }
133- Some ( Command :: Restack { branch } ) => {
134- restack ( state, & repo, run_version, branch, current_branch)
144+ Some ( Command :: Restack { branch, push } ) => {
145+ restack ( state, & repo, run_version, branch, current_branch, push )
135146 }
136147 Some ( Command :: Mount { parent_branch } ) => {
137148 state. mount ( & repo, & current_branch, parent_branch)
138149 }
139- Some ( Command :: Status ) | None => status ( state, & repo, & current_branch) ,
150+ Some ( Command :: Status { fetch } ) => status ( state, & repo, & current_branch, fetch ) ,
140151 Some ( Command :: Delete { branch_name } ) => state. delete_branch ( & repo, & branch_name) ,
141152 Some ( Command :: Diff { branch } ) => diff ( state, & repo, & branch. unwrap_or ( current_branch) ) ,
142153 Some ( Command :: Log { branch } ) => show_log ( state, & repo, & branch. unwrap_or ( current_branch) ) ,
@@ -148,6 +159,7 @@ fn inner_main() -> Result<()> {
148159 state. show_note ( & repo, & branch)
149160 }
150161 }
162+ None => status ( state, & repo, & current_branch, false ) ,
151163 }
152164}
153165
@@ -237,10 +249,11 @@ fn recur_tree(
237249
238250 println ! (
239251 "{} ({}) {}{}{}" ,
240- if is_current_branch {
241- branch. name. truecolor( 142 , 192 , 124 ) . bold( )
242- } else {
243- branch. name. truecolor( 178 , 178 , 178 )
252+ match ( is_current_branch, branch_status. is_descendent) {
253+ ( true , true ) => branch. name. truecolor( 142 , 192 , 124 ) . bold( ) ,
254+ ( true , false ) => branch. name. truecolor( 215 , 153 , 33 ) . bold( ) ,
255+ ( false , true ) => branch. name. truecolor( 142 , 192 , 124 ) ,
256+ ( false , false ) => branch. name. truecolor( 215 , 153 , 33 ) ,
244257 } ,
245258 branch_status. sha[ ..8 ] . truecolor( 215 , 153 , 33 ) ,
246259 {
@@ -314,8 +327,11 @@ fn recur_tree(
314327 Ok ( ( ) )
315328}
316329
317- fn status ( state : State , repo : & str , orig_branch : & str ) -> Result < ( ) > {
318- git_fetch ( ) ?;
330+ fn status ( mut state : State , repo : & str , orig_branch : & str , fetch : bool ) -> Result < ( ) > {
331+ if fetch {
332+ git_fetch ( ) ?;
333+ }
334+ let trunk = state. ensure_trunk ( repo) ?;
319335
320336 let Some ( tree) = state. get_tree ( repo) else {
321337 eprintln ! (
@@ -332,6 +348,7 @@ fn status(state: State, repo: &str, orig_branch: &str) -> Result<()> {
332348 ) ;
333349 eprintln ! ( "Run `git stack mount <parent_branch>` to add it." ) ;
334350 }
351+ state. save_state ( ) ?;
335352 Ok ( ( ) )
336353}
337354
@@ -341,34 +358,35 @@ fn restack(
341358 run_version : String ,
342359 restack_branch : Option < String > ,
343360 orig_branch : String ,
361+ push : bool ,
344362) -> Result < ( ) , anyhow:: Error > {
345363 let restack_branch = restack_branch. unwrap_or ( orig_branch. clone ( ) ) ;
346364
347365 // Find starting_branch in the stacks of branches to determine which stack to use.
348366 let plan = state. plan_restack ( repo, & restack_branch) ?;
349367
350- tracing:: info !( ?plan, "Restacking branches with plan..." ) ;
368+ tracing:: debug !( ?plan, "Restacking branches with plan..." ) ;
351369 git_checkout_main ( None ) ?;
352370 for RebaseStep { parent, branch } in plan {
353- tracing:: info !(
371+ tracing:: debug !(
354372 "Starting branch: {} [pwd={}]" ,
355373 restack_branch,
356374 env:: current_dir( ) ?. display( )
357375 ) ;
358376 let source = git_sha ( & branch. name ) ?;
359377
360378 if is_ancestor ( & parent, & branch. name ) ? {
361- tracing:: info !(
379+ tracing:: debug !(
362380 "Branch '{}' is already stacked on '{}'." ,
363381 branch. name,
364382 parent
365383 ) ;
366- tracing:: info !( "Force-pushing '{}' to origin ..." , branch. name) ;
367- if !shas_match ( & format ! ( "origin /{}" , branch. name) , & branch. name ) {
384+ tracing:: debug !( "Force-pushing '{}' to {DEFAULT_REMOTE} ..." , branch. name) ;
385+ if push && !shas_match ( & format ! ( "{DEFAULT_REMOTE} /{}" , branch. name) , & branch. name ) {
368386 run_git ( & [
369387 "push" ,
370388 "-fu" ,
371- "origin" ,
389+ DEFAULT_REMOTE ,
372390 & format ! ( "{branch_name}:{branch_name}" , branch_name = branch. name) ,
373391 ] ) ?;
374392 }
@@ -404,7 +422,9 @@ fn restack(
404422 ) ;
405423 std:: process:: exit ( 1 ) ;
406424 }
407- git_push ( & branch. name ) ?;
425+ if push {
426+ git_push ( & branch. name ) ?;
427+ }
408428 continue ;
409429 } else {
410430 tracing:: info!(
@@ -425,7 +445,9 @@ fn restack(
425445 ) ;
426446 std:: process:: exit ( 1 ) ;
427447 }
428- git_push ( & branch. name ) ?;
448+ if push {
449+ git_push ( & branch. name ) ?;
450+ }
429451 tracing:: info!( "Rebase completed successfully. Continuing..." ) ;
430452 }
431453 }
@@ -441,8 +463,13 @@ fn restack(
441463}
442464
443465fn git_push ( branch : & str ) -> Result < ( ) > {
444- if !shas_match ( & format ! ( "origin/{}" , branch) , branch) {
445- run_git ( & [ "push" , "-fu" , "origin" , & format ! ( "{}:{}" , branch, branch) ] ) ?;
466+ if !shas_match ( & format ! ( "{DEFAULT_REMOTE}/{}" , branch) , branch) {
467+ run_git ( & [
468+ "push" ,
469+ "-fu" ,
470+ DEFAULT_REMOTE ,
471+ & format ! ( "{}:{}" , branch, branch) ,
472+ ] ) ?;
446473 }
447474 Ok ( ( ) )
448475}
0 commit comments