@@ -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 -> parents [0 ];
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,133 @@ 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
+ filled_index = git__calloc ((commits -> length - 1 ), sizeof (unsigned int ));
422
+
423
+ for (i = 0 ; i < commits -> length ; ++ i ) {
424
+ if ((error = git_commit_list_parse (walk , commits -> contents [i ])) < 0 )
425
+ goto done ;
426
+ }
427
+
428
+ for (i = 0 ; i < commits -> length ; ++ i ) {
429
+ git_commit_list * common = NULL ;
430
+ git_commit_list_node * commit = commits -> contents [i ];
431
+
432
+ if (redundant [i ])
433
+ continue ;
434
+
435
+ git_vector_clear (& work );
436
+
437
+ for (j = 0 ; j < commits -> length ; j ++ ) {
438
+ if (i == j || redundant [j ])
439
+ continue ;
440
+
441
+ filled_index [work .length ] = j ;
442
+ if ((error = git_vector_insert (& work , commits -> contents [j ])) < 0 )
443
+ goto done ;
444
+ }
445
+
446
+ error = paint_down_to_common (& common , walk , commit , & work );
447
+ if (error < 0 )
448
+ goto done ;
449
+
450
+ if (commit -> flags & PARENT2 )
451
+ redundant [i ] = 1 ;
452
+
453
+ for (j = 0 ; j < work .length ; j ++ ) {
454
+ git_commit_list_node * w = work .contents [j ];
455
+ if (w -> flags & PARENT1 )
456
+ redundant [filled_index [j ]] = 1 ;
457
+ }
458
+
459
+ clear_commit_marks (commit , ALL_FLAGS );
460
+ clear_commit_marks_many (& work , ALL_FLAGS );
461
+
462
+ git_commit_list_free (& common );
463
+ }
464
+
465
+ for (i = 0 ; i < commits -> length ; ++ i ) {
466
+ if (redundant [i ])
467
+ commits -> contents [i ] = NULL ;
468
+ }
469
+
470
+ done :
471
+ git__free (redundant );
472
+ git__free (filled_index );
473
+ git_vector_free (& work );
474
+ return error ;
475
+ }
476
+
477
+ int git_merge__bases_many (git_commit_list * * out , git_revwalk * walk , git_commit_list_node * one , git_vector * twos )
478
+ {
479
+ int error ;
480
+ unsigned int i ;
481
+ git_commit_list_node * two ;
482
+ git_commit_list * result = NULL , * tmp = NULL ;
483
+
484
+ /* If there's only the one commit, there can be no merge bases */
485
+ if (twos -> length == 0 ) {
486
+ * out = NULL ;
487
+ return 0 ;
488
+ }
489
+
490
+ /* if the commit is repeated, we have a our merge base already */
491
+ git_vector_foreach (twos , i , two ) {
492
+ if (one == two )
493
+ return git_commit_list_insert (one , out ) ? 0 : -1 ;
494
+ }
495
+
496
+ if (git_commit_list_parse (walk , one ) < 0 )
497
+ return -1 ;
498
+
499
+ error = paint_down_to_common (& result , walk , one , twos );
500
+ if (error < 0 )
501
+ return error ;
379
502
380
503
/* filter out any stale commits in the results */
381
504
tmp = result ;
382
505
result = NULL ;
383
506
384
507
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 )
508
+ git_commit_list_node * c = git_commit_list_pop ( & tmp ) ;
509
+ if (!(c -> flags & STALE ))
510
+ if (git_commit_list_insert_by_date (c , & result ) == NULL )
388
511
return -1 ;
512
+ }
513
+
514
+ /* more than one merge base -- remove redundants */
515
+ if (result && result -> next ) {
516
+ git_vector redundant = GIT_VECTOR_INIT ;
517
+
518
+ while (result )
519
+ git_vector_insert (& redundant , git_commit_list_pop (& result ));
520
+
521
+ clear_commit_marks (one , ALL_FLAGS );
522
+ clear_commit_marks_many (twos , ALL_FLAGS );
523
+
524
+ if ((error = remove_redundant (walk , & redundant )) < 0 ) {
525
+ git_vector_free (& redundant );
526
+ return error ;
527
+ }
528
+
529
+ git_vector_foreach (& redundant , i , two ) {
530
+ if (two != NULL )
531
+ git_commit_list_insert_by_date (two , & result );
532
+ }
389
533
390
- git__free (tmp );
391
- tmp = next ;
534
+ git_vector_free (& redundant );
392
535
}
393
536
394
537
* out = result ;
0 commit comments