Skip to content

Commit b2faaae

Browse files
pabloosabaterrgitster
authored andcommitted
graph: limit the graph width to a hard-coded max
Repositories that have many active branches at the same time produce wide graphs. A lane consists of two columns, the edge and the padding (or another edge), each branch takes a lane in the graph and there is no way to limit how many can be shown. Limit the graph engine to draw at most 15 lanes. Lanes over the limit are not rendered. On the commit line, if the commit lives on a visible lane, show the normal commit mark and stop rendering. If the commit lives on the first hidden lane, show the "*" commit mark so it is known that this commit lives in the first hidden lane. Commits on deeper lanes aren't rendered, but the commit subject will always remain. For merges, the post-merge lane is only needed when the commit or the first parent lives on a visible lane (to draw the connection between them), when both are on hidden lanes, post-merge carries no useful information, skip it and go to collapsing or padding state. Also fix a pre-existing indentation issue. The hard-coded limit will be replaced by a user-facing option on a subsequent commit. Signed-off-by: Pablo Sabater <pabloosabaterr@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 6e8d538 commit b2faaae

File tree

1 file changed

+136
-25
lines changed

1 file changed

+136
-25
lines changed

graph.c

Lines changed: 136 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ static void graph_show_line_prefix(const struct diff_options *diffopt)
8282
static const char **column_colors;
8383
static unsigned short column_colors_max;
8484

