diff options
Diffstat (limited to 'ref-filter.c')
-rw-r--r-- | ref-filter.c | 65 |
1 files changed, 35 insertions, 30 deletions
diff --git a/ref-filter.c b/ref-filter.c index 110bcd741a..5550a0d34c 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -2167,9 +2167,9 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid, * obtain the commit using the 'oid' available and discard all * non-commits early. The actual filtering is done later. */ - if (filter->merge_commit || filter->with_commit || filter->no_commit || filter->verbose) { - commit = lookup_commit_reference_gently(the_repository, oid, - 1); + if (filter->reachable_from || filter->unreachable_from || + filter->with_commit || filter->no_commit || filter->verbose) { + commit = lookup_commit_reference_gently(the_repository, oid, 1); if (!commit) return 0; /* We perform the filtering for the '--contains' option... */ @@ -2231,13 +2231,19 @@ void ref_array_clear(struct ref_array *array) } } -static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata) +#define EXCLUDE_REACHED 0 +#define INCLUDE_REACHED 1 +static void reach_filter(struct ref_array *array, + struct commit_list *check_reachable, + int include_reached) { struct rev_info revs; int i, old_nr; - struct ref_filter *filter = ref_cbdata->filter; - struct ref_array *array = ref_cbdata->array; struct commit **to_clear = xcalloc(sizeof(struct commit *), array->nr); + struct commit_list *cr; + + if (!check_reachable) + return; repo_init_revisions(the_repository, &revs, NULL); @@ -2247,8 +2253,11 @@ static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata) to_clear[i] = item->commit; } - filter->merge_commit->object.flags |= UNINTERESTING; - add_pending_object(&revs, &filter->merge_commit->object, ""); + for (cr = check_reachable; cr; cr = cr->next) { + struct commit *merge_commit = cr->item; + merge_commit->object.flags |= UNINTERESTING; + add_pending_object(&revs, &merge_commit->object, ""); + } revs.limited = 1; if (prepare_revision_walk(&revs)) @@ -2263,14 +2272,19 @@ static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata) int is_merged = !!(commit->object.flags & UNINTERESTING); - if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE)) + if (is_merged == include_reached) array->items[array->nr++] = array->items[i]; else free_array_item(item); } clear_commit_marks_many(old_nr, to_clear, ALL_REV_FLAGS); - clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS); + + while (check_reachable) { + struct commit *merge_commit = pop_commit(&check_reachable); + clear_commit_marks(merge_commit, ALL_REV_FLAGS); + } + free(to_clear); } @@ -2322,8 +2336,8 @@ int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int clear_contains_cache(&ref_cbdata.no_contains_cache); /* Filters that need revision walking */ - if (filter->merge_commit) - do_merge_filter(&ref_cbdata); + reach_filter(array, filter->reachable_from, INCLUDE_REACHED); + reach_filter(array, filter->unreachable_from, EXCLUDE_REACHED); return ret; } @@ -2541,31 +2555,22 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) { struct ref_filter *rf = opt->value; struct object_id oid; - int no_merged = starts_with(opt->long_name, "no"); + struct commit *merge_commit; BUG_ON_OPT_NEG(unset); - if (rf->merge) { - if (no_merged) { - return error(_("option `%s' is incompatible with --merged"), - opt->long_name); - } else { - return error(_("option `%s' is incompatible with --no-merged"), - opt->long_name); - } - } - - rf->merge = no_merged - ? REF_FILTER_MERGED_OMIT - : REF_FILTER_MERGED_INCLUDE; - if (get_oid(arg, &oid)) die(_("malformed object name %s"), arg); - rf->merge_commit = lookup_commit_reference_gently(the_repository, - &oid, 0); - if (!rf->merge_commit) + merge_commit = lookup_commit_reference_gently(the_repository, &oid, 0); + + if (!merge_commit) return error(_("option `%s' must point to a commit"), opt->long_name); + if (starts_with(opt->long_name, "no")) + commit_list_insert(merge_commit, &rf->unreachable_from); + else + commit_list_insert(merge_commit, &rf->reachable_from); + return 0; } |