1105
struct commit_list **list, struct prio_queue *queue)
1106
{
1107
struct commit_list *parent = commit->parents;
1108
- unsigned left_flag;
1108
+ unsigned pass_flags;
1109
1110
if (commit->object.flags & ADDED)
1111
return 0;
1160
if (revs->no_walk)
1161
return 0;
1162
1163
- left_flag = (commit->object.flags & SYMMETRIC_LEFT);
1163
+ pass_flags = (commit->object.flags & (SYMMETRIC_LEFT | ANCESTRY_PATH));
1164
1165
for (parent = commit->parents; parent; parent = parent->next) {
1166
struct commit *p = parent->item;
1181
if (!*slot)
1182
*slot = *revision_sources_at(revs->sources, commit);
1183
}
1184
- p->object.flags |= left_flag;
1184
+ p->object.flags |= pass_flags;
1185
if (!(p->object.flags & SEEN)) {
1186
p->object.flags |= (SEEN | NOT_USER_GIVEN);
1187
if (list)
1304
}
1305
1306
/*
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.
1323
*/
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)
1325
{
1326
struct commit_list *p;
1327
struct commit_list *rlist = NULL;
1334
for (p = list; p; p = p->next)
1335
commit_list_insert(p->item, &rlist);
1336
1326
- for (p = bottom; p; p = p->next)
1337
+ for (p = bottoms; p; p = p->next)
1338
p->item->object.flags |= TMP_MARK;
1339
1340
/*
1367
*/
1368
1369
/*
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
1372
*/
1373
for (p = list; p; p = p->next) {
1374
struct commit *c = p->item;
1363
- if (c->object.flags & TMP_MARK)
1375
+ if (c->object.flags & (TMP_MARK | ANCESTRY_PATH))
1376
continue;
1377
c->object.flags |= UNINTERESTING;
1378
}
1379
1368
- /* We are done with the TMP_MARK */
1380
+ /* We are done with TMP_MARK and ANCESTRY_PATH */
1381
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);
1385
free_commit_list(rlist);
1386
}
1387
1388
/*
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.
1391
*
1392
* This is used to compute "rev-list --ancestry-path A..B", as we need
1393
* to filter the result of "A..B" further to the ones that can actually
1394
* reach A.
1395
*/
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)
1398
{
1386
- struct commit_list *elem, *bottom = NULL;
1399
+ struct commit_list *elem;
1400
for (elem = list; elem; elem = elem->next)
1401
if (elem->item->object.flags & BOTTOM)
1389
- commit_list_insert(elem->item, &bottom);
1390
- return bottom;
1402
+ commit_list_insert(elem->item, bottom);
1403
}
1404
1405
/* Assumes either left_only or right_only is set */
1426
struct commit_list *original_list = revs->commits;
1427
struct commit_list *newlist = NULL;
1428
struct commit_list **p = &newlist;
1417
- struct commit_list *bottom = NULL;
1429
struct commit *interesting_cache = NULL;
1430
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)
1435
die("--ancestry-path given but there are no bottom commits");
1436
}
1437
1476
if (revs->left_only || revs->right_only)
1477
limit_left_right(newlist, revs);
1478
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);
1481
1482
/*
1483
* Check if any commits have become TREESAME by some of their parents
2224
const struct setup_revision_opt* opt)
2225
{
2226
const char *arg = argv[0];
2216
- const char *optarg;
2227
+ const char *optarg = NULL;
2228
int argcount;
2229
const unsigned hexsz = the_hash_algo->hexsz;
2230
2295
revs->ancestry_path = 1;
2296
revs->simplify_history = 0;
2297
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);
2315
} else if (!strcmp(arg, "-g") || !strcmp(arg, "--walk-reflogs")) {
2316
init_reflog_walk(&revs->reflog_info);
2317
} else if (!strcmp(arg, "--default")) {
3021
void release_revisions(struct rev_info *revs)
3022
{
3023
free_commit_list(revs->commits);
3024
+ free_commit_list(revs->ancestry_path_bottoms);
3025
object_array_clear(&revs->pending);
3026
object_array_clear(&revs->boundary_commits);
3027
release_revisions_cmdline(&revs->cmdline);