@@ -13,6 +13,15 @@ use gix::refs::{
1313} ;
1414use petgraph:: visit:: EdgeRef ;
1515
16+ /// Represents somethign to be checked out - I'm not quite sure how
17+ /// `safe_checkout` knows what is the main checkout & what is a worktree - but
18+ /// that is some voodoo I'm not touching right now
19+ #[ derive( Debug , Clone ) ]
20+ pub struct CheckoutSpec {
21+ pub ( crate ) old_head_id : gix:: ObjectId ,
22+ pub ( crate ) head_id : gix:: ObjectId ,
23+ }
24+
1625/// Represents a successful rebase, and any valid, but potentially conflicting scenarios it had.
1726#[ allow( unused) ]
1827#[ derive( Debug , Clone ) ]
@@ -26,6 +35,10 @@ pub struct SuccessfulRebase {
2635 pub ( crate ) ref_edits : Vec < RefEdit > ,
2736 /// The new step graph
2837 pub ( crate ) graph : StepGraph ,
38+ /// Heads
39+ pub ( crate ) heads : Vec < StepGraphIndex > ,
40+ /// To checkout
41+ pub ( crate ) checkouts : Vec < CheckoutSpec > ,
2942}
3043
3144/// Represents the rebase output and the varying degrees of success it had.
@@ -61,11 +74,13 @@ impl Editor {
6174 // The step graph with updated commit oids
6275 let mut output_graph = StepGraph :: new ( ) ;
6376 let mut commit_mapping = HashMap :: new ( ) ;
77+ let mut checkouts = vec ! [ ] ;
78+ let mut unchanged_references = vec ! [ ] ;
6479
6580 for step_idx in steps_to_pick {
6681 // Do the frikkin rebase man!
6782 let step = self . graph [ step_idx] . clone ( ) ;
68- match step {
83+ let new_idx = match step {
6984 Step :: Pick { id } => {
7085 let graph_parents = collect_ordered_parents ( & self . graph , step_idx) ;
7186 let ontos = graph_parents
@@ -93,12 +108,14 @@ impl Editor {
93108 if id != new_id {
94109 commit_mapping. insert ( id, new_id) ;
95110 }
111+
112+ new_idx
96113 }
97114 CherryPickOutcome :: FailedToMergeBases => {
98115 // Exit early - the rebase failed because it encountered a commit it couldn't pick
99116 return Ok ( RebaseOutcome :: MergePickFailed ( id) ) ;
100117 }
101- } ;
118+ }
102119 }
103120 Step :: Reference { refname } => {
104121 let graph_parents = collect_ordered_parents ( & self . graph , step_idx) ;
@@ -120,7 +137,9 @@ impl Editor {
120137 let target = reference. target ( ) ;
121138 match target {
122139 gix:: refs:: TargetRef :: Object ( id) => {
123- if id != to_reference {
140+ if id == to_reference {
141+ unchanged_references. push ( refname. clone ( ) ) ;
142+ } else {
124143 ref_edits. push ( RefEdit {
125144 name : refname. clone ( ) ,
126145 change : Change :: Update {
@@ -132,6 +151,18 @@ impl Editor {
132151 } ,
133152 deref : false ,
134153 } ) ;
154+
155+ // TODO(CTO): This is FAR from the full set
156+ // of capabilities needed here. This ommits
157+ // any consideration of the head commit
158+ // being replaced. This really needs to do
159+ // some other lookup of all the heads
160+ if self . heads . contains ( & step_idx) {
161+ checkouts. push ( CheckoutSpec {
162+ old_head_id : id. into ( ) ,
163+ head_id : to_reference,
164+ } ) ;
165+ }
135166 }
136167 }
137168 gix:: refs:: TargetRef :: Symbolic ( name) => {
@@ -150,38 +181,67 @@ impl Editor {
150181 } ) ;
151182 } ;
152183
153- let new_idx = output_graph. add_node ( Step :: Reference { refname } ) ;
154- graph_mapping. insert ( step_idx, new_idx) ;
155- }
156- Step :: None => {
157- let new_idx = output_graph. add_node ( Step :: None ) ;
158- graph_mapping. insert ( step_idx, new_idx) ;
184+ output_graph. add_node ( Step :: Reference { refname } )
159185 }
186+ Step :: None => output_graph. add_node ( Step :: None ) ,
160187 } ;
161188
162- // Find deleted references
163- for reference in self . initial_references . iter ( ) {
164- if !ref_edits
189+ graph_mapping. insert ( step_idx, new_idx) ;
190+
191+ let mut edges = self
192+ . graph
193+ . edges_directed ( step_idx, petgraph:: Direction :: Outgoing )
194+ . collect :: < Vec < _ > > ( ) ;
195+ edges. sort_by_key ( |e| e. weight ( ) . order ) ;
196+ edges. reverse ( ) ;
197+
198+ for e in edges {
199+ let Some ( new_parent) = graph_mapping. get ( & e. target ( ) ) else {
200+ bail ! ( "Failed to find cooresponding parent" ) ;
201+ } ;
202+
203+ output_graph. add_edge ( new_idx, * new_parent, e. weight ( ) . clone ( ) ) ;
204+ }
205+ }
206+
207+ // Find deleted references
208+ for reference in self . initial_references . iter ( ) {
209+ if !ref_edits
210+ . iter ( )
211+ . any ( |e| e. name . as_ref ( ) == reference. as_ref ( ) )
212+ && !unchanged_references
165213 . iter ( )
166- . any ( |e| e. name . as_ref ( ) == reference. as_ref ( ) )
167- {
168- ref_edits. push ( RefEdit {
169- name : reference. clone ( ) ,
170- change : Change :: Delete {
171- log : gix:: refs:: transaction:: RefLog :: AndReference ,
172- expected : PreviousValue :: MustExist ,
173- } ,
174- deref : false ,
175- } ) ;
176- }
214+ . any ( |e| e. as_ref ( ) == reference. as_ref ( ) )
215+ {
216+ ref_edits. push ( RefEdit {
217+ name : reference. clone ( ) ,
218+ change : Change :: Delete {
219+ log : gix:: refs:: transaction:: RefLog :: AndReference ,
220+ expected : PreviousValue :: MustExist ,
221+ } ,
222+ deref : false ,
223+ } ) ;
177224 }
178225 }
179226
227+ let heads = self
228+ . heads
229+ . iter ( )
230+ . map ( |h| {
231+ graph_mapping
232+ . get ( h)
233+ . context ( "Failed to get new head" )
234+ . cloned ( )
235+ } )
236+ . collect :: < Result < Vec < _ > > > ( ) ?;
237+
180238 Ok ( RebaseOutcome :: Success ( SuccessfulRebase {
181239 ref_edits,
182240 commit_mapping,
183241 graph_mapping,
184242 graph : output_graph,
243+ heads,
244+ checkouts,
185245 } ) )
186246 }
187247}
0 commit comments