graph: add a 2 commit buffer for lookahead
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>
Pablo Sabater committed
Jul 14, 2026 at 14:09 UTC
bf3c696b44eb82f90b25101e36cd79651d1480f8
3 files changed
+84
-2
graph.c
+51
@@ -315,6 +315,14 @@ struct git_graph {
315
* diff_output_prefix_callback().
316
*/
317
struct strbuf prefix_buf;
318
+
319
+ /*
320
+ * Lookahead buffer: up to 2 pre-fetched commits that will be shown.
321
+ * Populated by get_revision() so graph_peek_next_visible() can use
322
+ * actual walk results instead of peeking at rev_info internals.
323
+ */
324
+ struct commit *lookahead[2];
325
+ int lookahead_nr;
326
};
327
328
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)
396
graph->num_columns = 0;
397
graph->num_new_columns = 0;
398
graph->mapping_size = 0;
399
+ graph->lookahead[0] = NULL;
400
+ graph->lookahead[1] = NULL;
401
+ graph->lookahead_nr = 0;
402
/*
403
* Start the column color at the maximum value, since we'll
404
* 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)
467
*/
468
static int graph_is_interesting(struct git_graph *graph, struct commit *commit)
469
{
470
+ /*
471
+ * Commits in the lookahead buffer have been pre-fetched by
472
+ * get_revision() and will be shown in the future. They already have
473
+ * the SHOWN flag set when they were pre-fetched but the graph still
474
+ * needs to treat them as interesting parents.
475
+ */
476
+ for (int i = 0; i < graph->lookahead_nr; i++)
477
+ if (graph->lookahead[i] == commit)
478
+ return 1;
479
/*
480
* If revs->boundary is set, commits whose children have
481
* 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)
783
graph->expansion_row < graph_num_expansion_rows(graph);
784
}
785
786
+struct commit *graph_pop_lookahead(struct git_graph *graph)
787
+{
788
+ struct commit *c;
789
+
790
+ if (!graph->lookahead_nr)
791
+ return NULL;
792
+
793
+ c = graph->lookahead[0];
794
+ if (!c)
795
+ BUG("lookahead buffer has %d entries but the first one is NULL",
796
+ graph->lookahead_nr);
797
+
798
+ graph->lookahead[0] = graph->lookahead[1];
799
+ graph->lookahead[1] = NULL;
800
+ graph->lookahead_nr--;
801
+ return c;
802
+}
803
+
804
+int graph_get_lookahead_room(struct git_graph *graph)
805
+{
806
+ return (int)ARRAY_SIZE(graph->lookahead) - graph->lookahead_nr;
807
+}
808
+
809
+void graph_push_lookahead(struct git_graph *graph, struct commit *c)
810
+{
811
+ if (!graph_get_lookahead_room(graph))
812
+ BUG("pushing into lookahead buffer when it is already full");
813
+
814
+ graph->lookahead[graph->lookahead_nr++] = c;
815
+}
816
+
817
void graph_update(struct git_graph *graph, struct commit *commit)
818
{
819
struct commit_list *parent;
graph.h
+17
@@ -262,4 +262,21 @@ void graph_show_commit_msg(struct git_graph *graph,
262
FILE *file,
263
struct strbuf const *sb);
264
265
+/*
266
+ * Pop the first commit from the graph's lookahead buffer.
267
+ * Returns NULL if the buffer is empty.
268
+ */
269
+struct commit *graph_pop_lookahead(struct git_graph *graph);
270
+
271
+/*
272
+ * Returns how many more commits can be added to the lookahead buffer.
273
+ */
274
+int graph_get_lookahead_room(struct git_graph *graph);
275
+
276
+/*
277
+ * Push a commit into the lookahead buffer. Must only be called when
278
+ * graph_get_lookahead_room() returns > 0.
279
+ */
280
+void graph_push_lookahead(struct git_graph *graph, struct commit *c);
281
+
282
#endif /* GRAPH_H */
revision.c
+16
-2
@@ -4715,10 +4715,24 @@ struct commit *get_revision(struct rev_info *revs)
4715
return c;
4716
}
4717
4718
- c = next_commit_to_show(revs);
4718
+ if (revs->graph) {
4719
+ c = graph_pop_lookahead(revs->graph);
4720
+ if (!c)
4721
+ c = next_commit_to_show(revs);
4722
+ } else {
4723
+ c = next_commit_to_show(revs);
4724
+ }
4725
4720
- if (c && revs->graph)
4726
+ if (c && revs->graph) {
4727
+ while (graph_get_lookahead_room(revs->graph)) {
4728
+ struct commit *next = next_commit_to_show(revs);
4729
+ if (!next)
4730
+ break;
4731
+ graph_push_lookahead(revs->graph, next);
4732
+ }
4733
graph_update(revs->graph, c);
4734
+ }
4735
+
4736
if (!c) {
4737
free_saved_parents(revs);
4738
commit_list_free(revs->previous_parents);