]> git.ipfire.org Git - thirdparty/git.git/commitdiff
graph: wrap cascading commits after 4 columns
authorPablo Sabater <pabloosabaterr@gmail.com>
Tue, 14 Jul 2026 12:09:36 +0000 (14:09 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 14 Jul 2026 14:32:51 +0000 (07:32 -0700)
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>
graph.c
t/t4218-log-graph-indentation.sh

diff --git a/graph.c b/graph.c
index 087094189f34671776c9ca71dcffb1468362e099..e3e206170c8453074ac751d3b48e20bc1118d3ea 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -1042,6 +1042,23 @@ void graph_update(struct git_graph *graph, struct commit *commit)
                 */
                if (!graph->visual_root_depth && flags.is_next_visual_root)
                        graph->visual_root_cascade = 1;
+
+               /*
+                * We wrap the cascading at a max of four columns at most, after
+                * that we wrap it back to the initial column.
+                *
+                * This could cause ambiguity in case of the next commit not
+                * being a visual root and be at the initial column after the
+                * first wrap.
+                *
+                * In case of being a non-visual-root the next, stop the
+                * cascading to get the commit indented.
+                */
+               if (!flags.is_next_visual_root &&
+                   graph->visual_root_depth &&
+                   !(graph->visual_root_depth % 4))
+                       graph->visual_root_cascade = 0;
+
                graph->visual_root_depth++;
        } else {
                graph->visual_root_depth = 0;
@@ -1328,8 +1345,11 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
                                 * Each visual column is 2 characters wide.
                                 * Omit the indentation for the first visual
                                 * root in cascade mode.
+                                *
+                                * Have a max of 4 columns when cascading, after
+                                * that wrap it and repeat.
                                 */
-                               int padding = (depth - graph->visual_root_cascade) * 2;
+                               int padding = ((depth - graph->visual_root_cascade) % 4) * 2;
                                graph_line_addchars(line, ' ', padding);
                                graph->width += padding;
                        }
index 60c7d84af7c9d63a9dfb1796083d66355fcdeb4c..d4c850c0d46e9b043f3b3a616af01ae07c91e644 100755 (executable)
@@ -511,4 +511,33 @@ test_expect_success '--grep skipped parent makes a visual root' '
        EOF
 '
 
+# The cascading wraps after 4 columns and when wraping (column % 4 == 0) if the
+# next is a non visual-root, force indentation to avoid an ambiguous graph
+# (commit 59_A is forcefully indented)
+test_expect_success 'visual root cascading gets wrapped after 4 columns' '
+       create_orphan _58 && test_commit 58_A && test_commit 58_B &&
+       create_orphan _59 && test_commit 59_A &&
+       create_orphan _60 && test_commit 60_A &&
+       create_orphan _61 && test_commit 61_A &&
+       create_orphan _62 && test_commit 62_A &&
+       create_orphan _63 && test_commit 63_A &&
+       create_orphan _64 && test_commit 64_A &&
+       create_orphan _65 && test_commit 65_A &&
+       create_orphan _66 && test_commit 66_A &&
+       create_orphan _67 && test_commit 67_A &&
+       lib_test_check_graph _58 _59 _60 _61 _62 _63 _64 _65 _66 _67 <<-\EOF
+       * 67_A
+         * 66_A
+           * 65_A
+             * 64_A
+       * 63_A
+         * 62_A
+           * 61_A
+             * 60_A
+         * 59_A
+       * 58_B
+       * 58_A
+       EOF
+'
+
 test_done