@@ -302,30 +302,59 @@ static int interesting(git_pqueue *list)
302
302
return 0 ;
303
303
}
304
304
305
- int git_merge__bases_many (git_commit_list * * out , git_revwalk * walk , git_commit_list_node * one , git_vector * twos )
305
+ static void clear_commit_marks_1 (git_commit_list * * plist ,
306
+ git_commit_list_node * commit , unsigned int mark )
306
307
{
307
- int error ;
308
- unsigned int i ;
309
- git_commit_list_node * two ;
310
- git_commit_list * result = NULL , * tmp = NULL ;
311
- git_pqueue list ;
308
+ while (commit ) {
309
+ unsigned int i ;
312
310
313
- /* If there's only the one commit, there can be no merge bases */
314
- if (twos -> length == 0 ) {
315
- * out = NULL ;
316
- return 0 ;
311
+ if (!(mark & commit -> flags ))
312
+ return ;
313
+
314
+ commit -> flags &= ~mark ;
315
+
316
+ for (i = 1 ; i < commit -> out_degree ; i ++ ) {
317
+ git_commit_list_node * p = commit -> parents [i ];
318
+ git_commit_list_insert (p , plist );
319
+ }
320
+
321
+ commit = commit -> out_degree ? commit -> parents [0 ] : NULL ;
317
322
}
323
+ }
318
324
319
- /* if the commit is repeated, we have a our merge base already */
320
- git_vector_foreach (twos , i , two ) {
321
- if (one == two )
322
- return git_commit_list_insert (one , out ) ? 0 : -1 ;
325
+ static void clear_commit_marks_many (git_vector * commits , unsigned int mark )
326
+ {
327
+ git_commit_list * list = NULL ;
328
+ git_commit_list_node * c ;
329
+ unsigned int i ;
330
+
331
+ git_vector_foreach (commits , i , c ) {
332
+ git_commit_list_insert (c , & list );
323
333
}
324
334
325
- if (git_pqueue_init (& list , 0 , twos -> length * 2 , git_commit_list_time_cmp ) < 0 )
326
- return -1 ;
335
+ while (list )
336
+ clear_commit_marks_1 (& list , git_commit_list_pop (& list ), mark );
337
+ }
327
338
328
- if (git_commit_list_parse (walk , one ) < 0 )
339
+ static void clear_commit_marks (git_commit_list_node * commit , unsigned int mark )
340
+ {
341
+ git_commit_list * list = NULL ;
342
+ git_commit_list_insert (commit , & list );
343
+ while (list )
344
+ clear_commit_marks_1 (& list , git_commit_list_pop (& list ), mark );
345
+ }
346
+
347
+ static int paint_down_to_common (
348
+ git_commit_list * * out , git_revwalk * walk , git_commit_list_node * one , git_vector * twos )
349
+ {
350
+ git_pqueue list ;
351
+ git_commit_list * result = NULL ;
352
+ git_commit_list_node * two ;
353
+
354
+ int error ;
355
+ unsigned int i ;
356
+
357
+ if (git_pqueue_init (& list , 0 , twos -> length * 2 , git_commit_list_time_cmp ) < 0 )
329
358
return -1 ;
330
359
331
360
one -> flags |= PARENT1 ;
@@ -376,19 +405,138 @@ int git_merge__bases_many(git_commit_list **out, git_revwalk *walk, git_commit_l
376
405
}
377
406
378
407
git_pqueue_free (& list );
408
+ * out = result ;
409
+ return 0 ;
410
+ }
411
+
412
+ static int remove_redundant (git_revwalk * walk , git_vector * commits )
413
+ {
414
+ git_vector work = GIT_VECTOR_INIT ;
415
+ unsigned char * redundant ;
416
+ unsigned int * filled_index ;
417
+ unsigned int i , j ;
418
+ int error = 0 ;
419
+
420
+ redundant = git__calloc (commits -> length , 1 );
421
+ GITERR_CHECK_ALLOC (redundant );
422
+ filled_index = git__calloc ((commits -> length - 1 ), sizeof (unsigned int ));
423
+ GITERR_CHECK_ALLOC (filled_index );
424
+
425
+ for (i = 0 ; i < commits -> length ; ++ i ) {
426
+ if ((error = git_commit_list_parse (walk , commits -> contents [i ])) < 0 )
427
+ goto done ;
428
+ }
429
+
430
+ for (i = 0 ; i < commits -> length ; ++ i ) {
431
+ git_commit_list * common = NULL ;
432
+ git_commit_list_node * commit = commits -> contents [i ];
433
+
434
+ if (redundant [i ])
435
+ continue ;
436
+
437
+ git_vector_clear (& work );
438
+
439
+ for (j = 0 ; j < commits -> length ; j ++ ) {
440
+ if (i == j || redundant [j ])
441
+ continue ;
442
+
443
+ filled_index [work .length ] = j ;
444
+ if ((error = git_vector_insert (& work , commits -> contents [j ])) < 0 )
445
+ goto done ;
446
+ }
447
+
448
+ error = paint_down_to_common (& common , walk , commit , & work );
449
+ if (error < 0 )
450
+ goto done ;
451
+
452
+ if (commit -> flags & PARENT2 )
453
+ redundant [i ] = 1 ;
454
+
455
+ for (j = 0 ; j < work .length ; j ++ ) {
456
+ git_commit_list_node * w = work .contents [j ];
457
+ if (w -> flags & PARENT1 )
458
+ redundant [filled_index [j ]] = 1 ;
459
+ }
460
+
461
+ clear_commit_marks (commit , ALL_FLAGS );
462
+ clear_commit_marks_many (& work , ALL_FLAGS );
463
+
464
+ git_commit_list_free (& common );
465
+ }
466
+
467
+ for (i = 0 ; i < commits -> length ; ++ i ) {
468
+ if (redundant [i ])
469
+ commits -> contents [i ] = NULL ;
470
+ }
471
+
472
+ done :
473
+ git__free (redundant );
474
+ git__free (filled_index );
475
+ git_vector_free (& work );
476
+ return error ;
477
+ }
478
+
479
+ int git_merge__bases_many (git_commit_list * * out , git_revwalk * walk , git_commit_list_node * one , git_vector * twos )
480
+ {
481
+ int error ;
482
+ unsigned int i ;
483
+ git_commit_list_node * two ;
484
+ git_commit_list * result = NULL , * tmp = NULL ;
485
+
486
+ /* If there's only the one commit, there can be no merge bases */
487
+ if (twos -> length == 0 ) {
488
+ * out = NULL ;
489
+ return 0 ;
490
+ }
491
+
492
+ /* if the commit is repeated, we have a our merge base already */
493
+ git_vector_foreach (twos , i , two ) {
494
+ if (one == two )
495
+ return git_commit_list_insert (one , out ) ? 0 : -1 ;
496
+ }
497
+
498
+ if (git_commit_list_parse (walk , one ) < 0 )
499
+ return -1 ;
500
+
501
+ error = paint_down_to_common (& result , walk , one , twos );
502
+ if (error < 0 )
503
+ return error ;
379
504
380
505
/* filter out any stale commits in the results */
381
506
tmp = result ;
382
507
result = NULL ;
383
508
384
509
while (tmp ) {
385
- struct git_commit_list * next = tmp -> next ;
386
- if (!(tmp -> item -> flags & STALE ))
387
- if (git_commit_list_insert_by_date (tmp -> item , & result ) == NULL )
510
+ git_commit_list_node * c = git_commit_list_pop ( & tmp ) ;
511
+ if (!(c -> flags & STALE ))
512
+ if (git_commit_list_insert_by_date (c , & result ) == NULL )
388
513
return -1 ;
514
+ }
515
+
516
+ /*
517
+ * more than one merge base -- see if there are redundant merge
518
+ * bases and remove them
519
+ */
520
+ if (result && result -> next ) {
521
+ git_vector redundant = GIT_VECTOR_INIT ;
522
+
523
+ while (result )
524
+ git_vector_insert (& redundant , git_commit_list_pop (& result ));
525
+
526
+ clear_commit_marks (one , ALL_FLAGS );
527
+ clear_commit_marks_many (twos , ALL_FLAGS );
528
+
529
+ if ((error = remove_redundant (walk , & redundant )) < 0 ) {
530
+ git_vector_free (& redundant );
531
+ return error ;
532
+ }
533
+
534
+ git_vector_foreach (& redundant , i , two ) {
535
+ if (two != NULL )
536
+ git_commit_list_insert_by_date (two , & result );
537
+ }
389
538
390
- git__free (tmp );
391
- tmp = next ;
539
+ git_vector_free (& redundant );
392
540
}
393
541
394
542
* out = result ;
0 commit comments