@@ -5,6 +5,8 @@ pub mod merge_ff;
55pub mod merge_rebase;
66pub mod rename;
77
8+ use std:: collections:: HashSet ;
9+
810use super :: {
911 remotes:: get_default_remote_in_repo, utils:: bytes2string,
1012} ;
@@ -55,13 +57,20 @@ pub struct LocalBranch {
5557 pub remote : Option < String > ,
5658}
5759
60+ ///
61+ #[ derive( Debug ) ]
62+ pub struct RemoteBranch {
63+ ///
64+ pub has_tracking : bool ,
65+ }
66+
5867///
5968#[ derive( Debug ) ]
6069pub enum BranchDetails {
6170 ///
6271 Local ( LocalBranch ) ,
6372 ///
64- Remote ,
73+ Remote ( RemoteBranch ) ,
6574}
6675
6776///
@@ -107,13 +116,26 @@ pub fn get_branches_info(
107116) -> Result < Vec < BranchInfo > > {
108117 scope_time ! ( "get_branches_info" ) ;
109118
110- let filter = if local {
111- BranchType :: Local
119+ let repo = utils:: repo ( repo_path) ?;
120+
121+ let ( filter, remotes_with_tracking) = if local {
122+ ( BranchType :: Local , HashSet :: default ( ) )
112123 } else {
113- BranchType :: Remote
124+ let remotes: HashSet < _ > = repo
125+ . branches ( Some ( BranchType :: Local ) ) ?
126+ . filter_map ( |b| {
127+ let branch = b. ok ( ) ?. 0 ;
128+ let upstream = branch. upstream ( ) ;
129+ upstream
130+ . ok ( ) ?
131+ . name_bytes ( )
132+ . ok ( )
133+ . map ( ToOwned :: to_owned)
134+ } )
135+ . collect ( ) ;
136+ ( BranchType :: Remote , remotes)
114137 } ;
115138
116- let repo = utils:: repo ( repo_path) ?;
117139 let mut branches_for_display: Vec < BranchInfo > = repo
118140 . branches ( Some ( filter) ) ?
119141 . map ( |b| {
@@ -129,18 +151,23 @@ pub fn get_branches_info(
129151 . and_then ( git2:: Buf :: as_str)
130152 . map ( String :: from) ;
131153
154+ let name_bytes = branch. name_bytes ( ) ?;
155+
132156 let details = if local {
133157 BranchDetails :: Local ( LocalBranch {
134158 is_head : branch. is_head ( ) ,
135159 has_upstream : upstream. is_ok ( ) ,
136160 remote,
137161 } )
138162 } else {
139- BranchDetails :: Remote
163+ BranchDetails :: Remote ( RemoteBranch {
164+ has_tracking : remotes_with_tracking
165+ . contains ( name_bytes) ,
166+ } )
140167 } ;
141168
142169 Ok ( BranchInfo {
143- name : bytes2string ( branch . name_bytes ( ) ? ) ?,
170+ name : bytes2string ( name_bytes) ?,
144171 reference,
145172 top_commit_message : bytes2string (
146173 top_commit. summary_bytes ( ) . unwrap_or_default ( ) ,
@@ -668,6 +695,17 @@ mod test_remote_branches {
668695 repo_clone, repo_init_bare, write_commit_file,
669696 } ;
670697
698+ impl BranchInfo {
699+ /// returns details about remote branch or None
700+ const fn remote_details ( & self ) -> Option < & RemoteBranch > {
701+ if let BranchDetails :: Remote ( details) = & self . details {
702+ Some ( details)
703+ } else {
704+ None
705+ }
706+ }
707+ }
708+
671709 #[ test]
672710 fn test_remote_branches ( ) {
673711 let ( r1_dir, _repo) = repo_init_bare ( ) . unwrap ( ) ;
@@ -756,4 +794,49 @@ mod test_remote_branches {
756794
757795 assert_eq ! ( & get_branch_name( clone2_dir) . unwrap( ) , "foo" ) ;
758796 }
797+
798+ #[ test]
799+ fn test_has_tracking ( ) {
800+ let ( r1_dir, _repo) = repo_init_bare ( ) . unwrap ( ) ;
801+
802+ let ( clone1_dir, clone1) =
803+ repo_clone ( r1_dir. path ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
804+ let clone1_dir = clone1_dir. path ( ) . to_str ( ) . unwrap ( ) ;
805+
806+ // clone1
807+
808+ write_commit_file ( & clone1, "test.txt" , "test" , "commit1" ) ;
809+ push (
810+ clone1_dir, "origin" , "master" , false , false , None , None ,
811+ )
812+ . unwrap ( ) ;
813+ create_branch ( clone1_dir, "foo" ) . unwrap ( ) ;
814+ write_commit_file ( & clone1, "test.txt" , "test2" , "commit2" ) ;
815+ push ( clone1_dir, "origin" , "foo" , false , false , None , None )
816+ . unwrap ( ) ;
817+
818+ let branches_1 =
819+ get_branches_info ( clone1_dir, false ) . unwrap ( ) ;
820+
821+ assert ! ( branches_1[ 0 ] . remote_details( ) . unwrap( ) . has_tracking) ;
822+ assert ! ( branches_1[ 1 ] . remote_details( ) . unwrap( ) . has_tracking) ;
823+
824+ // clone2
825+
826+ let ( clone2_dir, _clone2) =
827+ repo_clone ( r1_dir. path ( ) . to_str ( ) . unwrap ( ) ) . unwrap ( ) ;
828+
829+ let clone2_dir = clone2_dir. path ( ) . to_str ( ) . unwrap ( ) ;
830+
831+ let branches_2 =
832+ get_branches_info ( clone2_dir, false ) . unwrap ( ) ;
833+
834+ assert ! (
835+ !branches_2[ 0 ] . remote_details( ) . unwrap( ) . has_tracking
836+ ) ;
837+ assert ! (
838+ !branches_2[ 1 ] . remote_details( ) . unwrap( ) . has_tracking
839+ ) ;
840+ assert ! ( branches_2[ 2 ] . remote_details( ) . unwrap( ) . has_tracking) ;
841+ }
759842}
0 commit comments