@@ -6,21 +6,37 @@ use crate::{
66 ReferenceSpec ,
77 cherry_pick:: EmptyCommit ,
88 cherry_pick_one,
9- graph_rebase:: { Editor , Step , StepGraph , StepGraphIndex } ,
9+ graph_rebase:: {
10+ Editor , Step , StepGraph , StepGraphIndex ,
11+ cherry_pick:: { CherryPickOutcome , cherry_pick} ,
12+ } ,
1013 to_commit,
1114} ;
12- use anyhow:: { Context , Result } ;
15+ use anyhow:: { Context , Result , bail } ;
1316use petgraph:: visit:: EdgeRef ;
1417
15- /// Represents the rebase output and the varying degrees of success it had.
16- pub struct RebaseResult {
18+ /// Represents a successful rebase, and any valid, but potentially conflicting scenarios it had.
19+ #[ derive( Debug , Clone ) ]
20+ pub struct SuccessfulRebase {
1721 references : Vec < ReferenceSpec > ,
1822 commit_map : HashMap < gix:: ObjectId , gix:: ObjectId > ,
1923}
2024
25+ /// Represents the rebase output and the varying degrees of success it had.
26+ #[ derive( Debug , Clone ) ]
27+ pub enum RebaseOutcome {
28+ /// The rebase
29+ Success ( SuccessfulRebase ) ,
30+ /// The graph rebase failed because we encountered a situation where we
31+ /// couldn't merge bases.
32+ ///
33+ /// Holds the gix::ObjectId of the commit it failed to pick
34+ MergePickFailed ( gix:: ObjectId ) ,
35+ }
36+
2137impl Editor {
2238 /// Perform the rebase
23- pub fn rebase ( & self , repo : & gix:: Repository ) -> Result < RebaseResult > {
39+ pub fn rebase ( & self , repo : & gix:: Repository ) -> Result < RebaseOutcome > {
2440 // First we want to get a list of nodes that can be reached by
2541 // traversing downwards from the heads that we care about.
2642 // Usually there would be just one "head" which is an index to access
@@ -41,41 +57,52 @@ impl Editor {
4157 let step = self . graph [ step_idx] . clone ( ) ;
4258 match step {
4359 Step :: Pick { id } => {
44- let commit = to_commit ( repo, id) ?;
4560 let graph_parents = collect_ordered_parents ( & self . graph , step_idx) ;
46-
47- match ( commit. parents . len ( ) , graph_parents. len ( ) ) {
48- ( 0 , 0 ) => {
49- let new_idx = output_graph. add_node ( step) ;
61+ let ontos = graph_parents
62+ . iter ( )
63+ . map ( |idx| {
64+ let Some ( new_idx) = graph_mapping. get ( idx) else {
65+ bail ! ( "A matching parent can't be found in the output graph" ) ;
66+ } ;
67+
68+ match output_graph[ * new_idx] {
69+ Step :: Pick { id } => Ok ( id) ,
70+ _ => bail ! ( "A parent in the output graph is not a pick" ) ,
71+ }
72+ } )
73+ . collect :: < Result < Vec < _ > > > ( ) ?;
74+
75+ let outcome = cherry_pick ( repo, id, & ontos) ?;
76+
77+ match outcome {
78+ CherryPickOutcome :: Commit ( new_id)
79+ | CherryPickOutcome :: ConflictedCommit ( new_id)
80+ | CherryPickOutcome :: Identity ( new_id) => {
81+ let new_idx = output_graph. add_node ( Step :: Pick { id : new_id } ) ;
5082 graph_mapping. insert ( step_idx, new_idx) ;
5183 }
52- ( 1 , 0 ) => {
53- todo ! ( "1 to 0 cherry pick is not implemented yet" ) ;
54- }
55- ( 0 , 1 ) => {
56- todo ! ( "0 to 1 cherry pick is not implemented yet" ) ;
57- }
58- ( 1 , 1 ) => {
59- let ( _, parent_id) = graph_parents. first ( ) . expect ( "Impossible" ) ;
60-
61- let new_commit = cherry_pick_one (
62- repo,
63- * parent_id,
64- id,
65- pick_mode,
66- EmptyCommit :: Keep ,
67- ) ?;
68-
69- let new_idx = output_graph. add_node ( Step :: Pick { id : new_commit } ) ;
70- graph_mapping. insert ( step_idx, new_idx) ;
71- }
72- ( _, _) => {
73- todo ! ( "N to >2 parents & >2 parents to N is not implemented yet" ) ;
84+ CherryPickOutcome :: FailedToMergeBases => {
85+ // Exit early - the rebase failed because it encountered a commit it couldn't pick
86+ return Ok ( RebaseOutcome :: MergePickFailed ( id) ) ;
7487 }
7588 } ;
7689 }
77- Step :: Reference { refname } => { }
78- Step :: None => { }
90+ Step :: Reference { refname } => {
91+ let graph_parents = collect_ordered_parents ( & self . graph , step_idx) ;
92+ let first_parent_idx = graph_parents. first ( ) . context ( "References " )
93+ let Some ( new_idx) = graph_mapping. get ( idx) else {
94+ bail ! ( "A matching parent can't be found in the output graph" ) ;
95+ } ;
96+
97+ let to_reference = match output_graph[ * new_idx] {
98+ Step :: Pick { id } => id,
99+ _ => bail ! ( "A parent in the output graph is not a pick" ) ,
100+ } ;
101+ }
102+ Step :: None => {
103+ let new_idx = output_graph. add_node ( Step :: None ) ;
104+ graph_mapping. insert ( step_idx, new_idx) ;
105+ }
79106 } ;
80107 }
81108
@@ -87,10 +114,7 @@ impl Editor {
87114/// ordering.
88115///
89116/// We do this via a pruned depth first search.
90- fn collect_ordered_parents (
91- graph : & StepGraph ,
92- target : StepGraphIndex ,
93- ) -> Vec < ( StepGraphIndex , gix:: ObjectId ) > {
117+ fn collect_ordered_parents ( graph : & StepGraph , target : StepGraphIndex ) -> Vec < StepGraphIndex > {
94118 let mut potential_parent_edges = graph
95119 . edges_directed ( target, petgraph:: Direction :: Outgoing )
96120 . collect :: < Vec < _ > > ( ) ;
@@ -106,7 +130,7 @@ fn collect_ordered_parents(
106130
107131 while let Some ( candidate) = potential_parent_edges. pop ( ) {
108132 if let Step :: Pick { id } = graph[ candidate. target ( ) ] {
109- parents. push ( ( candidate. target ( ) , id ) ) ;
133+ parents. push ( candidate. target ( ) ) ;
110134 // Don't persue the children
111135 continue ;
112136 } ;
@@ -223,7 +247,7 @@ mod test {
223247 graph. add_edge ( c, e, Edge { order : 1 } ) ;
224248
225249 let parents = collect_ordered_parents ( & graph, a) ;
226- assert_eq ! ( & parents, & [ ( b, b_id ) , ( d, d_id ) , ( e, e_id ) , ( f , f_id ) ] ) ;
250+ assert_eq ! ( & parents, & [ b, d, e, f ] ) ;
227251
228252 Ok ( ( ) )
229253 }
@@ -260,7 +284,7 @@ mod test {
260284 graph. add_edge ( c, e, Edge { order : 0 } ) ;
261285
262286 let parents = collect_ordered_parents ( & graph, a) ;
263- assert_eq ! ( & parents, & [ ( b, b_id ) , ( e, e_id ) , ( d, d_id ) , ( f , f_id ) ] ) ;
287+ assert_eq ! ( & parents, & [ b, e, d, f ] ) ;
264288
265289 Ok ( ( ) )
266290 }
0 commit comments