@@ -82,6 +82,8 @@ static void graph_show_line_prefix(const struct diff_options *diffopt)
8282static const char * * column_colors ;
8383static unsigned short column_colors_max ;
8484
85+ static unsigned int max_lanes = 15 ;
86+
8587static 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+
320327static 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
10771145static 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