@@ -169,7 +169,7 @@ impl State {
169169 git2:: Error :: new (
170170 git2:: ErrorCode :: NotFound ,
171171 git2:: ErrorClass :: Reference ,
172- format ! ( "could not find base between {} and HEAD" , base. name ) ,
172+ format ! ( "could not find base between {} and HEAD" , base) ,
173173 )
174174 } )
175175 . with_code ( proc_exit:: Code :: USAGE_ERR ) ?;
@@ -239,28 +239,32 @@ struct StackState {
239239
240240impl StackState {
241241 fn update ( & mut self , repo : & dyn git_stack:: git:: Repo ) -> eyre:: Result < ( ) > {
242- self . base = repo
243- . find_local_branch ( self . base . name . as_str ( ) )
244- . ok_or_else ( || eyre:: eyre!( "can no longer find branch {}" , self . base. name) ) ?;
245- self . onto = repo
246- . find_local_branch ( self . onto . name . as_str ( ) )
247- . ok_or_else ( || eyre:: eyre!( "can no longer find branch {}" , self . onto. name) ) ?;
242+ self . base = update_branch ( repo, & self . base ) ?;
243+ self . onto = update_branch ( repo, & self . onto ) ?;
248244 self . branches . update ( repo) ;
249245 Ok ( ( ) )
250246 }
251247
252248 fn graphed_branches ( & self ) -> git_stack:: git:: Branches {
253249 let mut graphed_branches = self . branches . clone ( ) ;
254- if !graphed_branches. contains_oid ( self . base . id ) {
255- graphed_branches. insert ( self . base . clone ( ) ) ;
256- }
257- if !graphed_branches. contains_oid ( self . onto . id ) {
258- graphed_branches. insert ( self . onto . clone ( ) ) ;
259- }
250+ graphed_branches. insert ( self . base . clone ( ) ) ;
251+ graphed_branches. insert ( self . onto . clone ( ) ) ;
260252 graphed_branches
261253 }
262254}
263255
256+ fn update_branch (
257+ repo : & dyn git_stack:: git:: Repo ,
258+ branch : & git_stack:: git:: Branch ,
259+ ) -> eyre:: Result < git_stack:: git:: Branch > {
260+ if let Some ( remote) = & branch. remote {
261+ repo. find_remote_branch ( remote, & branch. name )
262+ } else {
263+ repo. find_local_branch ( & branch. name )
264+ }
265+ . ok_or_else ( || eyre:: eyre!( "Can no longer find branch {}" , branch) )
266+ }
267+
264268pub fn stack (
265269 args : & crate :: args:: Args ,
266270 colored_stdout : bool ,
@@ -280,7 +284,7 @@ pub fn stack(
280284 . flat_map ( |stack| stack. branches . iter ( ) )
281285 . filter ( |( oid, _) | !state. protected_branches . contains_oid ( * oid) )
282286 . flat_map ( |( _, b) | b. iter ( ) )
283- . filter_map ( |b| b. push_id . map ( |_| b. name . as_str ( ) ) )
287+ . filter_map ( |b| b. push_id . and_then ( |_| b. local_name ( ) ) )
284288 . collect ( ) ;
285289 push_branches. sort_unstable ( ) ;
286290 if !push_branches. is_empty ( ) {
@@ -297,14 +301,11 @@ pub fn stack(
297301 match git_fetch_upstream ( & mut state. repo , stack. onto . name . as_str ( ) ) {
298302 Ok ( _) => ( ) ,
299303 Err ( err) => {
300- log:: warn!( "Skipping pull of `{}`, {}" , stack. onto. name , err) ;
304+ log:: warn!( "Skipping pull of `{}`, {}" , stack. onto, err) ;
301305 }
302306 }
303307 } else {
304- log:: warn!(
305- "Skipping pull of `{}`, not a protected branch" ,
306- stack. onto. name
307- ) ;
308+ log:: warn!( "Skipping pull of `{}`, not a protected branch" , stack. onto) ;
308309 }
309310 }
310311 state. update ( ) . with_code ( proc_exit:: Code :: FAILURE ) ?;
@@ -355,7 +356,9 @@ pub fn stack(
355356 . map ( |stack| {
356357 let script = plan_changes ( & state, stack) . with_code ( proc_exit:: Code :: FAILURE ) ?;
357358 if script. is_branch_deleted ( & head_branch) {
358- head_branch = stack. onto . name . clone ( ) ;
359+ if let Some ( local_name) = stack. onto . local_name ( ) {
360+ head_branch = local_name. to_owned ( ) ;
361+ }
359362 }
360363 Ok ( script)
361364 } )
@@ -411,7 +414,7 @@ pub fn stack(
411414}
412415
413416fn plan_changes ( state : & State , stack : & StackState ) -> eyre:: Result < git_stack:: git:: Script > {
414- log:: trace!( "Planning stack changes with base={}" , stack. base. name , ) ;
417+ log:: trace!( "Planning stack changes with base={}" , stack. base, ) ;
415418 let graphed_branches = stack. graphed_branches ( ) ;
416419 let base_commit = state
417420 . repo
@@ -445,7 +448,7 @@ fn plan_changes(state: &State, stack: &StackState) -> eyre::Result<git_stack::gi
445448
446449 let mut dropped_branches = Vec :: new ( ) ;
447450 if state. rebase {
448- log:: trace!( "Rebasing onto {}" , stack. onto. name ) ;
451+ log:: trace!( "Rebasing onto {}" , stack. onto) ;
449452 let onto_id = stack. onto . pull_id . unwrap_or ( stack. onto . id ) ;
450453 let pull_start_id = stack. onto . id ;
451454 let pull_start_id = state
@@ -542,12 +545,12 @@ fn show(state: &State, colored_stdout: bool, colored_stderr: bool) -> eyre::Resu
542545 if graphed_branches. len ( ) == 1 && abbrev_graph {
543546 let branches = graphed_branches. iter ( ) . next ( ) . unwrap ( ) . 1 ;
544547 if branches. len ( ) == 1 && branches[ 0 ] . id != state. head_commit . id {
545- empty_stacks. push ( format ! ( "{}" , palette_stderr. info. paint( & branches[ 0 ] . name ) ) ) ;
548+ empty_stacks. push ( format ! ( "{}" , palette_stderr. info. paint( & branches[ 0 ] ) ) ) ;
546549 continue ;
547550 }
548551 }
549552
550- log:: trace!( "Rendering stack base={}" , stack. base. name , ) ;
553+ log:: trace!( "Rendering stack base={}" , stack. base, ) ;
551554 let base_commit = state
552555 . repo
553556 . find_commit ( stack. base . id )
@@ -605,7 +608,7 @@ fn show(state: &State, colored_stdout: bool, colored_stderr: bool) -> eyre::Resu
605608 if state. dry_run {
606609 // Show as-if we performed all mutations
607610 if state. rebase {
608- log:: trace!( "Rebasing onto {}" , stack. onto. name ) ;
611+ log:: trace!( "Rebasing onto {}" , stack. onto) ;
609612 let onto_id = stack. onto . pull_id . unwrap_or ( stack. onto . id ) ;
610613 let pull_start_id = stack. onto . id ;
611614 let pull_start_id = state
@@ -709,11 +712,27 @@ fn show(state: &State, colored_stdout: bool, colored_stderr: bool) -> eyre::Resu
709712}
710713
711714fn resolve_explicit_base (
712- repo : & dyn git_stack:: git:: Repo ,
715+ repo : & git_stack:: git:: GitRepo ,
713716 base : & str ,
714717) -> eyre:: Result < git_stack:: git:: Branch > {
715- repo. find_local_branch ( base)
716- . ok_or_else ( || eyre:: eyre!( "could not find branch {:?}" , base) )
718+ let ( _obj, r) = repo. raw ( ) . revparse_ext ( base) ?;
719+ let r = r. ok_or_else ( || eyre:: eyre!( "Expected branch, got `{}`" , base) ) ?;
720+ if r. is_tag ( ) {
721+ eyre:: bail!( "Expected branch, got tag `{}`" , base) ;
722+ }
723+
724+ if r. is_remote ( ) {
725+ let ( remote, name) = r
726+ . shorthand ( )
727+ . ok_or_else ( || eyre:: eyre!( "Expected branch, got `{}`" , base) ) ?
728+ . split_once ( '/' )
729+ . unwrap ( ) ;
730+ repo. find_remote_branch ( remote, name)
731+ . ok_or_else ( || eyre:: eyre!( "Could not find branch {:?}" , r. shorthand( ) ) )
732+ } else {
733+ repo. find_local_branch ( base)
734+ . ok_or_else ( || eyre:: eyre!( "Could not find branch {:?}" , base) )
735+ }
717736}
718737
719738fn resolve_implicit_base (
@@ -723,13 +742,13 @@ fn resolve_implicit_base(
723742 protected_branches : & git_stack:: git:: Branches ,
724743) -> eyre:: Result < git_stack:: git:: Branch > {
725744 let branch = git_stack:: git:: find_protected_base ( repo, protected_branches, head_oid)
726- . ok_or_else ( || eyre:: eyre!( "could not find a protected branch to use as a base" ) ) ?;
745+ . ok_or_else ( || eyre:: eyre!( "Could not find a protected branch to use as a base" ) ) ?;
727746 log:: debug!(
728747 "Chose branch {} as the base for {}" ,
729- branch. name ,
748+ branch,
730749 branches
731750 . get( head_oid)
732- . map( |b| b[ 0 ] . name . clone ( ) )
751+ . map( |b| b[ 0 ] . to_string ( ) )
733752 . or_else( || {
734753 repo. find_commit( head_oid) ?
735754 . summary
@@ -828,7 +847,7 @@ fn git_push(
828847 if failed. is_empty ( ) {
829848 Ok ( ( ) )
830849 } else {
831- eyre:: bail!( "could not push {}" , failed. into_iter( ) . join( ", " ) ) ;
850+ eyre:: bail!( "Could not push {}" , failed. into_iter( ) . join( ", " ) ) ;
832851 }
833852}
834853
@@ -839,10 +858,16 @@ fn git_push_node(
839858) -> Vec < String > {
840859 let mut failed = Vec :: new ( ) ;
841860 for branch in node. branches . iter ( ) {
861+ let local_branch = if let Some ( local_name) = branch. local_name ( ) {
862+ local_name
863+ } else {
864+ continue ;
865+ } ;
866+
842867 if node. pushable {
843868 let raw_branch = repo
844869 . raw ( )
845- . find_branch ( & branch . name , git2:: BranchType :: Local )
870+ . find_branch ( local_branch , git2:: BranchType :: Local )
846871 . expect ( "all referenced branches exist" ) ;
847872 let upstream_set = raw_branch. upstream ( ) . is_ok ( ) ;
848873
@@ -852,26 +877,26 @@ fn git_push_node(
852877 args. push ( "--set-upstream" ) ;
853878 }
854879 args. push ( remote) ;
855- args. push ( & branch . name ) ;
880+ args. push ( local_branch ) ;
856881 log:: trace!( "git {}" , args. join( " " ) , ) ;
857882 if !dry_run {
858883 let status = std:: process:: Command :: new ( "git" ) . args ( & args) . status ( ) ;
859884 match status {
860885 Ok ( status) => {
861886 if !status. success ( ) {
862- failed. push ( branch . name . clone ( ) ) ;
887+ failed. push ( local_branch . to_owned ( ) ) ;
863888 }
864889 }
865890 Err ( err) => {
866891 log:: debug!( "`git push` failed with {}" , err) ;
867- failed. push ( branch . name . clone ( ) ) ;
892+ failed. push ( local_branch . to_owned ( ) ) ;
868893 }
869894 }
870895 }
871896 } else if node. action . is_protected ( ) {
872- log:: debug!( "Skipping push of `{}`, protected" , branch. name ) ;
897+ log:: debug!( "Skipping push of `{}`, protected" , branch) ;
873898 } else {
874- log:: debug!( "Skipping push of `{}`" , branch. name ) ;
899+ log:: debug!( "Skipping push of `{}`" , branch) ;
875900 }
876901 }
877902
@@ -891,8 +916,8 @@ fn list(
891916 let mut branches: Vec < _ > = node. branches . iter ( ) . collect ( ) ;
892917 branches. sort ( ) ;
893918 for b in branches {
894- if protected. into_iter ( ) . flatten ( ) . contains ( & b) {
895- // Base / protected branches are just show for context, they aren't part of the
919+ if b . remote . is_some ( ) || protected. into_iter ( ) . flatten ( ) . contains ( & b) {
920+ // Base, remote, and protected branches are just shown for context, they aren't part of the
896921 // stack, so skip them here
897922 continue ;
898923 }
@@ -1305,15 +1330,27 @@ impl<'r> std::fmt::Display for RenderNode<'r> {
13051330 } else {
13061331 let mut branches: Vec < _ > = node. branches . iter ( ) . collect ( ) ;
13071332 branches. sort_by_key ( |b| {
1308- let is_head = self . head_branch . id == b. id && self . head_branch . name == b. name ;
1333+ let is_head = self . head_branch . id == b. id
1334+ && self . head_branch . remote == b. remote
1335+ && self . head_branch . name == b. name ;
13091336 let head_first = !is_head;
1310- ( head_first, & b. name )
1337+ ( head_first, & b. remote , & b . name )
13111338 } ) ;
13121339 write ! (
13131340 f,
13141341 "{}" ,
13151342 branches
1316- . into_iter( )
1343+ . iter( )
1344+ . filter( |b| {
1345+ if b. remote. is_some( ) {
1346+ let local_present = branches
1347+ . iter( )
1348+ . any( |b| b. local_name( ) == Some ( b. name. as_str( ) ) ) ;
1349+ !local_present
1350+ } else {
1351+ true
1352+ }
1353+ } )
13171354 . map( |b| {
13181355 format!(
13191356 "{}{}" ,
@@ -1361,17 +1398,22 @@ fn format_branch_name<'d>(
13611398 protected_branches : & ' d git_stack:: git:: Branches ,
13621399 palette : & ' d Palette ,
13631400) -> impl std:: fmt:: Display + ' d {
1364- if head_branch. id == branch. id && head_branch. name == branch. name {
1365- palette. highlight . paint ( branch. name . as_str ( ) )
1401+ if head_branch. id == branch. id
1402+ && head_branch. remote == branch. remote
1403+ && head_branch. name == branch. name
1404+ {
1405+ palette. highlight . paint ( branch. to_string ( ) )
13661406 } else {
13671407 let protected = protected_branches. get ( branch. id ) ;
13681408 if protected. into_iter ( ) . flatten ( ) . contains ( & branch) {
1369- palette. info . paint ( branch. name . as_str ( ) )
1409+ palette. info . paint ( branch. to_string ( ) )
1410+ } else if branch. remote . is_some ( ) {
1411+ palette. info . paint ( branch. to_string ( ) )
13701412 } else if node. action . is_protected ( ) {
13711413 // Either haven't started dev or it got merged
1372- palette. warn . paint ( branch. name . as_str ( ) )
1414+ palette. warn . paint ( branch. to_string ( ) )
13731415 } else {
1374- palette. good . paint ( branch. name . as_str ( ) )
1416+ palette. good . paint ( branch. to_string ( ) )
13751417 }
13761418 }
13771419}
0 commit comments