graph: flatten edges that fuse with their right neighbor

When a merge commit is printed and its final parent is the same commit
that occupies the column to the right of the merge, this results in a
kink in the displayed edges:

        * |
        |\ \
        | |/
        | *

Graphs containing these shapes can be hard to read, as the expansion to
the right followed immediately by collapsing back to the left creates a
lot of zig-zagging edges, especially when many columns are present.

We can improve this by eliminating the zig-zag and having the merge's
final parent edge fuse immediately with its neighbor:

        * |
        |\|
        | *

This reduces the horizontal width for the current commit by 2, and
requires one less row, making the graph display more compact. Taken in
combination with other graph-smoothing enhancements, it greatly
compresses the space needed to display certain histories:

        *
        |\
        | *                       *
        | |\                      |\
        | | *                     | *
        | | |                     | |\
        | |  \                    | | *
        | *-. \                   | * |
        | |\ \ \        =>        |/|\|
        |/ / / /                  | | *
        | | | /                   | * |
        | | |/                    | |/
        | | *                     * /
        | * |                     |/
        | |/                      *
        * |
        |/
        *

One of the test cases here cannot be correctly rendered in Git v2.23.0;
it produces this output following commit E:

        | | *-. \   5_E
        | | |\ \ \
        | |/ / / /
        | | | / _
        | |_|/
        |/| |

The new implementation makes sure that the rightmost edge in this
history is not left dangling as above.

Signed-off-by: James Coglan <jcoglan@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
James Coglan 2019-10-15 23:47:58 +00:00 committed by Junio C Hamano
parent 479db18bc0
commit 92beecc136
3 changed files with 86 additions and 34 deletions

34
graph.c
View File

