@@ -263,39 +263,7 @@ pub(crate) mod function {
263
263
{
264
264
let ws_mut: & mut Workspace = & mut ws_md;
265
265
for rn in & branches_to_apply {
266
- // Here we have to check if the new ref would be able to become its own stack,
267
- // or if it has to be a dependent branch. Stacks only work if the ref rests on a base
268
- // outside the workspace, so if we find it in the workspace (in an ambiguous spot) it must be
269
- // a dependent branch
270
- if let Some ( segment_to_insert_above) = workspace
271
- . stacks
272
- . iter ( )
273
- . flat_map ( |stack| stack. segments . iter ( ) )
274
- . find_map ( |segment| {
275
- segment. commits . iter ( ) . flat_map ( |c| c. refs . iter ( ) ) . find_map (
276
- |ambiguous_rn| {
277
- ( ambiguous_rn. as_ref ( ) == * rn)
278
- . then_some ( segment. ref_name . as_ref ( ) )
279
- . flatten ( )
280
- } ,
281
- )
282
- } )
283
- {
284
- if ws_mut
285
- . insert_new_segment_above_anchor_if_not_present (
286
- rn,
287
- segment_to_insert_above. as_ref ( ) ,
288
- )
289
- . is_none ( )
290
- {
291
- // For now bail, until we know it's worth fixing this case automatically.
292
- bail ! (
293
- "Missing reference {segment_to_insert_above} which should be known to workspace metadata to serve as insertion position for {rn}"
294
- ) ;
295
- }
296
- } else {
297
- ws_mut. add_or_insert_new_stack_if_not_present ( rn, order) ;
298
- }
266
+ ws_mut. add_or_insert_new_stack_if_not_present ( rn, order) ;
299
267
}
300
268
}
301
269
let ws_md_override = Some ( ( workspace_ref_name_to_update. clone ( ) , ( * ws_md) . clone ( ) ) ) ;
@@ -368,8 +336,9 @@ pub(crate) mod function {
368
336
) ;
369
337
}
370
338
// At this point, the workspace-metadata already knows the new branch(es), but the workspace itself
371
- // doesn't see one or more of to-be-applied branches. These are, however, part of the graph by now,
372
- // and we want to try to create a workspace merge.
339
+ // doesn't see one or more of to-be-applied branches (to become stacks).
340
+ // These are, however, part of the graph by now, and we want to try to create a workspace
341
+ // merge.
373
342
let mut in_memory_repo = repo. clone ( ) . for_tree_diffing ( ) ?. with_object_memory ( ) ;
374
343
let merge_result = WorkspaceCommit :: from_new_merge_with_metadata (
375
344
& ws_md. stacks ,
@@ -390,33 +359,104 @@ pub(crate) mod function {
390
359
. entrypoint_commit ( )
391
360
. context ( "BUG: how is it possible that there is no head commit?" ) ?
392
361
. id ;
393
- let new_head_id = merge_result. workspace_commit_id ;
394
- let graph = graph. redo_traversal_with_overlay (
395
- & in_memory_repo,
396
- meta,
397
- overlay. with_entrypoint ( new_head_id, Some ( workspace_ref_name_to_update. clone ( ) ) ) ,
398
- ) ?;
362
+ let mut new_head_id = merge_result. workspace_commit_id ;
363
+ let overlay =
364
+ overlay. with_entrypoint ( new_head_id, Some ( workspace_ref_name_to_update. clone ( ) ) ) ;
365
+ let mut graph =
366
+ graph. redo_traversal_with_overlay ( & in_memory_repo, meta, overlay. clone ( ) ) ?;
399
367
400
368
let workspace = graph. to_workspace ( ) ?;
401
- let unapplied_branches: Vec < _ > = branches_to_apply
402
- . iter ( )
403
- . filter_map ( |rn| {
404
- if workspace. refname_is_segment ( rn) {
405
- None
406
- } else {
407
- Some ( rn)
408
- }
409
- } )
410
- . collect ( ) ;
369
+ let collect_unapplied_branches = |workspace : & but_graph:: projection:: Workspace | {
370
+ branches_to_apply
371
+ . iter ( )
372
+ . filter ( |rn| workspace. refname_is_segment ( rn) )
373
+ . collect :: < Vec < _ > > ( )
374
+ } ;
375
+ let unapplied_branches = collect_unapplied_branches ( & workspace) ;
411
376
if !unapplied_branches. is_empty ( ) {
412
- bail ! (
413
- "Unexpectedly failed to apply {branches} which is/are still not in the workspace" ,
414
- branches = unapplied_branches
377
+ // Now that the merge is done, try to redo the operation one last time with dependent branches instead.
378
+ // Only do that for the still unapplied branches, which should always find some sort of anchor.
379
+ let ws_mut: & mut Workspace = & mut ws_md;
380
+ for branch_to_remove in & unapplied_branches {
381
+ ws_mut. remove_segment ( branch_to_remove) ;
382
+ }
383
+ for rn in & unapplied_branches {
384
+ // Here we have to check if the new ref would be able to become its own stack,
385
+ // or if it has to be a dependent branch. Stacks only work if the ref rests on a base
386
+ // outside the workspace, so if we find it in the workspace (in an ambiguous spot) it must be
387
+ // a dependent branch
388
+ if let Some ( segment_to_insert_above) = workspace
389
+ . stacks
415
390
. iter ( )
416
- . map( |rn| rn. shorten( ) . to_string( ) )
417
- . collect:: <Vec <_>>( )
418
- . join( ", " )
419
- )
391
+ . flat_map ( |stack| stack. segments . iter ( ) )
392
+ . find_map ( |segment| {
393
+ segment. commits . iter ( ) . flat_map ( |c| c. refs . iter ( ) ) . find_map (
394
+ |ambiguous_rn| {
395
+ ( ambiguous_rn. as_ref ( ) == * * rn)
396
+ . then_some ( segment. ref_name . as_ref ( ) )
397
+ . flatten ( )
398
+ } ,
399
+ )
400
+ } )
401
+ {
402
+ if ws_mut
403
+ . insert_new_segment_above_anchor_if_not_present (
404
+ rn,
405
+ segment_to_insert_above. as_ref ( ) ,
406
+ )
407
+ . is_none ( )
408
+ {
409
+ // For now bail, until we know it's worth fixing this case automatically.
410
+ bail ! (
411
+ "Missing reference {segment_to_insert_above} which should be known to workspace metadata to serve as insertion position for {rn}"
412
+ ) ;
413
+ }
414
+ } else {
415
+ bail ! (
416
+ "Unexpectedly failed to find anchor for {rn} to make it a dependent branch"
417
+ )
418
+ }
419
+ }
420
+
421
+ // Redo the merge, with the different stack configuration.
422
+ // Note that this is the exception, typically using stacks will be fine.
423
+ let merge_result = WorkspaceCommit :: from_new_merge_with_metadata (
424
+ & ws_md. stacks ,
425
+ workspace. graph ,
426
+ & in_memory_repo,
427
+ Some ( branch) ,
428
+ ) ?;
429
+
430
+ if merge_result. has_conflicts ( ) && on_workspace_conflict. should_abort ( ) {
431
+ return Ok ( Outcome {
432
+ graph : Cow :: Owned ( graph) ,
433
+ workspace_ref_created : needs_ws_ref_creation,
434
+ workspace_merge : Some ( merge_result) ,
435
+ } ) ;
436
+ }
437
+ new_head_id = merge_result. workspace_commit_id ;
438
+ let ws_md_override = Some ( ( workspace_ref_name_to_update. clone ( ) , ( * ws_md) . clone ( ) ) ) ;
439
+
440
+ graph = graph. redo_traversal_with_overlay (
441
+ & in_memory_repo,
442
+ meta,
443
+ overlay
444
+ . with_entrypoint ( new_head_id, Some ( workspace_ref_name_to_update. clone ( ) ) )
445
+ . with_workspace_metadata_override ( ws_md_override) ,
446
+ ) ?;
447
+ let workspace = graph. to_workspace ( ) ?;
448
+ let unapplied_branches = collect_unapplied_branches ( & workspace) ;
449
+
450
+ if !unapplied_branches. is_empty ( ) {
451
+ bail ! (
452
+ "Unexpectedly failed to apply {branches} which is/are still not in the workspace" ,
453
+ branches = unapplied_branches
454
+ . iter( )
455
+ . map( |rn| rn. shorten( ) . to_string( ) )
456
+ . collect:: <Vec <_>>( )
457
+ . join( ", " )
458
+ )
459
+ }
420
460
}
421
461
422
462
// All work is done, persist and exit.
0 commit comments