diff options
Diffstat (limited to 'ref-filter.c')
-rw-r--r-- | ref-filter.c | 180 |
1 files changed, 133 insertions, 47 deletions
diff --git a/ref-filter.c b/ref-filter.c index f8203c6b05..4991cd4f7a 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1,9 +1,15 @@ -#include "builtin.h" -#include "cache.h" +#include "git-compat-util.h" +#include "alloc.h" +#include "environment.h" +#include "gettext.h" +#include "gpg-interface.h" +#include "hex.h" #include "parse-options.h" #include "refs.h" #include "wildmatch.h" +#include "object-name.h" #include "object-store.h" +#include "oid-array.h" #include "repository.h" #include "commit.h" #include "remote.h" @@ -13,8 +19,8 @@ #include "ref-filter.h" #include "revision.h" #include "utf8.h" -#include "git-compat-util.h" #include "version.h" +#include "versioncmp.h" #include "trailer.h" #include "wt-status.h" #include "commit-slab.h" @@ -158,6 +164,7 @@ enum atom_type { ATOM_THEN, ATOM_ELSE, ATOM_REST, + ATOM_AHEADBEHIND, }; /* @@ -282,7 +289,8 @@ static int refname_atom_parser_internal(struct refname_atom *atom, const char *a return 0; } -static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *atom, +static int remote_ref_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { struct string_list params = STRING_LIST_INIT_DUP; @@ -329,7 +337,8 @@ static int remote_ref_atom_parser(struct ref_format *format, struct used_atom *a return 0; } -static int objecttype_atom_parser(struct ref_format *format, struct used_atom *atom, +static int objecttype_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (arg) @@ -341,7 +350,8 @@ static int objecttype_atom_parser(struct ref_format *format, struct used_atom *a return 0; } -static int objectsize_atom_parser(struct ref_format *format, struct used_atom *atom, +static int objectsize_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (!arg) { @@ -361,7 +371,8 @@ static int objectsize_atom_parser(struct ref_format *format, struct used_atom *a return 0; } -static int deltabase_atom_parser(struct ref_format *format, struct used_atom *atom, +static int deltabase_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (arg) @@ -373,7 +384,8 @@ static int deltabase_atom_parser(struct ref_format *format, struct used_atom *at return 0; } -static int body_atom_parser(struct ref_format *format, struct used_atom *atom, +static int body_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (arg) @@ -382,7 +394,8 @@ static int body_atom_parser(struct ref_format *format, struct used_atom *atom, return 0; } -static int subject_atom_parser(struct ref_format *format, struct used_atom *atom, +static int subject_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (!arg) @@ -394,7 +407,8 @@ static int subject_atom_parser(struct ref_format *format, struct used_atom *atom return 0; } -static int trailers_atom_parser(struct ref_format *format, struct used_atom *atom, +static int trailers_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { atom->u.contents.trailer_opts.no_divider = 1; @@ -448,8 +462,9 @@ static int contents_atom_parser(struct ref_format *format, struct used_atom *ato return 0; } -static int raw_atom_parser(struct ref_format *format, struct used_atom *atom, - const char *arg, struct strbuf *err) +static int raw_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, + const char *arg, struct strbuf *err) { if (!arg) atom->u.raw_data.option = RAW_BARE; @@ -460,7 +475,8 @@ static int raw_atom_parser(struct ref_format *format, struct used_atom *atom, return 0; } -static int oid_atom_parser(struct ref_format *format, struct used_atom *atom, +static int oid_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (!arg) @@ -479,7 +495,8 @@ static int oid_atom_parser(struct ref_format *format, struct used_atom *atom, return 0; } -static int person_email_atom_parser(struct ref_format *format, struct used_atom *atom, +static int person_email_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (!arg) @@ -493,7 +510,8 @@ static int person_email_atom_parser(struct ref_format *format, struct used_atom return 0; } -static int refname_atom_parser(struct ref_format *format, struct used_atom *atom, +static int refname_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { return refname_atom_parser_internal(&atom->u.refname, arg, atom->name, err); @@ -510,7 +528,8 @@ static align_type parse_align_position(const char *s) return -1; } -static int align_atom_parser(struct ref_format *format, struct used_atom *atom, +static int align_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { struct align *align = &atom->u.align; @@ -562,7 +581,8 @@ static int align_atom_parser(struct ref_format *format, struct used_atom *atom, return 0; } -static int if_atom_parser(struct ref_format *format, struct used_atom *atom, +static int if_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (!arg) { @@ -577,16 +597,33 @@ static int if_atom_parser(struct ref_format *format, struct used_atom *atom, return 0; } -static int rest_atom_parser(struct ref_format *format, struct used_atom *atom, +static int rest_atom_parser(struct ref_format *format, + struct used_atom *atom UNUSED, const char *arg, struct strbuf *err) { if (arg) return err_no_arg(err, "rest"); - format->use_rest = 1; return 0; } -static int head_atom_parser(struct ref_format *format, struct used_atom *atom, +static int ahead_behind_atom_parser(struct ref_format *format, struct used_atom *atom, + const char *arg, struct strbuf *err) +{ + struct string_list_item *item; + + if (!arg) + return strbuf_addf_ret(err, -1, _("expected format: %%(ahead-behind:<committish>)")); + + item = string_list_append(&format->bases, arg); + item->util = lookup_commit_reference_by_name(arg); + if (!item->util) + die("failed to find '%s'", arg); + + return 0; +} + +static int head_atom_parser(struct ref_format *format UNUSED, + struct used_atom *atom, const char *arg, struct strbuf *err) { if (arg) @@ -645,6 +682,7 @@ static struct { [ATOM_THEN] = { "then", SOURCE_NONE }, [ATOM_ELSE] = { "else", SOURCE_NONE }, [ATOM_REST] = { "rest", SOURCE_NONE, FIELD_STR, rest_atom_parser }, + [ATOM_AHEADBEHIND] = { "ahead-behind", SOURCE_OTHER, FIELD_STR, ahead_behind_atom_parser }, /* * Please update $__git_ref_fieldlist in git-completion.bash * when you add new atoms @@ -791,7 +829,7 @@ static void quote_formatting(struct strbuf *s, const char *str, ssize_t len, int } static int append_atom(struct atom_value *v, struct ref_formatting_state *state, - struct strbuf *unused_err) + struct strbuf *err UNUSED) { /* * Quote formatting is only done when the stack has a single @@ -841,7 +879,7 @@ static void end_align_handler(struct ref_formatting_stack **stack) } static int align_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state, - struct strbuf *unused_err) + struct strbuf *err UNUSED) { struct ref_formatting_stack *new_stack; @@ -888,7 +926,7 @@ static void if_then_else_handler(struct ref_formatting_stack **stack) } static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state, - struct strbuf *unused_err) + struct strbuf *err UNUSED) { struct ref_formatting_stack *new_stack; struct if_then_else *if_then_else = xcalloc(1, @@ -915,7 +953,8 @@ static int is_empty(struct strbuf *buf) return cur == end; } -static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state, +static int then_atom_handler(struct atom_value *atomv UNUSED, + struct ref_formatting_state *state, struct strbuf *err) { struct ref_formatting_stack *cur = state->stack; @@ -952,7 +991,8 @@ static int then_atom_handler(struct atom_value *atomv, struct ref_formatting_sta return 0; } -static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state, +static int else_atom_handler(struct atom_value *atomv UNUSED, + struct ref_formatting_state *state, struct strbuf *err) { struct ref_formatting_stack *prev = state->stack; @@ -973,7 +1013,8 @@ static int else_atom_handler(struct atom_value *atomv, struct ref_formatting_sta return 0; } -static int end_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state, +static int end_atom_handler(struct atom_value *atomv UNUSED, + struct ref_formatting_state *state, struct strbuf *err) { struct ref_formatting_stack *current = state->stack; @@ -1075,9 +1116,11 @@ static const char *do_grab_oid(const char *field, const struct object_id *oid, case O_FULL: return oid_to_hex(oid); case O_LENGTH: - return find_unique_abbrev(oid, atom->u.oid.length); + return repo_find_unique_abbrev(the_repository, oid, + atom->u.oid.length); case O_SHORT: - return find_unique_abbrev(oid, DEFAULT_ABBREV); + return repo_find_unique_abbrev(the_repository, oid, + DEFAULT_ABBREV); default: BUG("unknown %%(%s) option", field); } @@ -1822,7 +1865,7 @@ static void lazy_init_worktree_map(void) populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees); } -static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref) +static char *get_worktree_path(const struct ref_array_item *ref) { struct hashmap_entry entry, *e; struct ref_to_worktree_entry *lookup_result; @@ -1848,6 +1891,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) struct object *obj; int i; struct object_info empty = OBJECT_INFO_INIT; + int ahead_behind_atoms = 0; CALLOC_ARRAY(ref->value, used_atom_cnt); @@ -1881,7 +1925,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) refname = get_refname(atom, ref); else if (atom_type == ATOM_WORKTREEPATH) { if (ref->kind == FILTER_REFS_BRANCHES) - v->s = get_worktree_path(atom, ref); + v->s = get_worktree_path(ref); else v->s = xstrdup(""); continue; @@ -1978,6 +2022,16 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) else v->s = xstrdup(""); continue; + } else if (atom_type == ATOM_AHEADBEHIND) { + if (ref->counts) { + const struct ahead_behind_count *count; + count = ref->counts[ahead_behind_atoms++]; + v->s = xstrfmt("%d %d", count->ahead, count->behind); + } else { + /* Not a commit. */ + v->s = xstrdup(""); + } + continue; } else continue; @@ -2328,6 +2382,7 @@ static void free_array_item(struct ref_array_item *item) free((char *)item->value[i].s); free(item->value); } + free(item->counts); free(item); } @@ -2356,6 +2411,8 @@ void ref_array_clear(struct ref_array *array) free_worktrees(ref_to_worktree_map.worktrees); ref_to_worktree_map.worktrees = NULL; } + + FREE_AND_NULL(array->counts); } #define EXCLUDE_REACHED 0 @@ -2364,33 +2421,22 @@ 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 commit **to_clear; - struct commit_list *cr; if (!check_reachable) return; CALLOC_ARRAY(to_clear, array->nr); - - repo_init_revisions(the_repository, &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; } - 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)) - die(_("revision walk setup failed")); + tips_reachable_from_bases(the_repository, + check_reachable, + to_clear, array->nr, + UNINTERESTING); old_nr = array->nr; array->nr = 0; @@ -2414,10 +2460,50 @@ static void reach_filter(struct ref_array *array, clear_commit_marks(merge_commit, ALL_REV_FLAGS); } - release_revisions(&revs); free(to_clear); } +void filter_ahead_behind(struct repository *r, + struct ref_format *format, + struct ref_array *array) +{ + struct commit **commits; + size_t commits_nr = format->bases.nr + array->nr; + + if (!format->bases.nr || !array->nr) + return; + + ALLOC_ARRAY(commits, commits_nr); + for (size_t i = 0; i < format->bases.nr; i++) + commits[i] = format->bases.items[i].util; + + ALLOC_ARRAY(array->counts, st_mult(format->bases.nr, array->nr)); + + commits_nr = format->bases.nr; + array->counts_nr = 0; + for (size_t i = 0; i < array->nr; i++) { + const char *name = array->items[i]->refname; + commits[commits_nr] = lookup_commit_reference_by_name(name); + + if (!commits[commits_nr]) + continue; + + CALLOC_ARRAY(array->items[i]->counts, format->bases.nr); + for (size_t j = 0; j < format->bases.nr; j++) { + struct ahead_behind_count *count; + count = &array->counts[array->counts_nr++]; + count->tip_index = commits_nr; + count->base_index = j; + + array->items[i]->counts[j] = count; + } + commits_nr++; + } + + ahead_behind(r, commits, commits_nr, array->counts, array->counts_nr); + free(commits); +} + /* * 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 @@ -2765,7 +2851,7 @@ int parse_opt_merge_filter(const struct option *opt, const char *arg, int unset) BUG_ON_OPT_NEG(unset); - if (get_oid(arg, &oid)) + if (repo_get_oid(the_repository, arg, &oid)) die(_("malformed object name %s"), arg); merge_commit = lookup_commit_reference_gently(the_repository, &oid, 0); |