graph API: improve display of merge commits
This change improves the way merge commits are displayed, to eliminate a few visual artifacts. Previously, merge commits were displayed as: | M \ | |\ | As pointed out by Teemu Likonen, this didn't look nice if the rightmost branch line was displayed as '\' on the previous line, as it then appeared to have an extra space in it: | |\ | M \ | |\ | This change updates the code so that branch lines to the right of merge commits are printed slightly differently depending on how the previous line was displayed: | |\ | | | | | / | M \ | M | | M | | |\ \ | |\ \ | |\ \ Signed-off-by: Adam Simpkins <adam@adamsimpkins.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Adam Simpkins committed
Jun 1, 2008 at 13:56 UTC
3395908ee481e91bbe3ba054a7419b071b09cdef
1 file changed
+93
-17
graph.c
+93
-17
@@ -80,6 +80,27 @@ struct git_graph {
80
* This tells us what kind of line graph_next_line() should output.
81
*/
82
enum graph_state state;
83
+ /*
84
+ * The output state for the previous line of output.
85
+ * This is primarily used to determine how the first merge line
86
+ * should appear, based on the last line of the previous commit.
87
+ */
88
+ enum graph_state prev_state;
89
+ /*
90
+ * The index of the column that refers to this commit.
91
+ *
92
+ * If none of the incoming columns refer to this commit,
93
+ * this will be equal to num_columns.
94
+ */
95
+ int commit_index;
96
+ /*
97
+ * The commit_index for the previously displayed commit.
98
+ *
99
+ * This is used to determine how the first line of a merge
100
+ * graph output should appear, based on the last line of the
101
+ * previous commit.
102
+ */
103
+ int prev_commit_index;
104
/*
105
* The maximum number of columns that can be stored in the columns
106
* and new_columns arrays. This is also half the number of entries
@@ -137,6 +158,9 @@ struct git_graph *graph_init(struct rev_info *opt)
158
graph->num_parents = 0;
159
graph->expansion_row = 0;
160
graph->state = GRAPH_PADDING;
161
+ graph->prev_state = GRAPH_PADDING;
162
+ graph->commit_index = 0;
163
+ graph->prev_commit_index = 0;
164
graph->num_columns = 0;
165
graph->num_new_columns = 0;
166
graph->mapping_size = 0;
@@ -164,6 +188,12 @@ void graph_release(struct git_graph *graph)
188
free(graph);
189
}
190
191
+static void graph_update_state(struct git_graph *graph, enum graph_state s)
192
+{
193
+ graph->prev_state = graph->state;
194
+ graph->state = s;
195
+}
196
+
197
static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
198
{
199
if (graph->column_capacity >= num_columns)
@@ -342,6 +372,7 @@ static void graph_update_columns(struct git_graph *graph)
372
if (col_commit == graph->commit) {
373
int old_mapping_idx = mapping_idx;
374
seen_this = 1;
375
+ graph->commit_index = i;
376
for (parent = graph->commit->parents;
377
parent;
378
parent = parent->next) {
@@ -394,6 +425,13 @@ void graph_update(struct git_graph *graph, struct commit *commit)
425
graph->num_parents++;
426
}
427
428
+ /*
429
+ * Store the old commit_index in prev_commit_index.
430
+ * graph_update_columns() will update graph->commit_index for this
431
+ * commit.
432
+ */
433
+ graph->prev_commit_index = graph->commit_index;
434
+
435
/*
436
* Call graph_update_columns() to update
437
* columns, new_columns, and mapping.
@@ -404,6 +442,9 @@ void graph_update(struct git_graph *graph, struct commit *commit)
442
443
/*
444
* Update graph->state.
445
+ * Note that we don't call graph_update_state() here, since
446
+ * we don't want to update graph->prev_state. No line for
447
+ * graph->state was ever printed.
448
*
449
* If the previous commit didn't get to the GRAPH_PADDING state,
450
* it never finished its output. Goto GRAPH_SKIP, to print out
@@ -498,9 +539,9 @@ static void graph_output_skip_line(struct git_graph *graph, struct strbuf *sb)
539
graph_pad_horizontally(graph, sb);
540
541
if (graph->num_parents >= 3)
501
- graph->state = GRAPH_PRE_COMMIT;
542
+ graph_update_state(graph, GRAPH_PRE_COMMIT);
543
else
503
- graph->state = GRAPH_COMMIT;
544
+ graph_update_state(graph, GRAPH_COMMIT);
545
}
546
547
static void graph_output_pre_commit_line(struct git_graph *graph,
@@ -535,7 +576,22 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
576
if (col->commit == graph->commit) {
577
seen_this = 1;
578
strbuf_addf(sb, "| %*s", graph->expansion_row, "");
538
- } else if (seen_this) {
579
+ } else if (seen_this && (graph->expansion_row == 0)) {
580
+ /*
581
+ * This is the first line of the pre-commit output.
582
+ * If the previous commit was a merge commit and
583
+ * ended in the GRAPH_POST_MERGE state, all branch
584
+ * lines after graph->prev_commit_index were
585
+ * printed as "\" on the previous line. Continue
586
+ * to print them as "\" on this line. Otherwise,
587
+ * print the branch lines as "|".
588
+ */
589
+ if (graph->prev_state == GRAPH_POST_MERGE &&
590
+ graph->prev_commit_index < i)
591
+ strbuf_addstr(sb, "\\ ");
592
+ else
593
+ strbuf_addstr(sb, "| ");
594
+ } else if (seen_this && (graph->expansion_row > 0)) {
595
strbuf_addstr(sb, "\\ ");
596
} else {
597
strbuf_addstr(sb, "| ");
@@ -550,7 +606,7 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
606
*/
607
graph->expansion_row++;
608
if (graph->expansion_row >= num_expansion_rows)
553
- graph->state = GRAPH_COMMIT;
609
+ graph_update_state(graph, GRAPH_COMMIT);
610
}
611
612
static void graph_output_commit_char(struct git_graph *graph, struct strbuf *sb)
@@ -625,10 +681,8 @@ void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
681
seen_this = 1;
682
graph_output_commit_char(graph, sb);
683
628
- if (graph->num_parents < 2)
684
+ if (graph->num_parents < 3)
685
strbuf_addch(sb, ' ');
630
- else if (graph->num_parents == 2)
631
- strbuf_addstr(sb, " ");
686
else {
687
int num_dashes =
688
((graph->num_parents - 2) * 2) - 1;
@@ -636,8 +690,27 @@ void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
690
strbuf_addch(sb, '-');
691
strbuf_addstr(sb, ". ");
692
}
639
- } else if (seen_this && (graph->num_parents > 1)) {
693
+ } else if (seen_this && (graph->num_parents > 2)) {
694
strbuf_addstr(sb, "\\ ");
695
+ } else if (seen_this && (graph->num_parents == 2)) {
696
+ /*
697
+ * This is a 2-way merge commit.
698
+ * There is no GRAPH_PRE_COMMIT stage for 2-way
699
+ * merges, so this is the first line of output
700
+ * for this commit. Check to see what the previous
701
+ * line of output was.
702
+ *
703
+ * If it was GRAPH_POST_MERGE, the branch line
704
+ * coming into this commit may have been '\',
705
+ * and not '|' or '/'. If so, output the branch
706
+ * line as '\' on this line, instead of '|'. This
707
+ * makes the output look nicer.
708
+ */
709
+ if (graph->prev_state == GRAPH_POST_MERGE &&
710
+ graph->prev_commit_index < i)
711
+ strbuf_addstr(sb, "\\ ");
712
+ else
713
+ strbuf_addstr(sb, "| ");
714
} else {
715
strbuf_addstr(sb, "| ");
716
}
@@ -649,11 +722,11 @@ void graph_output_commit_line(struct git_graph *graph, struct strbuf *sb)
722
* Update graph->state
723
*/
724
if (graph->num_parents > 1)
652
- graph->state = GRAPH_POST_MERGE;
725
+ graph_update_state(graph, GRAPH_POST_MERGE);
726
else if (graph_is_mapping_correct(graph))
654
- graph->state = GRAPH_PADDING;
727
+ graph_update_state(graph, GRAPH_PADDING);
728
else
656
- graph->state = GRAPH_COLLAPSING;
729
+ graph_update_state(graph, GRAPH_COLLAPSING);
730
}
731
732
void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
@@ -679,9 +752,7 @@ void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
752
strbuf_addch(sb, '|');
753
for (j = 0; j < graph->num_parents - 1; j++)
754
strbuf_addstr(sb, "\\ ");
682
- if (graph->num_parents == 2)
683
- strbuf_addch(sb, ' ');
684
- } else if (seen_this && (graph->num_parents > 2)) {
755
+ } else if (seen_this) {
756
strbuf_addstr(sb, "\\ ");
757
} else {
758
strbuf_addstr(sb, "| ");
@@ -694,9 +765,9 @@ void graph_output_post_merge_line(struct git_graph *graph, struct strbuf *sb)
765
* Update graph->state
766
*/
767
if (graph_is_mapping_correct(graph))
697
- graph->state = GRAPH_PADDING;
768
+ graph_update_state(graph, GRAPH_PADDING);
769
else
699
- graph->state = GRAPH_COLLAPSING;
770
+ graph_update_state(graph, GRAPH_COLLAPSING);
771
}
772
773
void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
@@ -801,7 +872,7 @@ void graph_output_collapsing_line(struct git_graph *graph, struct strbuf *sb)
872
* Otherwise, we need to collapse some branch lines together.
873
*/
874
if (graph_is_mapping_correct(graph))
804
- graph->state = GRAPH_PADDING;
875
+ graph_update_state(graph, GRAPH_PADDING);
876
}
877
878
int graph_next_line(struct git_graph *graph, struct strbuf *sb)
@@ -865,6 +936,11 @@ void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
936
}
937
938
graph_pad_horizontally(graph, sb);
939
+
940
+ /*
941
+ * Update graph->prev_state since we have output a padding line
942
+ */
943
+ graph->prev_state = GRAPH_PADDING;
944
}
945
946
int graph_is_commit_finished(struct git_graph const *graph)