202
* previous commit.
203
*/
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;
219
/*
220
* The maximum number of columns that can be stored in the columns
221
* and new_columns arrays. This is also half the number of entries
327
graph->prev_state = GRAPH_PADDING;
328
graph->commit_index = 0;
329
graph->prev_commit_index = 0;
330
+ graph->merge_layout = 0;
331
graph->num_columns = 0;
332
graph->num_new_columns = 0;
333
graph->mapping_size = 0;
487
}
488
489
static void graph_insert_into_new_columns(struct git_graph *graph,
475
- struct commit *commit)
490
+ struct commit *commit,
491
+ int idx)
492
{
493
int i = graph_find_new_column_by_commit(graph, commit);
494
+ int mapping_idx;
495
496
/*
497
* If the commit is not already in the new_columns array, then add it
503
graph->new_columns[i].color = graph_find_commit_color(graph, commit);
504
}
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;
526
}
527
528
static void graph_update_columns(struct git_graph *graph)
588
if (col_commit == graph->commit) {
589
seen_this = 1;
590
graph->commit_index = i;
591
+ graph->merge_layout = -1;
592
for (parent = first_interesting_parent(graph);
593
parent;
594
parent = next_interesting_parent(graph, parent)) {
601
!is_commit_in_columns) {
602
graph_increment_column_color(graph);
603
}
568
- graph_insert_into_new_columns(graph, parent->item);
604
+ graph_insert_into_new_columns(graph, parent->item, i);
605
}
606
/*
607
* We always need to increment graph->width by at
612
if (graph->num_parents == 0)
613
graph->width += 2;
614
} else {
579
- graph_insert_into_new_columns(graph, col_commit);
615
+ graph_insert_into_new_columns(graph, col_commit, -1);
616
}
617
}
618
624
graph->mapping_size--;
625
}
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
+
652
static int graph_needs_pre_commit_line(struct git_graph *graph)
653
{
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);
657
}
658
659
void graph_update(struct git_graph *graph, struct commit *commit)
790
static void graph_output_pre_commit_line(struct git_graph *graph,
791
struct graph_line *line)
792
{
731
- int num_expansion_rows;
793
int i, seen_this;
794
795
/*
800
* We need 2 extra rows for every parent over 2.
801
*/
802
assert(graph->num_parents >= 3);
742
- num_expansion_rows = (graph->num_parents - 2) * 2;
803
804
/*
805
* graph->expansion_row tracks the current expansion row we are on.
806
* It should be in the range [0, num_expansion_rows - 1]
807
*/
808
assert(0 <= graph->expansion_row &&
749
- graph->expansion_row < num_expansion_rows);
809
+ graph->expansion_row < graph_num_expansion_rows(graph));
810
811
/*
812
* Output the row
846
* and move to state GRAPH_COMMIT if necessary
847
*/
848
graph->expansion_row++;
789
- if (graph->expansion_row >= num_expansion_rows)
849
+ if (!graph_needs_pre_commit_line(graph))
850
graph_update_state(graph, GRAPH_COMMIT);
851
}
852
884
* x 0 1 2 3
885
*
886
*/
827
- const int dashless_parents = 2;
887
+ const int dashless_parents = 3 - graph->merge_layout;
888
int dashful_parents = graph->num_parents - dashless_parents;
889
890
/*
892
* above) but sometimes the first parent goes into an existing column,
893
* like this:
894
*
835
- * | *---.
836
- * | |\ \ \
837
- * |/ / / /
895
+ * | *-.
896
+ * |/|\ \
897
+ * | | | |
898
* x 0 1 2
899
*
900
* In which case the number of parents will be one greater than the
985
graph_update_state(graph, GRAPH_COLLAPSING);
986
}
987
988
+const char merge_chars[] = {'/', '|', '\\'};
989
+
990
static void graph_output_post_merge_line(struct git_graph *graph, struct graph_line *line)
991
{
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;
997
998
/*
999
* Output the post-merge row
1016
* new_columns and use those to format the
1017
* edges.
1018
*/
954
- struct commit_list *parents = NULL;
1019
+ struct commit_list *parents = first_parent;
1020
int par_column;
1021
+ int idx = graph->merge_layout;
1022
+ char c;
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)) {
1026
par_column = graph_find_new_column_by_commit(graph, parents->item);
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++;
1035
}
1036
} else if (seen_this) {
1037
graph_line_write_column(line, col, '\\');
1038
graph_line_addch(line, ' ');
1039
} else {
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 ? '_' : ' ');
1043
}
1044
+
1045
+ if (col_commit == first_parent->item)
1046
+ seen_parent = 1;
1047
}
1048
1049
/*