@@ -1105,7 +1105,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
11051105 struct commit_list * * list , struct prio_queue * queue )
11061106{
11071107 struct commit_list * parent = commit -> parents ;
1108- unsigned left_flag ;
1108+ unsigned pass_flags ;
11091109
11101110 if (commit -> object .flags & ADDED )
11111111 return 0 ;
@@ -1160,7 +1160,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
11601160 if (revs -> no_walk )
11611161 return 0 ;
11621162
1163- left_flag = (commit -> object .flags & SYMMETRIC_LEFT );
1163+ pass_flags = (commit -> object .flags & ( SYMMETRIC_LEFT | ANCESTRY_PATH ) );
11641164
11651165 for (parent = commit -> parents ; parent ; parent = parent -> next ) {
11661166 struct commit * p = parent -> item ;
@@ -1181,7 +1181,7 @@ static int process_parents(struct rev_info *revs, struct commit *commit,
11811181 if (!* slot )
11821182 * slot = * revision_sources_at (revs -> sources , commit );
11831183 }
1184- p -> object .flags |= left_flag ;
1184+ p -> object .flags |= pass_flags ;
11851185 if (!(p -> object .flags & SEEN )) {
11861186 p -> object .flags |= (SEEN | NOT_USER_GIVEN );
11871187 if (list )
@@ -1304,13 +1304,24 @@ static int still_interesting(struct commit_list *src, timestamp_t date, int slop
13041304}
13051305
13061306/*
1307- * "rev-list --ancestry-path A..B" computes commits that are ancestors
1308- * of B but not ancestors of A but further limits the result to those
1309- * that are descendants of A. This takes the list of bottom commits and
1310- * the result of "A..B" without --ancestry-path, and limits the latter
1311- * further to the ones that can reach one of the commits in "bottom".
1307+ * "rev-list --ancestry-path=C_0 [--ancestry-path=C_1 ...] A..B"
1308+ * computes commits that are ancestors of B but not ancestors of A but
1309+ * further limits the result to those that have any of C in their
1310+ * ancestry path (i.e. are either ancestors of any of C, descendants
1311+ * of any of C, or are any of C). If --ancestry-path is specified with
1312+ * no commit, we use all bottom commits for C.
1313+ *
1314+ * Before this function is called, ancestors of C will have already
1315+ * been marked with ANCESTRY_PATH previously.
1316+ *
1317+ * This takes the list of bottom commits and the result of "A..B"
1318+ * without --ancestry-path, and limits the latter further to the ones
1319+ * that have any of C in their ancestry path. Since the ancestors of C
1320+ * have already been marked (a prerequisite of this function), we just
1321+ * need to mark the descendants, then exclude any commit that does not
1322+ * have any of these marks.
13121323 */
1313- static void limit_to_ancestry (struct commit_list * bottom , struct commit_list * list )
1324+ static void limit_to_ancestry (struct commit_list * bottoms , struct commit_list * list )
13141325{
13151326 struct commit_list * p ;
13161327 struct commit_list * rlist = NULL ;
@@ -1323,7 +1334,7 @@ static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *li
13231334 for (p = list ; p ; p = p -> next )
13241335 commit_list_insert (p -> item , & rlist );
13251336
1326- for (p = bottom ; p ; p = p -> next )
1337+ for (p = bottoms ; p ; p = p -> next )
13271338 p -> item -> object .flags |= TMP_MARK ;
13281339
13291340 /*
@@ -1356,38 +1367,39 @@ static void limit_to_ancestry(struct commit_list *bottom, struct commit_list *li
13561367 */
13571368
13581369 /*
1359- * The ones that are not marked with TMP_MARK are uninteresting
1370+ * The ones that are not marked with either TMP_MARK or
1371+ * ANCESTRY_PATH are uninteresting
13601372 */
13611373 for (p = list ; p ; p = p -> next ) {
13621374 struct commit * c = p -> item ;
1363- if (c -> object .flags & TMP_MARK )
1375+ if (c -> object .flags & ( TMP_MARK | ANCESTRY_PATH ) )
13641376 continue ;
13651377 c -> object .flags |= UNINTERESTING ;
13661378 }
13671379
1368- /* We are done with the TMP_MARK */
1380+ /* We are done with TMP_MARK and ANCESTRY_PATH */
13691381 for (p = list ; p ; p = p -> next )
1370- p -> item -> object .flags &= ~TMP_MARK ;
1371- for (p = bottom ; p ; p = p -> next )
1372- p -> item -> object .flags &= ~TMP_MARK ;
1382+ p -> item -> object .flags &= ~( TMP_MARK | ANCESTRY_PATH ) ;
1383+ for (p = bottoms ; p ; p = p -> next )
1384+ p -> item -> object .flags &= ~( TMP_MARK | ANCESTRY_PATH ) ;
13731385 free_commit_list (rlist );
13741386}
13751387
13761388/*
1377- * Before walking the history, keep the set of "negative" refs the
1378- * caller has asked to exclude.
1389+ * Before walking the history, add the set of "negative" refs the
1390+ * caller has asked to exclude to the bottom list .
13791391 *
13801392 * This is used to compute "rev-list --ancestry-path A..B", as we need
13811393 * to filter the result of "A..B" further to the ones that can actually
13821394 * reach A.
13831395 */
1384- static struct commit_list * collect_bottom_commits (struct commit_list * list )
1396+ static void collect_bottom_commits (struct commit_list * list ,
1397+ struct commit_list * * bottom )
13851398{
1386- struct commit_list * elem , * bottom = NULL ;
1399+ struct commit_list * elem ;
13871400 for (elem = list ; elem ; elem = elem -> next )
13881401 if (elem -> item -> object .flags & BOTTOM )
1389- commit_list_insert (elem -> item , & bottom );
1390- return bottom ;
1402+ commit_list_insert (elem -> item , bottom );
13911403}
13921404
13931405/* Assumes either left_only or right_only is set */
@@ -1414,12 +1426,12 @@ static int limit_list(struct rev_info *revs)
14141426 struct commit_list * original_list = revs -> commits ;
14151427 struct commit_list * newlist = NULL ;
14161428 struct commit_list * * p = & newlist ;
1417- struct commit_list * bottom = NULL ;
14181429 struct commit * interesting_cache = NULL ;
14191430
1420- if (revs -> ancestry_path ) {
1421- bottom = collect_bottom_commits (original_list );
1422- if (!bottom )
1431+ if (revs -> ancestry_path_implicit_bottoms ) {
1432+ collect_bottom_commits (original_list ,
1433+ & revs -> ancestry_path_bottoms );
1434+ if (!revs -> ancestry_path_bottoms )
14231435 die ("--ancestry-path given but there are no bottom commits" );
14241436 }
14251437
@@ -1464,9 +1476,8 @@ static int limit_list(struct rev_info *revs)
14641476 if (revs -> left_only || revs -> right_only )
14651477 limit_left_right (newlist , revs );
14661478
1467- if (bottom )
1468- limit_to_ancestry (bottom , newlist );
1469- free_commit_list (bottom );
1479+ if (revs -> ancestry_path )
1480+ limit_to_ancestry (revs -> ancestry_path_bottoms , newlist );
14701481
14711482 /*
14721483 * Check if any commits have become TREESAME by some of their parents
@@ -2213,7 +2224,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
22132224 const struct setup_revision_opt * opt )
22142225{
22152226 const char * arg = argv [0 ];
2216- const char * optarg ;
2227+ const char * optarg = NULL ;
22172228 int argcount ;
22182229 const unsigned hexsz = the_hash_algo -> hexsz ;
22192230
@@ -2284,6 +2295,23 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
22842295 revs -> ancestry_path = 1 ;
22852296 revs -> simplify_history = 0 ;
22862297 revs -> limited = 1 ;
2298+ revs -> ancestry_path_implicit_bottoms = 1 ;
2299+ } else if (skip_prefix (arg , "--ancestry-path=" , & optarg )) {
2300+ struct commit * c ;
2301+ struct object_id oid ;
2302+ const char * msg = _ ("could not get commit for ancestry-path argument %s" );
2303+
2304+ revs -> ancestry_path = 1 ;
2305+ revs -> simplify_history = 0 ;
2306+ revs -> limited = 1 ;
2307+
2308+ if (repo_get_oid_committish (revs -> repo , optarg , & oid ))
2309+ return error (msg , optarg );
2310+ get_reference (revs , optarg , & oid , ANCESTRY_PATH );
2311+ c = lookup_commit_reference (revs -> repo , & oid );
2312+ if (!c )
2313+ return error (msg , optarg );
2314+ commit_list_insert (c , & revs -> ancestry_path_bottoms );
22872315 } else if (!strcmp (arg , "-g" ) || !strcmp (arg , "--walk-reflogs" )) {
22882316 init_reflog_walk (& revs -> reflog_info );
22892317 } else if (!strcmp (arg , "--default" )) {
@@ -2993,6 +3021,7 @@ static void release_revisions_topo_walk_info(struct topo_walk_info *info);
29933021void release_revisions (struct rev_info * revs )
29943022{
29953023 free_commit_list (revs -> commits );
3024+ free_commit_list (revs -> ancestry_path_bottoms );
29963025 object_array_clear (& revs -> pending );
29973026 object_array_clear (& revs -> boundary_commits );
29983027 release_revisions_cmdline (& revs -> cmdline );
0 commit comments