@@ -26,7 +26,6 @@ struct RecreateCommitParams<'a> {
2626 commit : & ' a CommitInfo ,
2727 crate_paths : & ' a [ PathBuf ] ,
2828 target_repo_path : & ' a Path ,
29- transform : & ' a CargoTransform ,
3029 workspace_root : & ' a Path ,
3130 crate_name : & ' a str ,
3231 mode : & ' a SplitMode ,
@@ -76,22 +75,8 @@ impl Splitter {
7675 fn walk_filtered_history ( & self , paths : & [ PathBuf ] ) -> RailResult < Vec < CommitInfo > > {
7776 println ! ( " Walking commit history to find commits touching crate..." ) ;
7877
79- // Collect commits that touch any of the paths
80- // Use HashSet + Vec to deduplicate while preserving insertion order from git log
81- let mut seen_shas = std:: collections:: HashSet :: new ( ) ;
82- let mut filtered_commits = Vec :: new ( ) ;
83-
84- for path in paths {
85- // Get all commits that touch this path (already in chronological order from git log --reverse)
86- let path_commits = self . git . get_commits_touching_path ( path, None , "HEAD" ) ?;
87-
88- // Add to our deduplication list (skip if already seen)
89- for commit in path_commits {
90- if seen_shas. insert ( commit. sha . clone ( ) ) {
91- filtered_commits. push ( commit) ;
92- }
93- }
94- }
78+ // Use batched git command for all paths at once (much faster than N separate calls)
79+ let filtered_commits = self . git . get_commits_touching_paths ( paths, None , "HEAD" ) ?;
9580
9681 println ! (
9782 " Found {} total commits that touch the crate paths" ,
@@ -101,6 +86,23 @@ impl Splitter {
10186 Ok ( filtered_commits)
10287 }
10388
89+ /// Apply Cargo.toml transformation to a manifest file
90+ /// Returns Ok(()) if transform succeeded or file doesn't exist
91+ fn apply_manifest_transform ( & self , manifest_path : & Path , crate_name : & str ) -> RailResult < ( ) > {
92+ if !manifest_path. exists ( ) {
93+ return Ok ( ( ) ) ;
94+ }
95+
96+ let content = std:: fs:: read_to_string ( manifest_path) ?;
97+ let context = TransformContext {
98+ crate_name : crate_name. to_string ( ) ,
99+ workspace_root : self . workspace_root . clone ( ) ,
100+ } ;
101+ let transformed = self . transform . transform_to_split ( & content, & context) ?;
102+ std:: fs:: write ( manifest_path, transformed) ?;
103+ Ok ( ( ) )
104+ }
105+
104106 /// Recreate a commit in the target repository with transforms applied
105107 /// Returns the new commit SHA
106108 fn recreate_commit_in_target ( & self , params : & RecreateCommitParams ) -> RailResult < String > {
@@ -143,19 +145,12 @@ impl Splitter {
143145 std:: fs:: create_dir_all ( parent) ?;
144146 }
145147
148+ // Write file content
149+ std:: fs:: write ( & target_path, content_bytes) ?;
150+
146151 // Apply Cargo.toml transformation if applicable
147152 if file_path. file_name ( ) == Some ( std:: ffi:: OsStr :: new ( "Cargo.toml" ) ) {
148- // Transform the manifest
149- let content = String :: from_utf8 ( content_bytes. clone ( ) )
150- . map_err ( |_| RailError :: message ( format ! ( "File '{}' is not valid UTF-8" , file_path. display( ) ) ) ) ?;
151- let context = TransformContext {
152- crate_name : params. crate_name . to_string ( ) ,
153- workspace_root : params. workspace_root . to_path_buf ( ) ,
154- } ;
155- let transformed = params. transform . transform_to_split ( & content, & context) ?;
156- std:: fs:: write ( & target_path, transformed) ?;
157- } else {
158- std:: fs:: write ( & target_path, content_bytes) ?;
153+ self . apply_manifest_transform ( & target_path, params. crate_name ) ?;
159154 }
160155 }
161156
@@ -391,7 +386,6 @@ impl Splitter {
391386 commit,
392387 crate_paths : & config. crate_paths ,
393388 target_repo_path : & config. target_repo_path ,
394- transform : & self . transform ,
395389 workspace_root : & self . workspace_root ,
396390 crate_name : & config. crate_name ,
397391 mode : & config. mode ,
@@ -417,17 +411,21 @@ impl Splitter {
417411 project_files. copy_to_split ( & self . workspace_root , & config. target_repo_path ) ?;
418412
419413 // Create a final commit if any files were added
420- let status = std:: process:: Command :: new ( "git" )
414+ // git add -A is safe to run unconditionally (no-op if no changes)
415+ std:: process:: Command :: new ( "git" )
421416 . current_dir ( & config. target_repo_path )
422- . args ( [ "status " , "--porcelain " ] )
423- . output ( ) ?;
417+ . args ( [ "add " , "-A " ] )
418+ . status ( ) ?;
424419
425- if !status. stdout . is_empty ( ) {
420+ // Check if there are staged changes before committing
421+ let diff_cached = std:: process:: Command :: new ( "git" )
422+ . current_dir ( & config. target_repo_path )
423+ . args ( [ "diff" , "--cached" , "--quiet" ] )
424+ . status ( ) ?;
425+
426+ if !diff_cached. success ( ) {
427+ // Exit code 1 means there are differences (i.e., staged changes)
426428 println ! ( " Creating commit for auxiliary files" ) ;
427- std:: process:: Command :: new ( "git" )
428- . current_dir ( & config. target_repo_path )
429- . args ( [ "add" , "-A" ] )
430- . status ( ) ?;
431429 std:: process:: Command :: new ( "git" )
432430 . current_dir ( & config. target_repo_path )
433431 . args ( [ "commit" , "-m" , "Add workspace configs and project files" ] )
@@ -609,17 +607,9 @@ impl Splitter {
609607 self . copy_directory_recursive ( & source_path, target_repo_path) ?;
610608
611609 // Transform Cargo.toml manifest
610+ println ! ( " Transforming Cargo.toml" ) ;
612611 let manifest_path = target_repo_path. join ( "Cargo.toml" ) ;
613- if manifest_path. exists ( ) {
614- println ! ( " Transforming Cargo.toml" ) ;
615- let content = std:: fs:: read_to_string ( & manifest_path) ?;
616- let context = TransformContext {
617- crate_name : crate_name. to_string ( ) ,
618- workspace_root : self . workspace_root . clone ( ) ,
619- } ;
620- let transformed = self . transform . transform_to_split ( & content, & context) ?;
621- std:: fs:: write ( & manifest_path, transformed) ?;
622- }
612+ self . apply_manifest_transform ( & manifest_path, crate_name) ?;
623613
624614 // Copy auxiliary files
625615 if !aux_files. is_empty ( ) {
@@ -653,15 +643,7 @@ impl Splitter {
653643
654644 // Transform Cargo.toml manifest
655645 let manifest_path = target_path. join ( "Cargo.toml" ) ;
656- if manifest_path. exists ( ) {
657- let content = std:: fs:: read_to_string ( & manifest_path) ?;
658- let context = TransformContext {
659- crate_name : crate_name. to_string ( ) ,
660- workspace_root : self . workspace_root . clone ( ) ,
661- } ;
662- let transformed = self . transform . transform_to_split ( & content, & context) ?;
663- std:: fs:: write ( & manifest_path, transformed) ?;
664- }
646+ self . apply_manifest_transform ( & manifest_path, crate_name) ?;
665647 }
666648
667649 // Copy auxiliary files
0 commit comments