@@ -419,7 +419,7 @@ pub enum CherryPickFastError {
419419
420420/// Options for `Repo::amend_fast`
421421#[ derive( Debug ) ]
422- pub enum AmendFastOptions {
422+ pub enum AmendFastOptions < ' repo > {
423423 /// Amend a set of paths from the current state of the working copy.
424424 FromWorkingCopy {
425425 /// The status entries for the files to amend.
@@ -430,14 +430,20 @@ pub enum AmendFastOptions {
430430 /// The paths to amend.
431431 paths : Vec < PathBuf > ,
432432 } ,
433+ /// Amend a set of paths from a different commit.
434+ FromCommit {
435+ /// The commit whose contents will be ammended.
436+ commit : Commit < ' repo > ,
437+ } ,
433438}
434439
435- impl AmendFastOptions {
440+ impl < ' repo > AmendFastOptions < ' repo > {
436441 /// Returns whether there are any paths to be amended.
437442 pub fn is_empty ( & self ) -> bool {
438443 match & self {
439444 AmendFastOptions :: FromIndex { paths } => paths. is_empty ( ) ,
440445 AmendFastOptions :: FromWorkingCopy { status_entries } => status_entries. is_empty ( ) ,
446+ AmendFastOptions :: FromCommit { commit } => commit. is_empty ( ) ,
441447 }
442448 }
443449}
@@ -1378,6 +1384,11 @@ impl Repo {
13781384 result. extend ( entry. paths ( ) . iter ( ) . cloned ( ) ) ;
13791385 }
13801386 }
1387+ AmendFastOptions :: FromCommit { commit } => {
1388+ if let Some ( paths) = self . get_paths_touched_by_commit ( commit) ? {
1389+ result. extend ( paths. iter ( ) . cloned ( ) ) ;
1390+ }
1391+ }
13811392 } ;
13821393 result. into_iter ( ) . collect_vec ( )
13831394 } ;
@@ -1431,6 +1442,27 @@ impl Repo {
14311442 } )
14321443 . collect :: < HashMap < _ , _ > > ( )
14331444 }
1445+ AmendFastOptions :: FromCommit { commit } => self
1446+ . get_paths_touched_by_commit ( commit) ?
1447+ . unwrap_or_default ( )
1448+ . iter ( )
1449+ . map ( |path| {
1450+ // FIXME This is just a stab in the dark bsed on the other
1451+ // arms. I really have no idea what this is meant for or
1452+ // supposed to be doing.
1453+ match commit
1454+ . get_tree ( )
1455+ . expect ( "Could not get tree for commit" )
1456+ . get_path ( path)
1457+ . expect ( "Could not get tree entry for commit" )
1458+ {
1459+ Some ( entry) => {
1460+ ( path. clone ( ) , Some ( ( entry. get_oid ( ) , entry. get_filemode ( ) ) ) )
1461+ }
1462+ None => ( path. clone ( ) , None ) ,
1463+ }
1464+ } )
1465+ . collect :: < HashMap < _ , _ > > ( ) ,
14341466 } ;
14351467
14361468 // Merge the new path entries into the existing set of parent tree.
@@ -2411,6 +2443,127 @@ mod tests {
24112443 Ok ( ( ) )
24122444 }
24132445
2446+ #[ test]
2447+ fn test_amend_fast_from_commit ( ) -> eyre:: Result < ( ) > {
2448+ let git = make_git ( ) ?;
2449+ git. init_repo ( ) ?;
2450+
2451+ git. run ( & [ "checkout" , "master" ] ) ?;
2452+ let initial_oid = git. commit_file_with_contents ( "initial" , 2 , "initial contents" ) ?;
2453+ let second_oid = git. commit_file_with_contents ( "second" , 3 , "second contents" ) ?;
2454+
2455+ let repo = git. get_repo ( ) ?;
2456+ let initial_commit = repo. find_commit_or_fail ( initial_oid) ?;
2457+ let second_commit = repo. find_commit_or_fail ( second_oid) ?;
2458+
2459+ let tree = initial_commit. get_tree ( ) ?;
2460+ insta:: assert_debug_snapshot!( tree, @r###"
2461+ Tree {
2462+ inner: Tree {
2463+ id: 01deb7745d411223bbf6b9cb1abaeed451bb25a0,
2464+ },
2465+ }
2466+ "### ) ;
2467+ insta:: assert_debug_snapshot!( tree. inner. iter( ) . map( |entry| ( entry. name( ) . unwrap( ) . to_string( ) , entry. id( ) . to_string( ) ) ) . collect_vec( ) , @r###"
2468+ [
2469+ (
2470+ "initial.txt",
2471+ "5c41c3d7e736911dbbd53d62c10292b9bc78f838",
2472+ ),
2473+ ]
2474+ "### ) ;
2475+
2476+ let tree = repo. amend_fast (
2477+ & initial_commit,
2478+ & AmendFastOptions :: FromCommit {
2479+ commit : second_commit,
2480+ } ,
2481+ ) ?;
2482+
2483+ insta:: assert_debug_snapshot!( tree, @r###"
2484+ Tree {
2485+ inner: Tree {
2486+ id: cca737a0875ca64ba04a67a2aff58dfeb97ff275,
2487+ },
2488+ }
2489+ "### ) ;
2490+ insta:: assert_debug_snapshot!( tree. inner. iter( ) . map( |entry| ( entry. name( ) . unwrap( ) . to_string( ) , entry. id( ) . to_string( ) ) ) . collect_vec( ) , @r###"
2491+ [
2492+ (
2493+ "initial.txt",
2494+ "5c41c3d7e736911dbbd53d62c10292b9bc78f838",
2495+ ),
2496+ (
2497+ "second.txt",
2498+ "034b69666691fbb00fdc6f0e8ae8596d9a8d26ab",
2499+ ),
2500+ ]
2501+ "### ) ;
2502+
2503+ Ok ( ( ) )
2504+ }
2505+
2506+ #[ test]
2507+ fn test_amend_fast_from_distant_commit ( ) -> eyre:: Result < ( ) > {
2508+ let git = make_git ( ) ?;
2509+ git. init_repo ( ) ?;
2510+
2511+ git. run ( & [ "checkout" , "master" ] ) ?;
2512+ let initial_oid = git. commit_file_with_contents ( "initial" , 2 , "initial contents" ) ?;
2513+ let _second_oid = git. commit_file_with_contents ( "second" , 3 , "second contents" ) ?;
2514+ let third_oid = git. commit_file_with_contents ( "third" , 4 , "third contents" ) ?;
2515+
2516+ let repo = git. get_repo ( ) ?;
2517+ let initial_commit = repo. find_commit_or_fail ( initial_oid) ?;
2518+ let third_commit = repo. find_commit_or_fail ( third_oid) ?;
2519+
2520+ let tree = initial_commit. get_tree ( ) ?;
2521+ insta:: assert_debug_snapshot!( tree, @r###"
2522+ Tree {
2523+ inner: Tree {
2524+ id: 01deb7745d411223bbf6b9cb1abaeed451bb25a0,
2525+ },
2526+ }
2527+ "### ) ;
2528+ insta:: assert_debug_snapshot!( tree. inner. iter( ) . map( |entry| ( entry. name( ) . unwrap( ) . to_string( ) , entry. id( ) . to_string( ) ) ) . collect_vec( ) , @r###"
2529+ [
2530+ (
2531+ "initial.txt",
2532+ "5c41c3d7e736911dbbd53d62c10292b9bc78f838",
2533+ ),
2534+ ]
2535+ "### ) ;
2536+
2537+ let tree = repo. amend_fast (
2538+ & initial_commit,
2539+ & AmendFastOptions :: FromCommit {
2540+ commit : third_commit,
2541+ } ,
2542+ ) ?;
2543+
2544+ insta:: assert_debug_snapshot!( tree, @r###"
2545+ Tree {
2546+ inner: Tree {
2547+ id: 76ac27e1486c6db934f6e10dc5f1c30f480f979a,
2548+ },
2549+ }
2550+ "### ) ;
2551+ insta:: assert_debug_snapshot!( tree. inner. iter( ) . map( |entry| ( entry. name( ) . unwrap( ) . to_string( ) , entry. id( ) . to_string( ) ) ) . collect_vec( ) , @r###"
2552+ [
2553+ (
2554+ "initial.txt",
2555+ "5c41c3d7e736911dbbd53d62c10292b9bc78f838",
2556+ ),
2557+ (
2558+ "third.txt",
2559+ "175b41591c574329a8546b09c968345d0cddb4ed",
2560+ ),
2561+ ]
2562+ "### ) ;
2563+
2564+ Ok ( ( ) )
2565+ }
2566+
24142567 #[ test]
24152568 fn test_branch_debug ( ) -> eyre:: Result < ( ) > {
24162569 let git = make_git ( ) ?;
0 commit comments