@@ -99,6 +99,14 @@ pub(crate) struct StackToBranchOperation<'a> {
9999 pub ( crate ) to : & ' a str ,
100100}
101101
102+ /// Represents squashing all assignments from a stack to a commit.
103+ #[ derive( Debug ) ]
104+ pub ( crate ) struct StackToCommitOperation {
105+ /// The source stack id.
106+ pub ( crate ) from : StackId ,
107+ pub ( crate ) to : gix:: ObjectId ,
108+ }
109+
102110/// Represents amending all unassigned hunks into a commit.
103111#[ derive( Debug ) ]
104112pub ( crate ) struct UnassignedToCommitOperation {
@@ -122,11 +130,20 @@ pub(crate) struct UnassignedToStackOperation {
122130
123131/// Represents undoing a commit.
124132#[ derive( Debug ) ]
125- pub ( crate ) struct UndoCommitOperation {
133+ pub ( crate ) struct CommitToUnassignedOperation {
126134 /// The commit id to undo.
127135 pub ( crate ) oid : gix:: ObjectId ,
128136}
129137
138+ /// Represents undoing a commit to a stack.
139+ #[ derive( Debug ) ]
140+ pub ( crate ) struct CommitToStackOperation {
141+ /// The commit id to undo.
142+ pub ( crate ) oid : gix:: ObjectId ,
143+ /// The stack to assign the changes to.
144+ pub ( crate ) stack : StackId ,
145+ }
146+
130147/// Represents squashing one commit into another.
131148#[ derive( Debug ) ]
132149pub ( crate ) struct SquashCommitsOperation {
@@ -221,10 +238,12 @@ pub(crate) enum RubOperation<'a> {
221238 StackToUnassigned ( StackToUnassignedOperation ) ,
222239 StackToStack ( StackToStackOperation ) ,
223240 StackToBranch ( StackToBranchOperation < ' a > ) ,
241+ StackToCommit ( StackToCommitOperation ) ,
224242 UnassignedToCommit ( UnassignedToCommitOperation ) ,
225243 UnassignedToBranch ( UnassignedToBranchOperation < ' a > ) ,
226244 UnassignedToStack ( UnassignedToStackOperation ) ,
227- UndoCommit ( UndoCommitOperation ) ,
245+ CommitToUnassigned ( CommitToUnassignedOperation ) ,
246+ CommitToStack ( CommitToStackOperation ) ,
228247 SquashCommits ( SquashCommitsOperation ) ,
229248 MoveCommitToBranch ( MoveCommitToBranchOperation < ' a > ) ,
230249 BranchToUnassigned ( BranchToUnassignedOperation < ' a > ) ,
@@ -425,6 +444,44 @@ impl<'a> StackToBranchOperation<'a> {
425444 }
426445}
427446
447+ impl StackToCommitOperation {
448+ /// Executes this operation.
449+ pub ( crate ) fn execute ( self , ctx : & mut Context , out : & mut OutputChannel ) -> anyhow:: Result < ( ) > {
450+ let result = self . execute_inner ( ctx) ?;
451+ if let Some ( out) = out. for_human ( ) {
452+ let repo = ctx. repo . get ( ) ?;
453+ let new_commit = result
454+ . new_commit
455+ . map ( |c| {
456+ let short = shorten_object_id ( & repo, c) ;
457+ let ( lead, rest) = split_short_id ( & short, 2 ) ;
458+ format ! ( "{}{}" , lead. blue( ) . bold( ) , rest. blue( ) )
459+ } )
460+ . unwrap_or_default ( ) ;
461+ writeln ! (
462+ out,
463+ "Amended files assigned to {} → {}" ,
464+ stack_id_to_branch_name( ctx, self . from)
465+ . map( |b| format!( "[{b}]" ) . green( ) )
466+ . unwrap_or_else( || "stack" . to_string( ) . bold( ) ) ,
467+ new_commit,
468+ ) ?;
469+ } else if let Some ( out) = out. for_json ( ) {
470+ out. write_value ( serde_json:: json!( {
471+ "ok" : true ,
472+ "new_commit_id" : result. new_commit. map( |c| c. to_string( ) ) ,
473+ } ) ) ?;
474+ }
475+ Ok ( ( ) )
476+ }
477+
478+ /// Executes `StackToCommit` by squashing all hunks from the source stack to the target commit.
479+ pub ( crate ) fn execute_inner ( & self , ctx : & mut Context ) -> anyhow:: Result < CommitCreateResult > {
480+ let changes = changes_for_stack_assignment ( ctx, Some ( self . from ) ) ?;
481+ but_api:: commit:: amend:: commit_amend ( ctx, self . to , changes, DryRun :: No )
482+ }
483+ }
484+
428485impl UnassignedToCommitOperation {
429486 /// Executes this operation.
430487 pub ( crate ) fn execute ( self , ctx : & mut Context , out : & mut OutputChannel ) -> anyhow:: Result < ( ) > {
@@ -505,7 +562,7 @@ impl UnassignedToStackOperation {
505562 }
506563}
507564
508- impl UndoCommitOperation {
565+ impl CommitToUnassignedOperation {
509566 /// Executes this operation.
510567 pub ( crate ) fn execute ( self , ctx : & mut Context , out : & mut OutputChannel ) -> anyhow:: Result < ( ) > {
511568 self . execute_inner ( ctx) ?;
@@ -524,11 +581,36 @@ impl UndoCommitOperation {
524581
525582 /// Executes `UndoCommit` by uncommitting all changes from the selected commit.
526583 pub ( crate ) fn execute_inner ( & self , ctx : & mut Context ) -> anyhow:: Result < CommitUndoResult > {
527- // TODO(David): Have fun. - Love, Caleb
528584 but_api:: commit:: undo:: commit_undo ( ctx, self . oid , None , DryRun :: No )
529585 }
530586}
531587
588+ impl CommitToStackOperation {
589+ /// Executes this operation.
590+ pub ( crate ) fn execute ( self , ctx : & mut Context , out : & mut OutputChannel ) -> anyhow:: Result < ( ) > {
591+ self . execute_inner ( ctx) ?;
592+ if let Some ( out) = out. for_human ( ) {
593+ let repo = ctx. repo . get ( ) ?;
594+ writeln ! (
595+ out,
596+ "Uncommitted {} to {}" ,
597+ shorten_object_id( & repo, self . oid) . blue( ) ,
598+ stack_id_to_branch_name( ctx, self . stack)
599+ . map( |b| format!( "[{b}]" ) . green( ) )
600+ . unwrap_or_else( || "stack" . bold( ) ) ,
601+ ) ?;
602+ } else if let Some ( out) = out. for_json ( ) {
603+ out. write_value ( serde_json:: json!( { "ok" : true } ) ) ?;
604+ }
605+ Ok ( ( ) )
606+ }
607+
608+ /// Executes `UndoCommit` by uncommitting all changes from the selected commit.
609+ pub ( crate ) fn execute_inner ( & self , ctx : & mut Context ) -> anyhow:: Result < CommitUndoResult > {
610+ but_api:: commit:: undo:: commit_undo ( ctx, self . oid , Some ( self . stack ) , DryRun :: No )
611+ }
612+ }
613+
532614impl SquashCommitsOperation {
533615 /// Executes this operation.
534616 pub ( crate ) fn execute ( self , ctx : & mut Context , out : & mut OutputChannel ) -> anyhow:: Result < ( ) > {
@@ -795,7 +877,8 @@ impl<'a> RubOperation<'a> {
795877 RubOperation :: UnassignedToCommit ( operation) => operation. execute ( ctx, out) ,
796878 RubOperation :: UnassignedToBranch ( operation) => operation. execute ( ctx, out) ,
797879 RubOperation :: UnassignedToStack ( operation) => operation. execute ( ctx, out) ,
798- RubOperation :: UndoCommit ( operation) => operation. execute ( ctx, out) ,
880+ RubOperation :: CommitToUnassigned ( operation) => operation. execute ( ctx, out) ,
881+ RubOperation :: CommitToStack ( operation) => operation. execute ( ctx, out) ,
799882 RubOperation :: SquashCommits ( operation) => operation. execute ( ctx, out) ,
800883 RubOperation :: MoveCommitToBranch ( operation) => operation. execute ( ctx, out) ,
801884 RubOperation :: BranchToUnassigned ( operation) => operation. execute ( ctx, out) ,
@@ -805,6 +888,7 @@ impl<'a> RubOperation<'a> {
805888 RubOperation :: CommittedFileToBranch ( operation) => operation. execute ( ctx, out) ,
806889 RubOperation :: CommittedFileToCommit ( operation) => operation. execute ( ctx, out) ,
807890 RubOperation :: CommittedFileToUnassigned ( operation) => operation. execute ( ctx, out) ,
891+ RubOperation :: StackToCommit ( operation) => operation. execute ( ctx, out) ,
808892 }
809893 }
810894}
@@ -951,6 +1035,12 @@ pub(crate) fn route_operation<'a>(
9511035 to,
9521036 } ) )
9531037 }
1038+ ( Stack { stack_id, .. } , Commit { commit_id, .. } ) => {
1039+ Some ( RubOperation :: StackToCommit ( StackToCommitOperation {
1040+ from : * stack_id,
1041+ to : * commit_id,
1042+ } ) )
1043+ }
9541044 // Unassigned -> *
9551045 ( Unassigned { .. } , Commit { commit_id, .. } ) => Some ( RubOperation :: UnassignedToCommit (
9561046 UnassignedToCommitOperation { oid : * commit_id } ,
@@ -962,11 +1052,9 @@ pub(crate) fn route_operation<'a>(
9621052 UnassignedToStackOperation { to : * stack_id } ,
9631053 ) ) ,
9641054 // Commit -> *
965- ( Commit { commit_id, .. } , Unassigned { .. } ) => {
966- Some ( RubOperation :: UndoCommit ( UndoCommitOperation {
967- oid : * commit_id,
968- } ) )
969- }
1055+ ( Commit { commit_id, .. } , Unassigned { .. } ) => Some ( RubOperation :: CommitToUnassigned (
1056+ CommitToUnassignedOperation { oid : * commit_id } ,
1057+ ) ) ,
9701058 (
9711059 Commit {
9721060 commit_id : source, ..
@@ -985,6 +1073,12 @@ pub(crate) fn route_operation<'a>(
9851073 name,
9861074 } ,
9871075 ) ) ,
1076+ ( Commit { commit_id, .. } , Stack { stack_id, .. } ) => {
1077+ Some ( RubOperation :: CommitToStack ( CommitToStackOperation {
1078+ oid : * commit_id,
1079+ stack : * stack_id,
1080+ } ) )
1081+ }
9881082 // Branch -> *
9891083 ( Branch { name, .. } , Unassigned { .. } ) => Some ( RubOperation :: BranchToUnassigned (
9901084 BranchToUnassignedOperation { from : name } ,
@@ -1748,12 +1842,12 @@ mod tests {
17481842 // Valid: Commit -> Branch
17491843 assert ! ( route_operation( & commit, & branch_id( ) ) . is_some( ) ) ;
17501844
1845+ // Valid: Commit -> Stack
1846+ assert ! ( route_operation( & commit, & stack_id( ) ) . is_some( ) ) ;
1847+
17511848 // Invalid: Commit -> Uncommitted
17521849 assert ! ( route_operation( & commit, & uncommitted_id( ) ) . is_none( ) ) ;
17531850
1754- // Invalid: Commit -> Stack
1755- assert ! ( route_operation( & commit, & stack_id( ) ) . is_none( ) ) ;
1756-
17571851 // Invalid: Commit -> CommittedFile
17581852 assert ! ( route_operation( & commit, & committed_file_id( ) ) . is_none( ) ) ;
17591853 }
@@ -1794,12 +1888,12 @@ mod tests {
17941888 // Valid: Stack -> Branch
17951889 assert ! ( route_operation( & stack, & branch_id( ) ) . is_some( ) ) ;
17961890
1891+ // Valid: Stack -> Commit
1892+ assert ! ( route_operation( & stack, & commit_id( ) ) . is_some( ) ) ;
1893+
17971894 // Invalid: Stack -> Uncommitted
17981895 assert ! ( route_operation( & stack, & uncommitted_id( ) ) . is_none( ) ) ;
17991896
1800- // Invalid: Stack -> Commit
1801- assert ! ( route_operation( & stack, & commit_id( ) ) . is_none( ) ) ;
1802-
18031897 // Invalid: Stack -> CommittedFile
18041898 assert ! ( route_operation( & stack, & committed_file_id( ) ) . is_none( ) ) ;
18051899 }
@@ -1882,10 +1976,16 @@ mod tests {
18821976 _ => panic ! ( "Expected SquashCommits variant" ) ,
18831977 }
18841978
1885- // Commit -> Unassigned should be UndoCommit
1979+ // Commit -> Unassigned should be CommitToUnassigned
18861980 match route_operation ( & commit, & unassigned) {
1887- Some ( RubOperation :: UndoCommit ( ..) ) => { }
1888- _ => panic ! ( "Expected UndoCommit variant" ) ,
1981+ Some ( RubOperation :: CommitToUnassigned ( ..) ) => { }
1982+ _ => panic ! ( "Expected CommitToUnassigned variant" ) ,
1983+ }
1984+
1985+ // Commit -> Stack should be CommitToStack
1986+ match route_operation ( & commit, & stack) {
1987+ Some ( RubOperation :: CommitToStack ( ..) ) => { }
1988+ _ => panic ! ( "Expected CommitToStack variant" ) ,
18891989 }
18901990
18911991 // Branch -> Stack should be BranchToStack
@@ -1900,6 +2000,12 @@ mod tests {
19002000 _ => panic ! ( "Expected StackToBranch variant" ) ,
19012001 }
19022002
2003+ // Stack -> Commit should be StackToCommit
2004+ match route_operation ( & stack, & commit) {
2005+ Some ( RubOperation :: StackToCommit ( ..) ) => { }
2006+ _ => panic ! ( "Expected StackToCommit variant" ) ,
2007+ }
2008+
19032009 // CommittedFile -> Commit should be CommittedFileToCommit
19042010 match route_operation ( & committed_file, & commit) {
19052011 Some ( RubOperation :: CommittedFileToCommit ( ..) ) => { }
0 commit comments