85+
static unsigned int max_lanes = 15;
86+
8587
static void parse_graph_colors_config(struct strvec *colors, const char *string)
8688
{
8789
const char *end, *start;
@@ -317,6 +319,11 @@ struct git_graph {
317319
struct strbuf prefix_buf;
318320
};
319321

322+
static inline int graph_needs_truncation(int lane)
323+
{
324+
return lane >= max_lanes;
325+
}
326+
320327
static const char *diff_output_prefix_callback(struct diff_options *opt, void *data)
321328
{
322329
struct git_graph *graph = data;
@@ -607,7 +614,7 @@ static void graph_update_columns(struct git_graph *graph)
607614
{
608615
struct commit_list *parent;
609616
int max_new_columns;
610-
int i, seen_this, is_commit_in_columns;
617+
int i, seen_this, is_commit_in_columns, max;
611618

612619
/*
613620
* Swap graph->columns with graph->new_columns
@@ -696,6 +703,14 @@ static void graph_update_columns(struct git_graph *graph)
696703
}
697704
}
698705

706+
/*
707+
* Cap to the hard-coded limit.
708+
* Allow commits from merges to align to the merged lane.
709+
*/
710+
max = max_lanes * 2 + 2;
711+
if (graph->width > max)
712+
graph->width = max;
713+
699714
/*
700715
* Shrink mapping_size to be the minimum necessary
701716
*/
@@ -846,6 +861,8 @@ static void graph_output_padding_line(struct git_graph *graph,
846861
* Output a padding row, that leaves all branch lines unchanged
847862
*/
848863
for (i = 0; i < graph->num_new_columns; i++) {
864+
if (graph_needs_truncation(i))
865+
break;
849866
graph_line_write_column(line, &graph->new_columns[i], '|');
850867
graph_line_addch(line, ' ');
851868
}
@@ -903,6 +920,8 @@ static void graph_output_pre_commit_line(struct git_graph *graph,
903920
seen_this = 1;
904921
graph_line_write_column(line, col, '|');
905922
graph_line_addchars(line, ' ', graph->expansion_row);
923+
} else if (seen_this && graph_needs_truncation(i)) {
924+
break;
906925
} else if (seen_this && (graph->expansion_row == 0)) {
907926
/*
908927
* This is the first line of the pre-commit output.
@@ -994,6 +1013,14 @@ static void graph_draw_octopus_merge(struct git_graph *graph, struct graph_line
9941013
col = &graph->new_columns[j];
9951014

9961015
graph_line_write_column(line, col, '-');
1016+
1017+
/*
1018+
* Commit is at commit_index, each iteration move one lane to
1019+
* the right from the commit.
1020+
*/
1021+
if (graph_needs_truncation(graph->commit_index + 1 + i))
1022+
break;
1023+
9971024
graph_line_write_column(line, col, (i == dashed_parents - 1) ? '.' : '-');
9981025
}
9991026

@@ -1028,8 +1055,16 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
10281055
seen_this = 1;
10291056
graph_output_commit_char(graph, line);
10301057

1058+
if (graph_needs_truncation(i)) {
1059+
graph_line_addch(line, ' ');
1060+
break;
1061+
}
1062+
10311063
if (graph->num_parents > 2)
10321064
graph_draw_octopus_merge(graph, line);
1065+
} else if (graph_needs_truncation(i)) {
1066+
seen_this = 1;
1067+
break;
10331068
} else if (seen_this && (graph->edges_added > 1)) {
10341069
graph_line_write_column(line, col, '\\');
10351070
} else if (seen_this && (graph->edges_added == 1)) {
@@ -1065,13 +1100,46 @@ static void graph_output_commit_line(struct git_graph *graph, struct graph_line
10651100

10661101
/*
10671102
* Update graph->state
1103+
*
1104+
* If the commit is a merge and the first parent is in a visible lane,
1105+
* then the GRAPH_POST_MERGE is needed to draw the merge lane.
1106+
*
1107+
* If the commit is over the truncation limit, but the first parent is on
1108+
* a visible lane, then we still need the merge lane but truncated.
1109+
*
1110+
* If both commit and first parent are over the truncation limit, then
1111+
* there's no need to draw the merge lane because it would work as a
1112+
* padding lane.
10681113
*/
1069-
if (graph->num_parents > 1)
1070-
graph_update_state(graph, GRAPH_POST_MERGE);
1071-
else if (graph_is_mapping_correct(graph))
1114+
if (graph->num_parents > 1) {
1115+
if (!graph_needs_truncation(graph->commit_index)) {
1116+
graph_update_state(graph, GRAPH_POST_MERGE);
1117+
} else {
1118+
struct commit_list *p = first_interesting_parent(graph);
1119+
int lane;
1120+
1121+
/*
1122+
* graph->num_parents are found using first_interesting_parent
1123+
* and next_interesting_parent so it can't be a scenario
1124+
* where num_parents > 1 and there are no interesting parents
1125+
*/
1126+
if (!p)
1127+
BUG("num_parents > 1 but no interesting parent");
1128+
1129+
lane = graph_find_new_column_by_commit(graph, p->item);
1130+
1131+
if (!graph_needs_truncation(lane))
1132+
graph_update_state(graph, GRAPH_POST_MERGE);
1133+
else if (graph_is_mapping_correct(graph))
1134+
graph_update_state(graph, GRAPH_PADDING);
1135+
else
1136+
graph_update_state(graph, GRAPH_COLLAPSING);
1137+
}
1138+
} else if (graph_is_mapping_correct(graph)) {
10721139
graph_update_state(graph, GRAPH_PADDING);
1073-
else
1140+
} else {
10741141
graph_update_state(graph, GRAPH_COLLAPSING);
1142+
}
10751143
}
10761144

10771145
static const char merge_chars[] = {'/', '|', '\\'};
@@ -1109,6 +1177,7 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
11091177
int par_column;
11101178
int idx = graph->merge_layout;
11111179
char c;
1180+
int truncated = 0;
11121181
seen_this = 1;
11131182

11141183
for (j = 0; j < graph->num_parents; j++) {
@@ -1117,23 +1186,53 @@ static void graph_output_post_merge_line(struct git_graph *graph, struct graph_l
11171186

11181187
c = merge_chars[idx];
11191188
graph_line_write_column(line, &graph->new_columns[par_column], c);
1189+
1190+
/*
1191+
* j counts parents, it needs to be halved to be
1192+
* comparable with i. Don't truncate if there are
1193+
* no more lanes to print (end of the lane)
1194+
*/
1195+
if (graph_needs_truncation(j / 2 + i) &&
1196+
j / 2 + i <= graph->num_columns) {
1197+
if ((j + i * 2) % 2 != 0)
1198+
graph_line_addch(line, ' ');
1199+
truncated = 1;
1200+
break;
1201+
}
1202+
11201203
if (idx == 2) {
1121-
if (graph->edges_added > 0 || j < graph->num_parents - 1)
1204+
/*
1205+
* Check if the next lane needs truncation
1206+
* to avoid having the padding doubled
1207+
*/
1208+
if (graph_needs_truncation((j + 1) / 2 + i) &&
1209+
j < graph->num_parents - 1) {
1210+
truncated = 1;
1211+
break;
1212+
} else if (graph->edges_added > 0 || j < graph->num_parents - 1)
11221213
graph_line_addch(line, ' ');
11231214
} else {
11241215
idx++;
11251216
}
11261217
parents = next_interesting_parent(graph, parents);
11271218
}
1219+
if (truncated)
1220+
break;
11281221
if (graph->edges_added == 0)
11291222
graph_line_addch(line, ' ');
1130-
1223+
} else if (graph_needs_truncation(i)) {
1224+
break;
11311225
} else if (seen_this) {
11321226
if (graph->edges_added > 0)
11331227
graph_line_write_column(line, col, '\\');
11341228
else
11351229
graph_line_write_column(line, col, '|');
1136-
graph_line_addch(line, ' ');
1230+
/*
1231+
* If it's between two lanes and next would be truncated,
1232+
* don't add space padding.
1233+
*/
1234+
if (!graph_needs_truncation(i + 1))
1235+
graph_line_addch(line, ' ');
11371236
} else {
11381237
graph_line_write_column(line, col, '|');
11391238
if (graph->merge_layout != 0 || i != graph->commit_index - 1) {
@@ -1164,6 +1263,7 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct graph_l
11641263
short used_horizontal = 0;
11651264
int horizontal_edge = -1;
11661265
int horizontal_edge_target = -1;
1266+
int truncated = 0;
11671267

11681268
/*
11691269
* Swap the mapping and old_mapping arrays
@@ -1279,26 +1379,34 @@ static void graph_output_collapsing_line(struct git_graph *graph, struct graph_l
12791379
*/
12801380
for (i = 0; i < graph->mapping_size; i++) {
12811381
int target = graph->mapping[i];
1282-
if (target < 0)
1283-
graph_line_addch(line, ' ');
1284-
else if (target * 2 == i)
1285-
graph_line_write_column(line, &graph->new_columns[target], '|');
1286-
else if (target == horizontal_edge_target &&
1287-
i != horizontal_edge - 1) {
1288-
/*
1289-
* Set the mappings for all but the
1290-
* first segment to -1 so that they
1291-
* won't continue into the next line.
1292-
*/
1293-
if (i != (target * 2)+3)
1294-
graph->mapping[i] = -1;
1295-
used_horizontal = 1;
1296-
graph_line_write_column(line, &graph->new_columns[target], '_');
1382+
1383+
if (!truncated && graph_needs_truncation(i / 2)) {
1384+
truncated = 1;
1385+
}
1386+
1387+
if (target < 0) {
1388+
if (!truncated)
1389+
graph_line_addch(line, ' ');
1390+
} else if (target * 2 == i) {
1391+
if (!truncated)
1392+
graph_line_write_column(line, &graph->new_columns[target], '|');
1393+
} else if (target == horizontal_edge_target &&
1394+
i != horizontal_edge - 1) {
1395+
/*
1396+
* Set the mappings for all but the
1397+
* first segment to -1 so that they
1398+
* won't continue into the next line.
1399+
*/
1400+
if (i != (target * 2)+3)
1401+
graph->mapping[i] = -1;
1402+
used_horizontal = 1;
1403+
if (!truncated)
1404+
graph_line_write_column(line, &graph->new_columns[target], '_');
12971405
} else {
12981406
if (used_horizontal && i < horizontal_edge)
12991407
graph->mapping[i] = -1;
1300-
graph_line_write_column(line, &graph->new_columns[target], '/');
1301-
1408+
if (!truncated)
1409+
graph_line_write_column(line, &graph->new_columns[target], '/');
13021410
}
13031411
}
13041412

@@ -1372,6 +1480,9 @@ static void graph_padding_line(struct git_graph *graph, struct strbuf *sb)
13721480
for (i = 0; i < graph->num_columns; i++) {
13731481
struct column *col = &graph->columns[i];
13741482

1483+
if (graph_needs_truncation(i))
1484+
break;
1485+
13751486
graph_line_write_column(&line, col, '|');
13761487

13771488
if (col->commit == graph->commit && graph->num_parents > 2) {

0 commit comments

Comments
 (0)