graph: wrap cascading commits after 4 columns

Currently the visual root commits in a graph cascade indefinitely until a commit which is not a visual root or the last commit appears. On filters like --author where one author might contribute mostly on single patches this can become a visual issue. Make the cascading wrap after 4 columns. There are two possible cases of the wrap: 1. No ambiguity: * A * B * C * D * E * F 2. Ambiguous conflict: If F happens to not be a visual root and E gets wrapped back to the initial column then E and F would be vertically adjacent. The solution is to forcefully indent E one level: * A * B * C * D * E * F * F The magic number 4 comes as the minimum number of columns to wrap where the output shows clearly the commits are unrelated and doesn't cause too much "pyramid" effects Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Pablo Sabater committed Jul 14, 2026 at 14:09 UTC 233cc403310efbb12be7ecba997f7e378c6cc390
2 files changed +50 -1
graph.c
+21 -1
@@ -1042,6 +1042,23 @@ void graph_update(struct git_graph *graph, struct commit *commit)
1042 */
1043 if (!graph->visual_root_depth && flags.is_next_visual_root)
1044 graph->visual_root_cascade = 1;
1045 +
1046 + /*
1047 + * We wrap the cascading at a max of four columns at most, after
1048 + * that we wrap it back to the initial column.
1049 + *
1050 + * This could cause ambiguity in case of the next commit not
1051 + * being a visual root and be at the initial column after the
1052 + * first wrap.
1053 + *
1054 + * In case of being a non-visual-root the next, stop the
1055 + * cascading to get the commit indented.
1056 + */
1057 + if (!flags.is_next_visual_root &&
1058 + graph->visual_root_depth &&
1059 + !(graph->visual_root_depth % 4))
1060 + graph->visual_root_cascade = 0;
1061 +
1062 graph->visual_root_depth++;
1063 } else {
1064 graph->visual_root_depth = 0;
@@ -1328,8 +1345,11 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
1345 * Each visual column is 2 characters wide.
1346 * Omit the indentation for the first visual
1347 * root in cascade mode.
1348 + *
1349 + * Have a max of 4 columns when cascading, after
1350 + * that wrap it and repeat.
1351 */
1332 - int padding = (depth - graph->visual_root_cascade) * 2;
1352 + int padding = ((depth - graph->visual_root_cascade) % 4) * 2;
1353 graph_line_addchars(line, ' ', padding);
1354 graph->width += padding;
1355 }
t/t4218-log-graph-indentation.sh
+29
@@ -511,4 +511,33 @@ test_expect_success '--grep skipped parent makes a visual root' '
511 EOF
512 '
513
514 +# The cascading wraps after 4 columns and when wraping (column % 4 == 0) if the
515 +# next is a non visual-root, force indentation to avoid an ambiguous graph
516 +# (commit 59_A is forcefully indented)
517 +test_expect_success 'visual root cascading gets wrapped after 4 columns' '
518 + create_orphan _58 && test_commit 58_A && test_commit 58_B &&
519 + create_orphan _59 && test_commit 59_A &&
520 + create_orphan _60 && test_commit 60_A &&
521 + create_orphan _61 && test_commit 61_A &&
522 + create_orphan _62 && test_commit 62_A &&
523 + create_orphan _63 && test_commit 63_A &&
524 + create_orphan _64 && test_commit 64_A &&
525 + create_orphan _65 && test_commit 65_A &&
526 + create_orphan _66 && test_commit 66_A &&
527 + create_orphan _67 && test_commit 67_A &&
528 + lib_test_check_graph _58 _59 _60 _61 _62 _63 _64 _65 _66 _67 <<-\EOF
529 + * 67_A
530 + * 66_A
531 + * 65_A
532 + * 64_A
533 + * 63_A
534 + * 62_A
535 + * 61_A
536 + * 60_A
537 + * 59_A
538 + * 58_B
539 + * 58_A
540 + EOF
541 +'
542 +
543 test_done