1212use std:: collections:: HashSet ;
1313use std:: ffi:: OsString ;
1414use std:: fmt:: Write ;
15- use std:: time:: SystemTime ;
15+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
1616
1717use chrono:: DateTime ;
18- use eyre:: OptionExt ;
18+ use eyre:: { OptionExt , WrapErr } ;
1919use git_branchless_invoke:: CommandContext ;
2020use git_branchless_opts:: { MessageArgs , RecordArgs , ResolveRevsetOptions , Revset } ;
2121use git_branchless_reword:: { ResolveFixupCommitError , edit_message, resolve_commit_to_fixup} ;
@@ -24,8 +24,9 @@ use lib::core::check_out::{CheckOutCommitOptions, CheckoutTarget, check_out_comm
2424use lib:: core:: config:: { get_commit_template, get_restack_preserve_timestamps} ;
2525use lib:: core:: dag:: { CommitSet , Dag } ;
2626use lib:: core:: effects:: { Effects , OperationType } ;
27- use lib:: core:: eventlog:: { EventLogDb , EventReplayer , EventTransactionId } ;
27+ use lib:: core:: eventlog:: { Event as LogEvent , EventLogDb , EventReplayer , EventTransactionId } ;
2828use lib:: core:: formatting:: Pluralize ;
29+ use lib:: core:: gc:: mark_commit_reachable;
2930use lib:: core:: repo_ext:: RepoExt ;
3031use lib:: core:: rewrite:: {
3132 BuildRebasePlanError , BuildRebasePlanOptions , ExecuteRebasePlanOptions ,
@@ -34,10 +35,10 @@ use lib::core::rewrite::{
3435} ;
3536use lib:: core:: untracked_file_cache:: { UntrackedFileStrategy , process_untracked_files} ;
3637use lib:: git:: {
37- CategorizedReferenceName , ConfigRead , FileMode , GitRunInfo , MaybeZeroOid , NonZeroOid , Repo ,
38- ResolvedReferenceInfo , Signature , Stage , UpdateIndexCommand , WorkingCopyChangesType ,
39- WorkingCopySnapshot , process_diff_for_record , summarize_diff_for_temporary_commit ,
40- update_index,
38+ CategorizedReferenceName , ConfigRead , FileMode , GitRunInfo , MaybeZeroOid , NonZeroOid ,
39+ ReferenceName , Repo , ResolvedReferenceInfo , Signature , Stage , UpdateIndexCommand ,
40+ WorkingCopyChangesType , WorkingCopySnapshot , process_diff_for_record ,
41+ summarize_diff_for_temporary_commit , update_index,
4142} ;
4243use lib:: try_exit_code;
4344use lib:: util:: { ExitCode , EyreExitOr } ;
@@ -112,6 +113,7 @@ fn record(
112113 & event_log_db,
113114 & event_tx_id,
114115 messages,
116+ branch_name,
115117 ) ?) ;
116118 } else {
117119 try_exit_code ! ( create_commit_with_changes(
@@ -454,13 +456,14 @@ fn create_new_commit(
454456 event_log_db : & EventLogDb ,
455457 event_tx_id : & EventTransactionId ,
456458 messages : Vec < String > ,
459+ branch_name : Option < String > ,
457460) -> EyreExitOr < ( ) > {
458461 let head_info = repo. get_head_info ( ) ?;
459- let current_commit_oid = match head_info {
462+ let ( current_commit_oid, existing_ref_name ) = match head_info {
460463 ResolvedReferenceInfo {
461464 oid : Some ( oid) ,
462- reference_name : _ ,
463- } => oid,
465+ reference_name,
466+ } => ( oid, reference_name ) ,
464467 ResolvedReferenceInfo {
465468 oid : None ,
466469 reference_name : _,
@@ -510,22 +513,46 @@ fn create_new_commit(
510513 vec ! [ & current_commit] ,
511514 ) ?;
512515
513- // TODO: move branch if ref_name
514- // TODO: mark commit reachable (will show in sl if descendants, but not if detached)
515- // FIXME: --new --create <branch> doesn't seem to work
516+ mark_commit_reachable ( repo, new_oid)
517+ . wrap_err ( "Marking commit as reachable for GC purposes." ) ?;
518+ event_log_db. add_events ( vec ! [ LogEvent :: CommitEvent {
519+ timestamp: now. duration_since( UNIX_EPOCH ) ?. as_secs_f64( ) ,
520+ event_tx_id: * event_tx_id,
521+ commit_oid: new_oid,
522+ } ] ) ?;
523+
524+ let checkout_target = if let Some ( name) = branch_name {
525+ // --create <branch>: create the new branch at the new commit.
526+ try_exit_code ! ( git_run_info. run(
527+ effects,
528+ Some ( * event_tx_id) ,
529+ & [ "branch" , & name, & new_oid. to_string( ) ] ,
530+ ) ?) ;
531+ let ref_name = ReferenceName :: from ( format ! ( "refs/heads/{name}" ) ) ;
532+ CheckoutTarget :: Reference ( ref_name)
533+ } else if let Some ( ref_name) = existing_ref_name {
534+ // On a named branch: advance it to the new commit, mirroring `git commit`.
535+ try_exit_code ! ( git_run_info. run(
536+ effects,
537+ Some ( * event_tx_id) ,
538+ & [ "update-ref" , ref_name. as_str( ) , & new_oid. to_string( ) ] ,
539+ ) ?) ;
540+ CheckoutTarget :: Reference ( ref_name)
541+ } else {
542+ // Detached HEAD, no --create: check out by OID.
543+ CheckoutTarget :: Oid ( new_oid)
544+ } ;
516545
517546 try_exit_code ! ( check_out_commit(
518547 effects,
519548 git_run_info,
520549 repo,
521550 event_log_db,
522551 * event_tx_id,
523- Some ( CheckoutTarget :: Oid ( new_oid ) ) ,
552+ Some ( checkout_target ) ,
524553 & CheckOutCommitOptions {
525- additional_args: vec![ ] ,
526- force_detach: false ,
527- reset: false ,
528554 render_smartlog: false ,
555+ ..Default :: default ( )
529556 } ,
530557 ) ?) ;
531558
0 commit comments