@@ -96,6 +96,12 @@ impl PullResult {
9696 }
9797}
9898
99+ #[ derive( Debug , Serialize , Deserialize , Clone , PartialEq , Eq ) ]
100+ pub struct GitBranchInfo {
101+ pub name : String ,
102+ pub is_current : bool ,
103+ }
104+
99105pub struct GitManager {
100106 workdir : PathBuf ,
101107 status_cache : GitStatus ,
@@ -440,6 +446,57 @@ impl GitManager {
440446 Ok ( ( ) )
441447 }
442448
449+ pub fn list_branches ( & self ) -> Result < Vec < GitBranchInfo > > {
450+ let repo = self . repo ( ) ?;
451+ let current_branch = Self :: branch_name ( & repo) ;
452+ let mut branches = Vec :: new ( ) ;
453+
454+ for branch_result in repo. branches ( Some ( git2:: BranchType :: Local ) ) ? {
455+ let ( branch, _) = branch_result?;
456+ if let Some ( name) = branch. name ( ) ? {
457+ branches. push ( GitBranchInfo {
458+ name : name. to_string ( ) ,
459+ is_current : name == current_branch,
460+ } ) ;
461+ }
462+ }
463+
464+ branches. sort_by ( |a, b| a. name . cmp ( & b. name ) ) ;
465+ Ok ( branches)
466+ }
467+
468+ pub fn checkout_branch ( & self , branch : & str ) -> Result < ( ) > {
469+ let repo = self . repo ( ) ?;
470+ let mut status_opts = StatusOptions :: new ( ) ;
471+ status_opts
472+ . include_untracked ( true )
473+ . recurse_untracked_dirs ( true )
474+ . include_ignored ( false ) ;
475+ let statuses = repo. statuses ( Some ( & mut status_opts) ) ?;
476+ if !statuses. is_empty ( ) {
477+ anyhow:: bail!(
478+ "Failed to change branch\n Git command failed:\n You have local changes. Please commit your changes or stash them before you switch branches."
479+ ) ;
480+ }
481+
482+ let local_branch = repo
483+ . find_branch ( branch, git2:: BranchType :: Local )
484+ . with_context ( || format ! ( "Local branch '{}' not found" , branch) ) ?;
485+ let reference = local_branch. into_reference ( ) ;
486+ let reference_name = reference
487+ . name ( )
488+ . context ( "Invalid branch reference name" ) ?
489+ . to_string ( ) ;
490+
491+ repo. set_head ( & reference_name)
492+ . with_context ( || format ! ( "Failed to set HEAD to '{}'" , branch) ) ?;
493+ repo. checkout_head ( Some ( git2:: build:: CheckoutBuilder :: new ( ) . safe ( ) ) )
494+ . with_context ( || format ! ( "Failed to change branch to '{}'" , branch) ) ?;
495+
496+ info ! ( "Checked out branch {}" , branch) ;
497+ Ok ( ( ) )
498+ }
499+
443500 /// Pull from remote
444501 pub fn pull ( & self ) -> Result < PullResult > {
445502 let repo = self . repo ( ) ?;
0 commit comments