@@ -202,6 +202,20 @@ struct git_graph {
202
202
* previous commit.
203
203
*/
204
204
int prev_commit_index ;
205
+ /*
206
+ * Which layout variant to use to display merge commits. If the
207
+ * commit's first parent is known to be in a column to the left of the
208
+ * merge, then this value is 0 and we use the layout on the left.
209
+ * Otherwise, the value is 1 and the layout on the right is used. This
210
+ * field tells us how many columns the first parent occupies.
211
+ *
212
+ * 0) 1)
213
+ *
214
+ * | | | *-. | | *---.
215
+ * | |_|/|\ \ | | |\ \ \
216
+ * |/| | | | | | | | | | *
217
+ */
218
+ int merge_layout ;
205
219
/*
206
220
* The maximum number of columns that can be stored in the columns
207
221
* and new_columns arrays. This is also half the number of entries
@@ -313,6 +327,7 @@ struct git_graph *graph_init(struct rev_info *opt)
313
327
graph -> prev_state = GRAPH_PADDING ;
314
328
graph -> commit_index = 0 ;
315
329
graph -> prev_commit_index = 0 ;
330
+ graph -> merge_layout = 0 ;
316
331
graph -> num_columns = 0 ;
317
332
graph -> num_new_columns = 0 ;
318
333
graph -> mapping_size = 0 ;
@@ -472,9 +487,11 @@ static int graph_find_new_column_by_commit(struct git_graph *graph,
472
487
}
473
488
474
489
static void graph_insert_into_new_columns (struct git_graph * graph ,
475
- struct commit * commit )
490
+ struct commit * commit ,
491
+ int idx )
476
492
{
477
493
int i = graph_find_new_column_by_commit (graph , commit );
494
+ int mapping_idx ;
478
495
479
496
/*
480
497
* If the commit is not already in the new_columns array, then add it
@@ -486,8 +503,26 @@ static void graph_insert_into_new_columns(struct git_graph *graph,
486
503
graph -> new_columns [i ].color = graph_find_commit_color (graph , commit );
487
504
}
488
505
489
- graph -> mapping [graph -> width ] = i ;
490
- graph -> width += 2 ;
506
+ if (graph -> num_parents > 1 && idx > -1 && graph -> merge_layout == -1 ) {
507
+ /*
508
+ * If this is the first parent of a merge, choose a layout for
509
+ * the merge line based on whether the parent appears in a
510
+ * column to the left of the merge
511
+ */
512
+ int dist , shift ;
513
+
514
+ dist = idx - i ;
515
+ shift = (dist > 1 ) ? 2 * dist - 3 : 1 ;
516
+
517
+ graph -> merge_layout = (dist > 0 ) ? 0 : 1 ;
518
+ mapping_idx = graph -> width + (graph -> merge_layout - 1 ) * shift ;
519
+ graph -> width += 2 * graph -> merge_layout ;
520
+ } else {
521
+ mapping_idx = graph -> width ;
522
+ graph -> width += 2 ;
523
+ }
524
+
525
+ graph -> mapping [mapping_idx ] = i ;
491
526
}
492
527
493
528
static void graph_update_columns (struct git_graph * graph )
@@ -553,6 +588,7 @@ static void graph_update_columns(struct git_graph *graph)
553
588
if (col_commit == graph -> commit ) {
554
589
seen_this = 1 ;
555
590
graph -> commit_index = i ;
591
+ graph -> merge_layout = -1 ;
556
592
for (parent = first_interesting_parent (graph );
557
593
parent ;
558
594
parent = next_interesting_parent (graph , parent )) {
@@ -565,7 +601,7 @@ static void graph_update_columns(struct git_graph *graph)
565
601
!is_commit_in_columns ) {
566
602
graph_increment_column_color (graph );
567
603
}
568
- graph_insert_into_new_columns (graph , parent -> item );
604
+ graph_insert_into_new_columns (graph , parent -> item , i );
569
605
}
570
606
/*
571
607
* We always need to increment graph->width by at
@@ -576,7 +612,7 @@ static void graph_update_columns(struct git_graph *graph)
576
612
if (graph -> num_parents == 0 )
577
613
graph -> width += 2 ;
578
614
} else {
579
- graph_insert_into_new_columns (graph , col_commit );
615
+ graph_insert_into_new_columns (graph , col_commit , -1 );
580
616
}
581
617
}
582
618
@@ -588,10 +624,36 @@ static void graph_update_columns(struct git_graph *graph)
588
624
graph -> mapping_size -- ;
589
625
}
590
626
627
+ static int graph_num_expansion_rows (struct git_graph * graph )
628
+ {
629
+ /*
630
+ * Normally, we need two expansion rows for each dashed parent line from
631
+ * an octopus merge:
632
+ *
633
+ * | *
634
+ * | |\
635
+ * | | \
636
+ * | | \
637
+ * | *-. \
638
+ * | |\ \ \
639
+ *
640
+ * If the merge is skewed to the left, then its parents occupy one less
641
+ * column, and we don't need as many expansion rows to route around it;
642
+ * in some cases that means we don't need any expansion rows at all:
643
+ *
644
+ * | *
645
+ * | |\
646
+ * | * \
647
+ * |/|\ \
648
+ */
649
+ return (graph -> num_parents + graph -> merge_layout - 3 ) * 2 ;
650
+ }
651
+
591
652
static int graph_needs_pre_commit_line (struct git_graph * graph )
592
653
{
593
654
return graph -> num_parents >= 3 &&
594
- graph -> commit_index < (graph -> num_columns - 1 );
655
+ graph -> commit_index < (graph -> num_columns - 1 ) &&
656
+ graph -> expansion_row < graph_num_expansion_rows (graph );
595
657
}
596
658
597
659
void graph_update (struct git_graph * graph , struct commit * commit )
@@ -728,7 +790,6 @@ static void graph_output_skip_line(struct git_graph *graph, struct graph_line *l
728
790
static void graph_output_pre_commit_line (struct git_graph * graph ,
729
791
struct graph_line * line )
730
792
{
731
- int num_expansion_rows ;
732
793
int i , seen_this ;
733
794
734
795
/*
@@ -739,14 +800,13 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
739
800
* We need 2 extra rows for every parent over 2.
740
801
*/
741
802
assert (graph -> num_parents >= 3 );
742
- num_expansion_rows = (graph -> num_parents - 2 ) * 2 ;
743
803
744
804
/*
745
805
* graph->expansion_row tracks the current expansion row we are on.
746
806
* It should be in the range [0, num_expansion_rows - 1]
747
807
*/
748
808
assert (0 <= graph -> expansion_row &&
749
- graph -> expansion_row < num_expansion_rows );
809
+ graph -> expansion_row < graph_num_expansion_rows ( graph ) );
750
810
751
811
/*
752
812
* Output the row
@@ -786,7 +846,7 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
786
846
* and move to state GRAPH_COMMIT if necessary
787
847
*/
788
848
graph -> expansion_row ++ ;
789
- if (graph -> expansion_row >= num_expansion_rows )
849
+ if (! graph_needs_pre_commit_line ( graph ) )
790
850
graph_update_state (graph , GRAPH_COMMIT );
791
851
}
792
852
@@ -824,17 +884,17 @@ static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line
824
884
* x 0 1 2 3
825
885
*
826
886
*/
827
- const int dashless_parents = 2 ;
887
+ const int dashless_parents = 3 - graph -> merge_layout ;
828
888
int dashful_parents = graph -> num_parents - dashless_parents ;
829
889
830
890
/*
831
891
* Usually, we add one new column for each parent (like the diagram
832
892
* above) but sometimes the first parent goes into an existing column,
833
893
* like this:
834
894
*
835
- * | *--- .
836
- * | |\ \ \
837
- * |/ / / /
895
+ * | *-.
896
+ * |/| \ \
897
+ * | | | |
838
898
* x 0 1 2
839
899
*
840
900
* In which case the number of parents will be one greater than the
@@ -925,10 +985,15 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
925
985
graph_update_state (graph , GRAPH_COLLAPSING );
926
986
}
927
987
988
+ const char merge_chars [] = {'/' , '|' , '\\' };
989
+
928
990
static void graph_output_post_merge_line (struct git_graph * graph , struct graph_line * line )
929
991
{
930
992
int seen_this = 0 ;
931
- int i , j ;
993
+ int i ;
994
+
995
+ struct commit_list * first_parent = first_interesting_parent (graph );
996
+ int seen_parent = 0 ;
932
997
933
998
/*
934
999
* Output the post-merge row
@@ -951,30 +1016,34 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
951
1016
* new_columns and use those to format the
952
1017
* edges.
953
1018
*/
954
- struct commit_list * parents = NULL ;
1019
+ struct commit_list * parents = first_parent ;
955
1020
int par_column ;
1021
+ int idx = graph -> merge_layout ;
1022
+ char c ;
956
1023
seen_this = 1 ;
957
- parents = first_interesting_parent (graph );
958
- assert (parents );
959
- par_column = graph_find_new_column_by_commit (graph , parents -> item );
960
- assert (par_column >= 0 );
961
-
962
- graph_line_write_column (line , & graph -> new_columns [par_column ], '|' );
963
- for (j = 0 ; j < graph -> num_parents - 1 ; j ++ ) {
964
- parents = next_interesting_parent (graph , parents );
965
- assert (parents );
1024
+
1025
+ for (; parents ; parents = next_interesting_parent (graph , parents )) {
966
1026
par_column = graph_find_new_column_by_commit (graph , parents -> item );
967
1027
assert (par_column >= 0 );
968
- graph_line_write_column (line , & graph -> new_columns [par_column ], '\\' );
969
- graph_line_addch (line , ' ' );
1028
+
1029
+ c = merge_chars [idx ];
1030
+ graph_line_write_column (line , & graph -> new_columns [par_column ], c );
1031
+ if (idx == 2 )
1032
+ graph_line_addch (line , ' ' );
1033
+ else
1034
+ idx ++ ;
970
1035
}
971
1036
} else if (seen_this ) {
972
1037
graph_line_write_column (line , col , '\\' );
973
1038
graph_line_addch (line , ' ' );
974
1039
} else {
975
1040
graph_line_write_column (line , col , '|' );
976
- graph_line_addch (line , ' ' );
1041
+ if (graph -> merge_layout != 0 || i != graph -> commit_index - 1 )
1042
+ graph_line_addch (line , seen_parent ? '_' : ' ' );
977
1043
}
1044
+
1045
+ if (col_commit == first_parent -> item )
1046
+ seen_parent = 1 ;
978
1047
}
979
1048
980
1049
/*
0 commit comments