ref-filter: allow merged and no-merged filters
Enable ref-filter to process multiple merged and no-merged filters, and extend functionality to git branch, git tag and git for-each-ref. This provides an easy way to check for branches that are "graduation candidates:" $ git branch --no-merged master --merged next If passed more than one merged (or more than one no-merged) filter, refs must be reachable from any one of the merged commits, and reachable from none of the no-merged commits. Signed-off-by: Aaron Lipman <alipman88@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
committed by
Junio C Hamano
parent
415af72b17
commit
21bf933928
64
ref-filter.c
64
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,20 @@ void ref_array_clear(struct ref_array *array)
|
||||
}
|
||||
}
|
||||
|
||||
static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
|
||||
static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata, int reachable)
|
||||
{
|
||||
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 *rl;
|
||||
|
||||
struct commit_list *check_reachable_list = reachable ?
|
||||
ref_cbdata->filter->reachable_from :
|
||||
ref_cbdata->filter->unreachable_from;
|
||||
|
||||
if (!check_reachable_list)
|
||||
return;
|
||||
|
||||
repo_init_revisions(the_repository, &revs, NULL);
|
||||
|
||||
@ -2247,8 +2254,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 (rl = check_reachable_list; rl; rl = rl->next) {
|
||||
struct commit *merge_commit = rl->item;
|
||||
merge_commit->object.flags |= UNINTERESTING;
|
||||
add_pending_object(&revs, &merge_commit->object, "");
|
||||
}
|
||||
|
||||
revs.limited = 1;
|
||||
if (prepare_revision_walk(&revs))
|
||||
@ -2263,14 +2273,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 == reachable)
|
||||
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_list) {
|
||||
struct commit *merge_commit = pop_commit(&check_reachable_list);
|
||||
clear_commit_marks(merge_commit, ALL_REV_FLAGS);
|
||||
}
|
||||
|
||||
free(to_clear);
|
||||
}
|
||||
|
||||
@ -2322,8 +2337,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);
|
||||
do_merge_filter(&ref_cbdata, DO_MERGE_FILTER_REACHABLE);
|
||||
do_merge_filter(&ref_cbdata, DO_MERGE_FILTER_UNREACHABLE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2541,31 +2556,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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user