11use anyhow:: { anyhow, Result } ;
2- use std :: collections :: HashSet ;
2+ use logchop :: OptionLogger ;
33use std:: path:: Path ;
44use std:: str;
5+ use std:: { collections:: HashSet , convert:: TryInto } ;
56
67use duct:: cmd;
78use git2:: { Config , Repository } ;
@@ -138,13 +139,50 @@ pub fn guess_default_remote_name() -> Result<String> {
138139 }
139140}
140141
142+ /// Get the ID of the previous MR that had been checked out using git-req
143+ pub fn get_previous_mr_id ( ) -> Result < i64 > {
144+ let repo = Repository :: open_from_env ( ) . expect ( "Couldn't find repository" ) ;
145+ let testco = repo. find_reference ( "git-req/previous" ) ?;
146+ let content = testco. peel_to_blob ( ) ?;
147+ let binary = content. content ( ) ;
148+ let reqnum = i64:: from_le_bytes ( binary. try_into ( ) ?) ;
149+ debug ! ( "Loaded previous reference MR number: {}" , reqnum) ;
150+ Ok ( reqnum)
151+ }
152+
153+ /// Push a new `current` history ref, moving the existing `current` to `previous`
154+ pub fn push_current_ref ( new_req_number : i64 ) -> Result < i64 > {
155+ trace ! ( "Storing refs for MR {}" , new_req_number) ;
156+ let repo = Repository :: open_from_env ( ) . expect ( "Couldn't find repository" ) ;
157+ let old_oid = match repo. find_reference ( "git-req/current" ) {
158+ Ok ( current_ref) => current_ref
159+ . target ( )
160+ . debug_none ( "Could not peel current ref" ) ,
161+ Err ( _) => None ,
162+ } ;
163+ let data = new_req_number. to_le_bytes ( ) ;
164+ let new_oid = repo. blob ( & data) . unwrap ( ) ;
165+ if let Some ( oid) = old_oid {
166+ repo. reference ( "git-req/previous" , oid, true , "" ) . unwrap ( ) ;
167+ debug ! ( "Wrote old OID '{}' to git_req/previous" , oid) ;
168+ } ;
169+ repo. reference ( "git-req/current" , new_oid, true , "" ) ?;
170+ Ok ( new_req_number)
171+ }
172+
173+ #[ derive( Debug ) ]
174+ pub enum CheckoutResult {
175+ BranchChanged ,
176+ BranchUnchanged ,
177+ }
178+
141179/// Check out a branch by name
142180pub fn checkout_branch (
143181 remote_name : & str ,
144182 remote_branch_name : & str ,
145183 local_branch_name : & str ,
146184 is_virtual_remote_branch : bool ,
147- ) -> Result < ( ) > {
185+ ) -> Result < CheckoutResult > {
148186 let repo = Repository :: open_from_env ( ) . expect ( "Couldn't find repository" ) ;
149187 let local_branch_name = match get_project_config ( "defaultremote" ) {
150188 Some ( default_remote_name) => {
@@ -166,8 +204,16 @@ pub fn checkout_branch(
166204 match local_branch_exists {
167205 Ok ( _) => {
168206 debug ! ( "Checking out branch: {}" , local_branch_name) ;
207+ let head = repo. head ( ) ?;
208+ trace ! ( "On head: {:?}" , head. name( ) ) ;
209+ if head. is_branch ( )
210+ && head. name ( ) . unwrap ( ) == format ! ( "refs/heads/{}" , & local_branch_name)
211+ {
212+ // return Err(anyhow!("Already on {}", &local_branch_name));
213+ return Ok ( CheckoutResult :: BranchUnchanged ) ;
214+ }
169215 match cmd ! ( "git" , "checkout" , & local_branch_name) . run ( ) {
170- Ok ( _) => Ok ( ( ) ) ,
216+ Ok ( _) => Ok ( CheckoutResult :: BranchChanged ) ,
171217 Err ( err) => Err ( anyhow ! ( "Could not check out local branch: {}" , err) ) ,
172218 }
173219 }
@@ -203,7 +249,7 @@ pub fn checkout_branch(
203249 ) ;
204250 } ;
205251 match cmd ( "git" , checkout_args) . run ( ) {
206- Ok ( _) => Ok ( ( ) ) ,
252+ Ok ( _) => Ok ( CheckoutResult :: BranchChanged ) ,
207253 Err ( err) => Err ( anyhow ! ( "Could not check out local branch: {}" , err) ) ,
208254 }
209255 }
0 commit comments