This is to separate out connected regions of the resulting commit graph so as to not have them confused as belonging to the same timeline. --- graph.c | 55 +++++++++++- t/t4218-log-graph-connected-regions.sh | 119 +++++++++++++++++++++++++ 2 files changed, 170 insertions(+), 4 deletions(-) create mode 100755 t/t4218-log-graph-connected-regions.sh diff --git a/graph.c b/graph.c index 1ca34770ee..c0107c02fa 100644 --- a/graph.c +++ b/graph.c @@ -69,6 +69,12 @@ enum graph_state { GRAPH_COLLAPSING }; +enum connected_region_state { + CONNECTED_REGION_FIRST_COMMIT, + CONNECTED_REGION_USE_CURRENT, + CONNECTED_REGION_NEW_REGION +}; + static void graph_show_line_prefix(const struct diff_options *diffopt) { if (!diffopt || !diffopt->line_prefix) @@ -310,6 +316,12 @@ struct git_graph { * stored as an index into the array column_colors. */ unsigned short default_column_color; + /* + * The state of which connected region the current commit belongs to. + * This is used to output a clarifying separator line between + * connected regions. + */ + enum connected_region_state connected_region_state; }; static struct strbuf *diff_output_prefix_callback(struct diff_options *opt, void *data) @@ -380,6 +392,7 @@ struct git_graph *graph_init(struct rev_info *opt) * This way we start at 0 for the first commit. */ graph->default_column_color = column_colors_max - 1; + graph->connected_region_state = CONNECTED_REGION_FIRST_COMMIT; /* * Allocate a reasonably large default number of columns @@ -729,9 +742,9 @@ static int graph_num_expansion_rows(struct git_graph *graph) static int graph_needs_pre_commit_line(struct git_graph *graph) { - return graph->num_parents >= 3 && + return graph->connected_region_state == CONNECTED_REGION_NEW_REGION || (graph->num_parents >= 3 && graph->commit_index < (graph->num_columns - 1) && - graph->expansion_row < graph_num_expansion_rows(graph); + graph->expansion_row < graph_num_expansion_rows(graph)); } void graph_update(struct git_graph *graph, struct commit *commit) @@ -760,6 +773,12 @@ void graph_update(struct git_graph *graph, struct commit *commit) * commit. */ graph->prev_commit_index = graph->commit_index; + + /* + * Determine whether this commit belongs to a new connected region. + */ + graph->connected_region_state = (graph->connected_region_state != CONNECTED_REGION_FIRST_COMMIT && + graph->num_new_columns == 0) ? CONNECTED_REGION_NEW_REGION : CONNECTED_REGION_USE_CURRENT; /* * Call graph_update_columns() to update @@ -865,8 +884,28 @@ static void graph_output_skip_line(struct git_graph *graph, struct graph_line *l graph_update_state(graph, GRAPH_COMMIT); } -static void graph_output_pre_commit_line(struct git_graph *graph, - struct graph_line *line) +static void graph_output_separator_line(struct git_graph *graph, struct graph_line *line) +{ + /* + * This function adds a row that separates two disconnected graphs, + * as the appearance of multiple separate commits on top of each other + * may cause a misunderstanding that they belong to a timeline. + */ + assert(graph->connected_region_state == CONNECTED_REGION_NEW_REGION); + + /* + * Output the row. + */ + graph_line_addstr(line, "---"); + + /* + * Immediately move to GRAPH_COMMIT state as there for sure aren't going to be + * any more pre-commit lines. + */ + graph_update_state(graph, GRAPH_COMMIT); +} + +static void graph_output_parent_expansion_line(struct git_graph *graph, struct graph_line *line) { int i, seen_this; @@ -928,6 +967,14 @@ static void graph_output_pre_commit_line(struct git_graph *graph, graph_update_state(graph, GRAPH_COMMIT); } +static void graph_output_pre_commit_line(struct git_graph *graph, struct graph_line *line) +{ + if (graph->connected_region_state == CONNECTED_REGION_NEW_REGION) + graph_output_separator_line(graph, line); + else + graph_output_parent_expansion_line(graph, line); +} + static void graph_output_commit_char(struct git_graph *graph, struct graph_line *line) { /* diff --git a/t/t4218-log-graph-connected-regions.sh b/t/t4218-log-graph-connected-regions.sh new file mode 100755 index 0000000000..4efe17827e --- /dev/null +++ b/t/t4218-log-graph-connected-regions.sh @@ -0,0 +1,119 @@ +#!/bin/sh + +test_description="git log --graph connected regions" + +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh +. "$TEST_DIRECTORY/lib-terminal.sh" +. "$TEST_DIRECTORY/lib-log-graph.sh" + +test_cmp_graph () { + lib_test_cmp_graph --format=%s "$@" +} + +add_commit () { + touch $1 && + git add $1 && + git commit -m $1 + git tag "$1-commit" +} + +test_expect_success setup ' + git checkout -b a && + add_commit root && + + add_commit a1 && + add_commit a2 && + add_commit a3 && + + git checkout -b b root-commit && + add_commit b1 && + add_commit b2 && + git checkout -b c && + add_commit c3 && + git checkout b && + add_commit b3 && + git merge c -m b4 && + + git checkout -b d root-commit && + add_commit d1 && + add_commit d2 && + git checkout -b e && + add_commit e3 && + git checkout d && + add_commit d3 && + add_commit d4 +' + +cat > expect <<\EOF +* a3 +* a2 +* a1 +| * b4 +| |\ +| | * c3 +| * | b3 +| |/ +| * b2 +| * b1 +|/ +| * d4 +| * d3 +| | * e3 +| |/ +| * d2 +| * d1 +|/ +* root +EOF + +test_expect_success 'all commits' ' + test_cmp_graph a b c d e +' + +cat > expect <<\EOF +* a3 +* a2 +* a1 +--- +* b4 +|\ +| * c3 +* | b3 +|/ +* b2 +* b1 +--- +* d4 +* d3 +| * e3 +|/ +* d2 +* d1 +EOF + +test_expect_success 'without root commit' ' + test_cmp_graph a b c d e ^root-commit +' + +cat > expect <<\EOF +* a3 +--- +* b4 +|\ +| * c3 +* b3 +--- +* d4 +* d3 +--- +* e3 +EOF + +test_expect_success "branches' tips" ' + test_cmp_graph a b c d e ^a2-commit ^b2-commit ^d2-commit +' + +test_done -- 2.44.0