@ -557,8 +557,24 @@ static void graph_insert_into_new_columns(struct git_graph *graph,
shift = (dist > 1) ? 2 * dist - 3 : 1;
graph->merge_layout = (dist > 0) ? 0 : 1;
graph->edges_added = graph->num_parents + graph->merge_layout - 2;
mapping_idx = graph->width + (graph->merge_layout - 1) * shift;
graph->width += 2 * graph->merge_layout;
} else if (graph->edges_added > 0 && i == graph->mapping[graph->width - 2]) {
/*
* If some columns have been added by a merge, but this commit
* was found in the last existing column, then adjust the
* numbers so that the two edges immediately join, i.e.:
*
* * | * |
* |\ \ => |\|
* | |/ | *
* | *
*/
mapping_idx = graph->width - 2;
graph->edges_added = -1;
} else {
mapping_idx = graph->width;
graph->width += 2;
@ -604,6 +620,8 @@ static void graph_update_columns(struct git_graph *graph)
graph->mapping[i] = -1;
graph->width = 0;
graph->prev_edges_added = graph->edges_added;
graph->edges_added = 0;
/*
* Populate graph->new_columns and graph->mapping
@ -731,9 +749,6 @@ void graph_update(struct git_graph *graph, struct commit *commit)
*/
graph_update_columns(graph);
graph->prev_edges_added = graph->edges_added;
graph->edges_added = graph->num_parents + graph->merge_layout - 2;
graph->expansion_row = 0;
/*
@ -1041,7 +1056,7 @@ const char merge_chars[] = {'/', '|', '\\'};
static void graph_output_post_merge_line(struct git_graph *graph, struct graph_line *line)
{
int seen_this = 0;
int i;
int i, j;
struct commit_list *first_parent = first_interesting_parent(graph);
int seen_parent = 0;
@ -1073,16 +1088,19 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
char c;
seen_this = 1;
for (; parents; parents = next_interesting_parent(graph, parents)) {
for (j = 0; j < graph->num_parents; j++) {
par_column = graph_find_new_column_by_commit(graph, parents->item);
assert(par_column >= 0);
c = merge_chars[idx];
graph_line_write_column(line, &graph->new_columns[par_column], c);
if (idx == 2)
graph_line_addch(line, ' ');
else
if (idx == 2) {
if (graph->edges_added > 0 || j < graph->num_parents - 1)
graph_line_addch(line, ' ');
} else {
idx++;
}
parents = next_interesting_parent(graph, parents);
}
if (graph->edges_added == 0)
graph_line_addch(line, ' ');

View File

@ -11,9 +11,8 @@ test_expect_success 'log --graph with merge fusing with its left and right neigh
| * G
| |\
| | * F
| * | E
|/|\ \
| | |/
| * | E
|/|\|
| | * D
| * | C
| |/
@ -43,9 +42,9 @@ test_expect_success 'log --graph with left-skewed merge' '
| | | | * 0_G
| |_|_|/|
|/| | | |
| | | * | 0_F
| |_|/|\ \
|/| | | |/
| | | * | 0_F
| |_|/|\|
|/| | | |
| | | | * 0_E
| |_|_|/
|/| | |
@ -153,9 +152,8 @@ test_expect_success 'log --graph with nested right-skewed merge following left-s
| | * 3_G
| * | 3_F
|/| |
| * | 3_E
| |\ \
| | |/
| * | 3_E
| |\|
| | * 3_D
| * | 3_C
| |/
@ -216,4 +214,44 @@ test_expect_success 'log --graph with right-skewed merge following a left-skewed
test_cmp expect actual
'
test_expect_success 'log --graph with octopus merge with column joining its penultimate parent' '
cat >expect <<-\EOF &&
* 5_H
|\
| *-. 5_G
| |\ \
| | | * 5_F
| | * | 5_E
| |/|\ \
| |_|/ /
|/| | /
| | |/
* | | 5_D
| | * 5_C
| |/
|/|
| * 5_B
|/
* 5_A
EOF
git checkout --orphan 5_p &&
test_commit 5_A &&
git branch 5_q &&
git branch 5_r &&
test_commit 5_B &&
git checkout 5_q && test_commit 5_C &&
git checkout 5_r && test_commit 5_D &&
git checkout 5_p &&
git merge --no-ff 5_q 5_r -m 5_E &&
git checkout 5_q && test_commit 5_F &&
git checkout -b 5_s 5_p^ &&
git merge --no-ff 5_p 5_q -m 5_G &&
git checkout 5_r &&
git merge --no-ff 5_s -m 5_H &&
git log --graph --pretty=tformat:%s | sed "s/ *$//" >actual &&
test_cmp expect actual
'
test_done

View File

@ -67,11 +67,10 @@ test_expect_success '--graph --all' '
echo "| * $C4" >> expected &&
echo "| * $C3" >> expected &&
echo "* | $A5" >> expected &&
echo "| | " >> expected &&
echo "| \\ " >> expected &&
echo "*-. \\ $A4" >> expected &&
echo "|\\ \\ \\ " >> expected &&
echo "| | |/ " >> expected &&
echo "| | " >> expected &&
echo "| \\ " >> expected &&
echo "*-. | $A4" >> expected &&
echo "|\\ \\| " >> expected &&
echo "| | * $C2" >> expected &&
echo "| | * $C1" >> expected &&
echo "| * | $B2" >> expected &&
@ -97,11 +96,10 @@ test_expect_success '--graph --simplify-by-decoration' '
echo "| * $C4" >> expected &&
echo "| * $C3" >> expected &&
echo "* | $A5" >> expected &&
echo "| | " >> expected &&
echo "| \\ " >> expected &&
echo "*-. \\ $A4" >> expected &&
echo "|\\ \\ \\ " >> expected &&
echo "| | |/ " >> expected &&
echo "| | " >> expected &&
echo "| \\ " >> expected &&
echo "*-. | $A4" >> expected &&
echo "|\\ \\| " >> expected &&
echo "| | * $C2" >> expected &&
echo "| | * $C1" >> expected &&
echo "| * | $B2" >> expected &&
@ -131,9 +129,8 @@ test_expect_success '--graph --simplify-by-decoration prune branch B' '
echo "| * $C4" >> expected &&
echo "| * $C3" >> expected &&
echo "* | $A5" >> expected &&
echo "* | $A4" >> expected &&
echo "|\\ \\ " >> expected &&
echo "| |/ " >> expected &&
echo "* | $A4" >> expected &&
echo "|\\| " >> expected &&
echo "| * $C2" >> expected &&
echo "| * $C1" >> expected &&
echo "* | $A3" >> expected &&
@ -151,10 +148,9 @@ test_expect_success '--graph --full-history -- bar.txt' '
echo "|\\ " >> expected &&
echo "| * $C4" >> expected &&
echo "* | $A5" >> expected &&
echo "* | $A4" >> expected &&
echo "|\\ \\ " >> expected &&
echo "| |/ " >> expected &&
echo "* / $A3" >> expected &&
echo "* | $A4" >> expected &&
echo "|\\| " >> expected &&
echo "* | $A3" >> expected &&
echo "|/ " >> expected &&
echo "* $A2" >> expected &&
git rev-list --graph --full-history --all -- bar.txt > actual &&