зеркало из https://github.com/microsoft/git.git
ref-filter: implement '--merged' and '--no-merged' options
In 'branch -l' we have '--merged' option which only lists refs (branches) merged into the named commit and '--no-merged' option which only lists refs (branches) not merged into the named commit. Implement these two options in ref-filter.{c,h} so that other commands can benefit from this. Based-on-patch-by: Jeff King <peff@peff.net> Mentored-by: Christian Couder <christian.couder@gmail.com> Mentored-by: Matthieu Moy <matthieu.moy@grenoble-inp.fr> Signed-off-by: Karthik Nayak <karthik.188@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
5afcb90560
Коммит
35257aa012
|
@ -635,6 +635,10 @@ static int print_ref_list(int kinds, int detached, int verbose, int abbrev, stru
|
||||||
cb.pattern = pattern;
|
cb.pattern = pattern;
|
||||||
cb.ret = 0;
|
cb.ret = 0;
|
||||||
for_each_rawref(append_ref, &cb);
|
for_each_rawref(append_ref, &cb);
|
||||||
|
/*
|
||||||
|
* The following implementation is currently duplicated in ref-filter. It
|
||||||
|
* will eventually be removed when we port branch.c to use ref-filter APIs.
|
||||||
|
*/
|
||||||
if (merge_filter != NO_FILTER) {
|
if (merge_filter != NO_FILTER) {
|
||||||
struct commit *filter;
|
struct commit *filter;
|
||||||
filter = lookup_commit_reference_gently(merge_filter_ref, 0);
|
filter = lookup_commit_reference_gently(merge_filter_ref, 0);
|
||||||
|
|
73
ref-filter.c
73
ref-filter.c
|
@ -9,6 +9,7 @@
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "quote.h"
|
#include "quote.h"
|
||||||
#include "ref-filter.h"
|
#include "ref-filter.h"
|
||||||
|
#include "revision.h"
|
||||||
|
|
||||||
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
|
typedef enum { FIELD_STR, FIELD_ULONG, FIELD_TIME } cmp_type;
|
||||||
|
|
||||||
|
@ -898,6 +899,7 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
|
||||||
struct ref_filter_cbdata *ref_cbdata = cb_data;
|
struct ref_filter_cbdata *ref_cbdata = cb_data;
|
||||||
struct ref_filter *filter = ref_cbdata->filter;
|
struct ref_filter *filter = ref_cbdata->filter;
|
||||||
struct ref_array_item *ref;
|
struct ref_array_item *ref;
|
||||||
|
struct commit *commit = NULL;
|
||||||
|
|
||||||
if (flag & REF_BAD_NAME) {
|
if (flag & REF_BAD_NAME) {
|
||||||
warning("ignoring ref with broken name %s", refname);
|
warning("ignoring ref with broken name %s", refname);
|
||||||
|
@ -910,12 +912,24 @@ static int ref_filter_handler(const char *refname, const struct object_id *oid,
|
||||||
if (filter->points_at.nr && !match_points_at(&filter->points_at, oid->hash, refname))
|
if (filter->points_at.nr && !match_points_at(&filter->points_at, oid->hash, refname))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A merge filter is applied on refs pointing to commits. Hence
|
||||||
|
* obtain the commit using the 'oid' available and discard all
|
||||||
|
* non-commits early. The actual filtering is done later.
|
||||||
|
*/
|
||||||
|
if (filter->merge_commit) {
|
||||||
|
commit = lookup_commit_reference_gently(oid->hash, 1);
|
||||||
|
if (!commit)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not open the object yet; sort may only need refname
|
* We do not open the object yet; sort may only need refname
|
||||||
* to do its job and the resulting list may yet to be pruned
|
* to do its job and the resulting list may yet to be pruned
|
||||||
* by maxcount logic.
|
* by maxcount logic.
|
||||||
*/
|
*/
|
||||||
ref = new_ref_array_item(refname, oid->hash, flag);
|
ref = new_ref_array_item(refname, oid->hash, flag);
|
||||||
|
ref->commit = commit;
|
||||||
|
|
||||||
REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);
|
REALLOC_ARRAY(ref_cbdata->array->items, ref_cbdata->array->nr + 1);
|
||||||
ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;
|
ref_cbdata->array->items[ref_cbdata->array->nr++] = ref;
|
||||||
|
@ -941,6 +955,50 @@ void ref_array_clear(struct ref_array *array)
|
||||||
array->nr = array->alloc = 0;
|
array->nr = array->alloc = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
init_revisions(&revs, NULL);
|
||||||
|
|
||||||
|
for (i = 0; i < array->nr; i++) {
|
||||||
|
struct ref_array_item *item = array->items[i];
|
||||||
|
add_pending_object(&revs, &item->commit->object, item->refname);
|
||||||
|
to_clear[i] = item->commit;
|
||||||
|
}
|
||||||
|
|
||||||
|
filter->merge_commit->object.flags |= UNINTERESTING;
|
||||||
|
add_pending_object(&revs, &filter->merge_commit->object, "");
|
||||||
|
|
||||||
|
revs.limited = 1;
|
||||||
|
if (prepare_revision_walk(&revs))
|
||||||
|
die(_("revision walk setup failed"));
|
||||||
|
|
||||||
|
old_nr = array->nr;
|
||||||
|
array->nr = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < old_nr; i++) {
|
||||||
|
struct ref_array_item *item = array->items[i];
|
||||||
|
struct commit *commit = item->commit;
|
||||||
|
|
||||||
|
int is_merged = !!(commit->object.flags & UNINTERESTING);
|
||||||
|
|
||||||
|
if (is_merged == (filter->merge == REF_FILTER_MERGED_INCLUDE))
|
||||||
|
array->items[array->nr++] = array->items[i];
|
||||||
|
else
|
||||||
|
free_array_item(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < old_nr; i++)
|
||||||
|
clear_commit_marks(to_clear[i], ALL_REV_FLAGS);
|
||||||
|
clear_commit_marks(filter->merge_commit, ALL_REV_FLAGS);
|
||||||
|
free(to_clear);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* API for filtering a set of refs. Based on the type of refs the user
|
* API for filtering a set of refs. Based on the type of refs the user
|
||||||
* has requested, we iterate through those refs and apply filters
|
* has requested, we iterate through those refs and apply filters
|
||||||
|
@ -950,17 +1008,24 @@ void ref_array_clear(struct ref_array *array)
|
||||||
int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
|
int filter_refs(struct ref_array *array, struct ref_filter *filter, unsigned int type)
|
||||||
{
|
{
|
||||||
struct ref_filter_cbdata ref_cbdata;
|
struct ref_filter_cbdata ref_cbdata;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
ref_cbdata.array = array;
|
ref_cbdata.array = array;
|
||||||
ref_cbdata.filter = filter;
|
ref_cbdata.filter = filter;
|
||||||
|
|
||||||
|
/* Simple per-ref filtering */
|
||||||
if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))
|
if (type & (FILTER_REFS_ALL | FILTER_REFS_INCLUDE_BROKEN))
|
||||||
return for_each_rawref(ref_filter_handler, &ref_cbdata);
|
ret = for_each_rawref(ref_filter_handler, &ref_cbdata);
|
||||||
else if (type & FILTER_REFS_ALL)
|
else if (type & FILTER_REFS_ALL)
|
||||||
return for_each_ref(ref_filter_handler, &ref_cbdata);
|
ret = for_each_ref(ref_filter_handler, &ref_cbdata);
|
||||||
else
|
else if (type)
|
||||||
die("filter_refs: invalid type");
|
die("filter_refs: invalid type");
|
||||||
return 0;
|
|
||||||
|
/* Filters that need revision walking */
|
||||||
|
if (filter->merge_commit)
|
||||||
|
do_merge_filter(&ref_cbdata);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
|
static int cmp_ref_sorting(struct ref_sorting *s, struct ref_array_item *a, struct ref_array_item *b)
|
||||||
|
|
|
@ -31,6 +31,7 @@ struct ref_array_item {
|
||||||
unsigned char objectname[20];
|
unsigned char objectname[20];
|
||||||
int flag;
|
int flag;
|
||||||
const char *symref;
|
const char *symref;
|
||||||
|
struct commit *commit;
|
||||||
struct atom_value *value;
|
struct atom_value *value;
|
||||||
char refname[FLEX_ARRAY];
|
char refname[FLEX_ARRAY];
|
||||||
};
|
};
|
||||||
|
@ -43,6 +44,13 @@ struct ref_array {
|
||||||
struct ref_filter {
|
struct ref_filter {
|
||||||
const char **name_patterns;
|
const char **name_patterns;
|
||||||
struct sha1_array points_at;
|
struct sha1_array points_at;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
REF_FILTER_MERGED_NONE = 0,
|
||||||
|
REF_FILTER_MERGED_INCLUDE,
|
||||||
|
REF_FILTER_MERGED_OMIT
|
||||||
|
} merge;
|
||||||
|
struct commit *merge_commit;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ref_filter_cbdata {
|
struct ref_filter_cbdata {
|
||||||
|
|
Загрузка…
Ссылка в новой задаче