@@ -2,7 +2,9 @@ use crate::VirtualBranchesExt;
22use anyhow:: { Context , Result } ;
33use bstr:: { BStr , BString , ByteSlice } ;
44use core:: fmt;
5- use gitbutler_branch:: { Branch as GitButlerBranch , BranchId , ReferenceExtGix , Target } ;
5+ use gitbutler_branch:: {
6+ Branch as GitButlerBranch , BranchId , BranchIdentity , ReferenceExtGix , Target ,
7+ } ;
68use gitbutler_command_context:: CommandContext ;
79use gitbutler_reference:: normalize_branch_name;
810use gix:: prelude:: ObjectIdExt ;
@@ -33,9 +35,12 @@ pub fn list_branches(
3335 for reference in platform. all ( ) ?. filter_map ( Result :: ok) {
3436 // Loosely match on branch names
3537 if let Some ( branch_names) = & filter_branch_names {
36- let has_matching_name = branch_names
37- . iter ( )
38- . any ( |branch_name| reference. name ( ) . as_bstr ( ) . ends_with_str ( & branch_name. 0 ) ) ;
38+ let has_matching_name = branch_names. iter ( ) . any ( |branch_name| {
39+ reference
40+ . name ( )
41+ . as_bstr ( )
42+ . ends_with_str ( branch_name. as_bstr ( ) )
43+ } ) ;
3944
4045 if !has_matching_name {
4146 continue ;
@@ -189,9 +194,13 @@ fn branch_group_to_branch(
189194 } ;
190195
191196 if virtual_branch. is_none ( )
192- && local_branches
193- . iter ( )
194- . any ( |b| b. name ( ) . given_name ( remotes) . as_deref ( ) . ok ( ) == Some ( target. branch . branch ( ) ) )
197+ && local_branches. iter ( ) . any ( |b| {
198+ b. name ( )
199+ . identity ( remotes)
200+ . as_deref ( )
201+ . ok ( )
202+ . map_or ( false , |identity| identity == target. branch . branch ( ) )
203+ } )
195204 {
196205 return Ok ( None ) ;
197206 }
@@ -203,11 +212,10 @@ fn branch_group_to_branch(
203212 in_workspace : branch. in_workspace ,
204213 } ) ;
205214
206- // TODO(ST): keep the type alive, don't reduce to BString
207- let mut remotes: Vec < BString > = Vec :: new ( ) ;
215+ let mut remotes: Vec < gix:: remote:: Name < ' static > > = Vec :: new ( ) ;
208216 for branch in remote_branches. iter ( ) {
209217 if let Some ( remote_name) = branch. remote_name ( gix:: remote:: Direction :: Fetch ) {
210- remotes. push ( remote_name. as_bstr ( ) . into ( ) ) ;
218+ remotes. push ( remote_name. to_owned ( ) ) ;
211219 }
212220 }
213221
@@ -293,7 +301,7 @@ impl GroupBranch<'_> {
293301 fn identity ( & self , remotes : & BTreeSet < Cow < ' _ , BStr > > ) -> Option < BranchIdentity > {
294302 match self {
295303 GroupBranch :: Local ( branch) | GroupBranch :: Remote ( branch) => {
296- branch. name ( ) . given_name ( remotes) . ok ( )
304+ branch. name ( ) . identity ( remotes) . ok ( )
297305 }
298306 // The identity of a Virtual branch is derived from the source refname, upstream or the branch given name, in that order
299307 GroupBranch :: Virtual ( branch) => {
@@ -302,25 +310,24 @@ impl GroupBranch<'_> {
302310 let rich_name = branch. name . clone ( ) ;
303311 let rich_name = normalize_branch_name ( & rich_name) . ok ( ) ?;
304312 let identity = name_from_source. unwrap_or ( name_from_upstream. unwrap_or ( & rich_name) ) ;
305- Some ( identity. to_string ( ) )
313+ Some ( identity. into ( ) )
306314 }
307315 }
308- . map ( BranchIdentity )
316+ . map ( BranchIdentity :: from )
309317 }
310318}
311319
312320/// Determines if a branch should be listed in the UI.
313321/// This excludes the target branch as well as gitbutler specific branches.
314322fn should_list_git_branch ( identity : & BranchIdentity ) -> bool {
315323 // Exclude gitbutler technical branches (not useful for the user)
316- let is_technical = [
317- "gitbutler/integration" ,
318- "gitbutler/target" ,
319- "gitbutler/oplog" ,
320- "HEAD" ,
321- ]
322- . contains ( & & * identity. 0 ) ;
323- !is_technical
324+ const TECHNICAL_IDENTITIES : & [ & [ u8 ] ] = & [
325+ b"gitbutler/integration" ,
326+ b"gitbutler/target" ,
327+ b"gitbutler/oplog" ,
328+ b"HEAD" ,
329+ ] ;
330+ !TECHNICAL_IDENTITIES . contains ( & identity. as_bytes ( ) )
324331}
325332
326333/// A filter that can be applied to the branch listing
@@ -347,8 +354,8 @@ pub struct BranchListing {
347354 pub name : BranchIdentity ,
348355 /// This is a list of remotes that this branch can be found on (e.g. `origin`, `upstream` etc.),
349356 /// by collecting remotes from all local branches with the same identity that have a tracking setup.
350- #[ serde( serialize_with = "gitbutler_serde::serde::as_string_lossy_vec " ) ]
351- pub remotes : Vec < BString > ,
357+ #[ serde( serialize_with = "gitbutler_serde::as_string_lossy_vec_remote_name " ) ]
358+ pub remotes : Vec < gix :: remote :: Name < ' static > > ,
352359 /// The branch may or may not have a virtual branch associated with it.
353360 pub virtual_branch : Option < VirtualBranchReference > ,
354361 /// Timestamp in milliseconds since the branch was last updated.
@@ -370,52 +377,25 @@ pub struct BranchListing {
370377/// Represents a "commit author" or "signature", based on the data from the git history
371378#[ derive( Debug , Clone , Serialize , PartialEq , Eq , Hash ) ]
372379pub struct Author {
373- // TODO(ST): use `BString` here to not degenerate information
374380 /// The name of the author as configured in the git config
375- pub name : Option < String > ,
381+ pub name : Option < BString > ,
376382 /// The email of the author as configured in the git config
377- pub email : Option < String > ,
378- }
379-
380- /// The identity of a branch as to allow to group similar branches together.
381- ///
382- /// * For *local* branches, it is what's left without the standard prefix, like `refs/heads`, e.g. `main`
383- /// for `refs/heads/main` or `feat/one` for `refs/heads/feat/one`.
384- /// * For *remote* branches, it is what's without the prefix and remote name, like `main` for `refs/remotes/origin/main`.
385- /// or `feat/one` for `refs/remotes/my/special/remote/feat/one`.
386- /// * For virtual branches, it's either the above if there is a `source_refname` or an `upstream`, or it's the normalized
387- /// name of the virtual branch.
388- #[ derive( Debug , Clone , Serialize , PartialEq , Eq , Hash , Ord , PartialOrd ) ]
389- pub struct BranchIdentity ( String ) ;
390-
391- /// Facilitate obtaining this type from the UI - otherwise it would be better not to have it as it should be
392- /// a particular thing, not any string.
393- impl From < String > for BranchIdentity {
394- fn from ( value : String ) -> Self {
395- BranchIdentity ( value)
396- }
397- }
398-
399- /// Also not for testing.
400- impl From < & str > for BranchIdentity {
401- fn from ( value : & str ) -> Self {
402- BranchIdentity ( value. into ( ) )
403- }
383+ pub email : Option < BString > ,
404384}
405385
406386impl From < git2:: Signature < ' _ > > for Author {
407387 fn from ( value : git2:: Signature ) -> Self {
408- let name = value. name ( ) . map ( str:: to_string) ;
409- let email = value. email ( ) . map ( str:: to_string) ;
388+ let name = value. name ( ) . map ( str:: to_string) . map ( Into :: into ) ;
389+ let email = value. email ( ) . map ( str:: to_string) . map ( Into :: into ) ;
410390 Author { name, email }
411391 }
412392}
413393
414394impl From < gix:: actor:: SignatureRef < ' _ > > for Author {
415395 fn from ( value : gix:: actor:: SignatureRef < ' _ > ) -> Self {
416396 Author {
417- name : Some ( value. name . to_string ( ) ) ,
418- email : Some ( value. email . to_string ( ) ) ,
397+ name : Some ( value. name . to_owned ( ) ) ,
398+ email : Some ( value. email . to_owned ( ) ) ,
419399 }
420400 }
421401}
@@ -436,9 +416,13 @@ pub struct VirtualBranchReference {
436416/// a list of enriched branch data in the form of `BranchData`.
437417pub fn get_branch_listing_details (
438418 ctx : & CommandContext ,
439- branch_names : impl IntoIterator < Item = impl Into < BranchIdentity > > ,
419+ branch_names : impl IntoIterator < Item = impl TryInto < BranchIdentity > > ,
440420) -> Result < Vec < BranchListingDetails > > {
441- let branch_names: Vec < _ > = branch_names. into_iter ( ) . map ( Into :: into) . collect ( ) ;
421+ let branch_names: Vec < _ > = branch_names
422+ . into_iter ( )
423+ . map ( TryInto :: try_into)
424+ . filter_map ( Result :: ok)
425+ . collect ( ) ;
442426 let repo = ctx. repository ( ) ;
443427 let branches = list_branches ( ctx, None , Some ( branch_names. clone ( ) ) ) ?;
444428 let default_target = ctx
@@ -536,10 +520,10 @@ pub struct BranchEntry {
536520 /// The name of the branch (e.g. `main`, `feature/branch`)
537521 pub name : String ,
538522 /// The head commit of the branch
539- #[ serde( with = "gitbutler_serde::serde:: oid" ) ]
523+ #[ serde( with = "gitbutler_serde::oid" ) ]
540524 head : git2:: Oid ,
541525 /// The commit base of the branch
542- #[ serde( with = "gitbutler_serde::serde:: oid" ) ]
526+ #[ serde( with = "gitbutler_serde::oid" ) ]
543527 base : git2:: Oid ,
544528 /// The list of commits associated with the branch
545529 pub commits : Vec < CommitEntry > ,
@@ -568,18 +552,17 @@ pub struct RemoteBranchEntry {
568552#[ serde( rename_all = "camelCase" ) ]
569553pub struct CommitEntry {
570554 /// The commit sha that it can be referenced by
571- #[ serde( with = "gitbutler_serde::serde:: oid" ) ]
555+ #[ serde( with = "gitbutler_serde::oid" ) ]
572556 pub id : git2:: Oid ,
573557 /// If the commit is referencing a specific change, this is its change id
574558 pub change_id : Option < String > ,
575559 /// The commit message
576- #[ serde( serialize_with = "gitbutler_serde::serde::as_string_lossy" ) ]
577560 pub description : BString ,
578561 /// The timestamp of the commit in milliseconds
579562 pub created_at : u128 ,
580563 /// The author of the commit
581564 pub authors : Vec < Author > ,
582565 /// The parent commits of the commit
583- #[ serde( with = "gitbutler_serde::serde:: oid_vec" ) ]
566+ #[ serde( with = "gitbutler_serde::oid_vec" ) ]
584567 pub parent_ids : Vec < git2:: Oid > ,
585568}
0 commit comments