@@ -6,6 +6,9 @@ use bstr::{BString, ByteSlice};
6
6
use gitbutler_oxidize:: { ObjectIdExt , OidExt } ;
7
7
use gitbutler_repo:: rebase:: { cherry_rebase_group, merge_commits} ;
8
8
9
+ ///
10
+ pub mod commit;
11
+
9
12
/// An instruction for [`RebaseBuilder::rebase()`].
10
13
#[ derive( Debug ) ]
11
14
pub enum RebaseStep {
@@ -171,64 +174,69 @@ fn rebase(
171
174
let git2_repo = git2:: Repository :: open ( repo. path ( ) ) ?;
172
175
let mut references = vec ! [ ] ;
173
176
// Start with the base commit
174
- let mut head = base;
177
+ let ( mut cursor , mut last_seen_commit ) = ( base, base ) ;
175
178
// Running cherry_rebase_group for each step individually
176
179
for step in steps {
177
180
match step {
178
181
RebaseStep :: Pick {
179
182
commit_id,
180
183
new_message,
181
184
} => {
182
- let mut new_head =
185
+ last_seen_commit = commit_id;
186
+ let mut new_commit =
183
187
cherry_rebase_group ( & git2_repo, base. to_git2 ( ) , & [ commit_id. to_git2 ( ) ] , true ) ?
184
188
. to_gix ( ) ;
185
189
if let Some ( new_message) = new_message {
186
- new_head = reword_commit ( repo, new_head , new_message. clone ( ) ) ?;
190
+ new_commit = reword_commit ( repo, new_commit , new_message. clone ( ) ) ?;
187
191
}
188
192
// Update the base for the next loop iteration
189
- head = new_head ;
193
+ cursor = new_commit ;
190
194
}
191
195
RebaseStep :: Merge {
192
196
commit_id,
193
197
new_message,
194
198
} => {
195
- head = merge_commits ( repo, head, commit_id, & new_message. to_str_lossy ( ) ) ?;
199
+ last_seen_commit = commit_id;
200
+ cursor = merge_commits ( repo, cursor, commit_id, & new_message. to_str_lossy ( ) ) ?;
196
201
}
197
202
RebaseStep :: Fixup {
198
203
commit_id,
199
204
new_message,
200
205
} => {
206
+ last_seen_commit = commit_id;
201
207
// This time, the base is the parent of the last commit
202
- let base_commit = repo. find_commit ( head ) ?;
208
+ let base_commit = repo. find_commit ( cursor ) ?;
203
209
204
210
// First cherry-pick the target oid on top of base_commit
205
- let new_head =
206
- cherry_rebase_group ( & git2_repo, head. to_git2 ( ) , & [ commit_id. to_git2 ( ) ] , true ) ?
207
- . to_gix ( ) ;
211
+ let new_commit = cherry_rebase_group (
212
+ & git2_repo,
213
+ cursor. to_git2 ( ) ,
214
+ & [ commit_id. to_git2 ( ) ] ,
215
+ true ,
216
+ ) ?
217
+ . to_gix ( ) ;
208
218
209
219
// Now, lets pretend the base didn't exist by swapping parent with the parent of the base
210
- let commit = repo. find_commit ( new_head ) ?;
220
+ let commit = repo. find_commit ( new_commit ) ?;
211
221
let mut new_commit = commit. decode ( ) ?. to_owned ( ) ;
212
222
new_commit. parents = base_commit. parent_ids ( ) . map ( |id| id. detach ( ) ) . collect ( ) ;
213
- // Optionally reword the commit
214
223
if let Some ( new_message) = new_message {
215
224
new_commit. message = new_message;
216
225
}
217
- let new_head = repo. write_object ( new_commit) ?. detach ( ) ;
218
- // Update the base for the next loop iteration
219
- head = new_head;
226
+ cursor = commit:: create ( repo, new_commit) ?;
220
227
}
221
228
RebaseStep :: Reference { name : refname } => {
222
229
references. push ( ReferenceSpec {
223
230
refname : refname. clone ( ) ,
224
- oid : head,
231
+ commit_id : cursor,
232
+ previous_commit_id : last_seen_commit,
225
233
} ) ;
226
234
}
227
235
}
228
236
}
229
237
230
238
Ok ( RebaseOutput {
231
- new_head : head ,
239
+ top_commit : cursor ,
232
240
references,
233
241
} )
234
242
}
@@ -240,7 +248,7 @@ fn reword_commit(
240
248
) -> Result < gix:: ObjectId > {
241
249
let mut new_commit = repo. find_commit ( oid) ?. decode ( ) ?. to_owned ( ) ;
242
250
new_commit. message = new_message;
243
- Ok ( repo . write_object ( new_commit) ?. detach ( ) )
251
+ Ok ( commit :: create ( repo , new_commit) ?)
244
252
}
245
253
246
254
/// A reference that is an output of a rebase operation.
@@ -249,13 +257,16 @@ pub struct ReferenceSpec {
249
257
/// A literal reference, useful only to the caller.
250
258
pub refname : BString ,
251
259
/// The commit it now points to.
252
- pub oid : gix:: ObjectId ,
260
+ pub commit_id : gix:: ObjectId ,
261
+ /// The commit it previously pointed to (as per pick-list).
262
+ /// Useful for reference-transactions that validate the current value before changing it to the new one.
263
+ pub previous_commit_id : gix:: ObjectId ,
253
264
}
254
265
255
266
/// The output of the [rebase](RebaseBuilder::rebase()) operation.
256
267
pub struct RebaseOutput {
257
- /// The oid of the last commit in the rebase operation, i.e. the new head .
258
- pub new_head : gix:: ObjectId ,
259
- /// The list of references that should be created , ordered from the least recent to the most recent.
268
+ /// The id of the most recently created commit in the rebase operation.
269
+ pub top_commit : gix:: ObjectId ,
270
+ /// The list of references along with their new locations , ordered from the least recent to the most recent.
260
271
pub references : Vec < ReferenceSpec > ,
261
272
}
0 commit comments