]> git.ipfire.org Git - thirdparty/git.git/commitdiff
graph: add a 2 commit buffer for lookahead
authorPablo Sabater <pabloosabaterr@gmail.com>
Tue, 14 Jul 2026 12:09:34 +0000 (14:09 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 14 Jul 2026 14:32:51 +0000 (07:32 -0700)
In a subsequent commit the graph renderer needs to know if the next
commit is a visual root or if it is the last commit to be shown. This
requires peeking 2 commits ahead.

Commits are pre-fetched in get_revision() through next_commit_to_show()
where they are also marked as SHOWN, regardless the source they come
from.

Update graph_is_interesting() so it considers commits inside the
lookahead buffer as interesting as well.

Helped-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
graph.c
graph.h
revision.c

diff --git a/graph.c b/graph.c
index 842282685f6cef791fdb1039ffe91e0fd2e3ed9e..89ebcf7540589d34b5be93ca194f8cd2d2eebd50 100644 (file)
--- a/graph.c
+++ b/graph.c
@@ -315,6 +315,14 @@ struct git_graph {
         * diff_output_prefix_callback().
         */
        struct strbuf prefix_buf;
+
+       /*
+        * Lookahead buffer: up to 2 pre-fetched commits that will be shown.
+        * Populated by get_revision() so graph_peek_next_visible() can use
+        * actual walk results instead of peeking at rev_info internals.
+        */
+       struct commit *lookahead[2];
+       int lookahead_nr;
 };
 
 static inline int graph_needs_truncation(struct git_graph *graph, int lane)
@@ -388,6 +396,9 @@ struct git_graph *graph_init(struct rev_info *opt)
        graph->num_columns = 0;
        graph->num_new_columns = 0;
        graph->mapping_size = 0;
+       graph->lookahead[0] = NULL;
+       graph->lookahead[1] = NULL;
+       graph->lookahead_nr = 0;
        /*
         * Start the column color at the maximum value, since we'll
         * always increment it for the first commit we output.
@@ -456,6 +467,15 @@ static void graph_ensure_capacity(struct git_graph *graph, int num_columns)
  */
 static int graph_is_interesting(struct git_graph *graph, struct commit *commit)
 {
+       /*
+        * Commits in the lookahead buffer have been pre-fetched by
+        * get_revision() and will be shown in the future. They already have
+        * the SHOWN flag set when they were pre-fetched but the graph still
+        * needs to treat them as interesting parents.
+        */
+       for (int i = 0; i < graph->lookahead_nr; i++)
+               if (graph->lookahead[i] == commit)
+                       return 1;
        /*
         * If revs->boundary is set, commits whose children have
         * been shown are always interesting, even if they have the
@@ -763,6 +783,37 @@ static int graph_needs_pre_commit_line(struct git_graph *graph)
               graph->expansion_row < graph_num_expansion_rows(graph);
 }
 
+struct commit *graph_pop_lookahead(struct git_graph *graph)
+{
+       struct commit *c;
+
+       if (!graph->lookahead_nr)
+               return NULL;
+
+       c = graph->lookahead[0];
+       if (!c)
+               BUG("lookahead buffer has %d entries but the first one is NULL",
+                   graph->lookahead_nr);
+
+       graph->lookahead[0] = graph->lookahead[1];
+       graph->lookahead[1] = NULL;
+       graph->lookahead_nr--;
+       return c;
+}
+
+int graph_get_lookahead_room(struct git_graph *graph)
+{
+       return (int)ARRAY_SIZE(graph->lookahead) - graph->lookahead_nr;
+}
+
+void graph_push_lookahead(struct git_graph *graph, struct commit *c)
+{
+       if (!graph_get_lookahead_room(graph))
+               BUG("pushing into lookahead buffer when it is already full");
+
+       graph->lookahead[graph->lookahead_nr++] = c;
+}
+
 void graph_update(struct git_graph *graph, struct commit *commit)
 {
        struct commit_list *parent;
diff --git a/graph.h b/graph.h
index 3fd1dcb2e94d4399fc40406f9ec71b319cda0d5f..1193711fb8892cc12d3250c3b7d34edb970491c5 100644 (file)
--- a/graph.h
+++ b/graph.h
@@ -262,4 +262,21 @@ void graph_show_commit_msg(struct git_graph *graph,
                           FILE *file,
                           struct strbuf const *sb);
 
+/*
+ * Pop the first commit from the graph's lookahead buffer.
+ * Returns NULL if the buffer is empty.
+ */
+struct commit *graph_pop_lookahead(struct git_graph *graph);
+
+/*
+ * Returns how many more commits can be added to the lookahead buffer.
+ */
+int graph_get_lookahead_room(struct git_graph *graph);
+
+/*
+ * Push a commit into the lookahead buffer. Must only be called when
+ * graph_get_lookahead_room() returns > 0.
+ */
+void graph_push_lookahead(struct git_graph *graph, struct commit *c);
+
 #endif /* GRAPH_H */
index 288935943f4fbab918d968abee7debfcb3a0569c..258c3cf782894bbc7fdfeb90d51c5896872baa10 100644 (file)
@@ -4715,10 +4715,24 @@ struct commit *get_revision(struct rev_info *revs)
                return c;
        }
 
-       c = next_commit_to_show(revs);
+       if (revs->graph) {
+               c = graph_pop_lookahead(revs->graph);
+               if (!c)
+                       c = next_commit_to_show(revs);
+       } else {
+               c = next_commit_to_show(revs);
+       }
 
-       if (c && revs->graph)
+       if (c && revs->graph) {
+               while (graph_get_lookahead_room(revs->graph)) {
+                       struct commit *next = next_commit_to_show(revs);
+                       if (!next)
+                               break;
+                       graph_push_lookahead(revs->graph, next);
+               }
                graph_update(revs->graph, c);
+       }
+
        if (!c) {
                free_saved_parents(revs);
                commit_list_free(revs->previous_parents);