From: Junio C Hamano Date: Mon, 5 Jun 2017 00:18:11 +0000 (+0900) Subject: Merge branch 'mh/packed-ref-store-prep' X-Git-Tag: v2.14.0-rc0~109 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/711a11c301dafe84389624f009a2abfb7da5d83f?hp=-c Merge branch 'mh/packed-ref-store-prep' The implementation of "ref" API around the "packed refs" have been cleaned up, in preparation for further changes. * mh/packed-ref-store-prep: (25 commits) cache_ref_iterator_begin(): avoid priming unneeded directories ref-filter: limit traversal to prefix create_ref_entry(): remove `check_name` option refs_ref_iterator_begin(): handle `GIT_REF_PARANOIA` read_packed_refs(): report unexpected fopen() failures read_packed_refs(): do more of the work of reading packed refs get_packed_ref_cache(): assume "packed-refs" won't change while locked should_pack_ref(): new function, extracted from `files_pack_refs()` ref_update_reject_duplicates(): add a sanity check ref_update_reject_duplicates(): use `size_t` rather than `int` ref_update_reject_duplicates(): expose function to whole refs module ref_transaction_prepare(): new optional step for reference updates ref_transaction_commit(): check for valid `transaction->state` files_transaction_cleanup(): new helper function files_ref_store: put the packed files lock directly in this struct files-backend: move `lock` member to `files_ref_store` lockfile: add a new method, is_lock_file_locked() ref_store: take a `msg` parameter when deleting references refs: use `size_t` indexes when iterating over ref transaction updates refs_ref_iterator_begin(): don't check prefixes redundantly ... --- 711a11c301dafe84389624f009a2abfb7da5d83f diff --combined builtin/remote.c index 9054e2858e,5f52c5a6d6..f1a88fe265 --- a/builtin/remote.c +++ b/builtin/remote.c @@@ -786,7 -786,7 +786,7 @@@ static int rm(int argc, const char **ar strbuf_release(&buf); if (!result) - result = delete_refs(&branches, REF_NODEREF); + result = delete_refs("remote: remove", &branches, REF_NODEREF); string_list_clear(&branches, 0); if (skipped.nr) { @@@ -1151,11 -1151,8 +1151,11 @@@ static int show(int argc, const char ** url_nr = states.remote->url_nr; } for (i = 0; i < url_nr; i++) - /* TRANSLATORS: the colon ':' should align with - the one in " Fetch URL: %s" translation */ + /* + * TRANSLATORS: the colon ':' should align + * with the one in " Fetch URL: %s" + * translation. + */ printf_ln(_(" Push URL: %s"), url[i]); if (!i) printf_ln(_(" Push URL: %s"), _("(no URL)")); @@@ -1304,7 -1301,7 +1304,7 @@@ static int prune_remote(const char *rem string_list_sort(&refs_to_prune); if (!dry_run) - result |= delete_refs(&refs_to_prune, 0); + result |= delete_refs("remote: prune", &refs_to_prune, 0); for_each_string_list_item(item, &states.stale) { const char *refname = item->util; diff --combined ref-filter.c index af5c0edb48,25ca56d62f..ab32bc9c31 --- a/ref-filter.c +++ b/ref-filter.c @@@ -93,7 -93,6 +93,7 @@@ static struct used_atom unsigned int length; } objectname; struct refname_atom refname; + char *head; } u; } *used_atom; static int used_atom_cnt, need_tagged, need_symref; @@@ -288,12 -287,6 +288,12 @@@ static void if_atom_parser(struct used_ } } +static void head_atom_parser(struct used_atom *atom, const char *arg) +{ + struct object_id unused; + + atom->u.head = resolve_refdup("HEAD", RESOLVE_REF_READING, unused.hash, NULL); +} static struct { const char *name; @@@ -332,7 -325,7 +332,7 @@@ { "push", FIELD_STR, remote_ref_atom_parser }, { "symref", FIELD_STR, refname_atom_parser }, { "flag" }, - { "HEAD" }, + { "HEAD", FIELD_STR, head_atom_parser }, { "color", FIELD_STR, color_atom_parser }, { "align", FIELD_STR, align_atom_parser }, { "end" }, @@@ -1258,17 -1251,13 +1258,17 @@@ char *get_head_description(void state.branch); else if (state.detached_from) { if (state.detached_at) - /* TRANSLATORS: make sure this matches - "HEAD detached at " in wt-status.c */ + /* + * TRANSLATORS: make sure this matches "HEAD + * detached at " in wt-status.c + */ strbuf_addf(&desc, _("(HEAD detached at %s)"), state.detached_from); else - /* TRANSLATORS: make sure this matches - "HEAD detached from " in wt-status.c */ + /* + * TRANSLATORS: make sure this matches "HEAD + * detached from " in wt-status.c + */ strbuf_addf(&desc, _("(HEAD detached from %s)"), state.detached_from); } @@@ -1380,7 -1369,12 +1380,7 @@@ static void populate_value(struct ref_a } else if (!deref && grab_objectname(name, ref->objectname.hash, v, atom)) { continue; } else if (!strcmp(name, "HEAD")) { - const char *head; - struct object_id oid; - - head = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, - oid.hash, NULL); - if (head && !strcmp(ref->refname, head)) + if (atom->u.head && !strcmp(ref->refname, atom->u.head)) v->s = "*"; else v->s = " "; @@@ -1671,6 -1665,68 +1671,68 @@@ static int filter_pattern_match(struct return match_pattern(filter, refname); } + /* + * Find the longest prefix of pattern we can pass to + * `for_each_fullref_in()`, namely the part of pattern preceding the + * first glob character. (Note that `for_each_fullref_in()` is + * perfectly happy working with a prefix that doesn't end at a + * pathname component boundary.) + */ + static void find_longest_prefix(struct strbuf *out, const char *pattern) + { + const char *p; + + for (p = pattern; *p && !is_glob_special(*p); p++) + ; + + strbuf_add(out, pattern, p - pattern); + } + + /* + * This is the same as for_each_fullref_in(), but it tries to iterate + * only over the patterns we'll care about. Note that it _doesn't_ do a full + * pattern match, so the callback still has to match each ref individually. + */ + static int for_each_fullref_in_pattern(struct ref_filter *filter, + each_ref_fn cb, + void *cb_data, + int broken) + { + struct strbuf prefix = STRBUF_INIT; + int ret; + + if (!filter->match_as_path) { + /* + * in this case, the patterns are applied after + * prefixes like "refs/heads/" etc. are stripped off, + * so we have to look at everything: + */ + return for_each_fullref_in("", cb, cb_data, broken); + } + + if (!filter->name_patterns[0]) { + /* no patterns; we have to look at everything */ + return for_each_fullref_in("", cb, cb_data, broken); + } + + if (filter->name_patterns[1]) { + /* + * multiple patterns; in theory this could still work as long + * as the patterns are disjoint. We'd just make multiple calls + * to for_each_ref(). But if they're not disjoint, we'd end up + * reporting the same ref multiple times. So let's punt on that + * for now. + */ + return for_each_fullref_in("", cb, cb_data, broken); + } + + find_longest_prefix(&prefix, filter->name_patterns[0]); + + ret = for_each_fullref_in(prefix.buf, cb, cb_data, broken); + strbuf_release(&prefix); + return ret; + } + /* * Given a ref (sha1, refname), check if the ref belongs to the array * of sha1s. If the given ref is a tag, check if the given tag points @@@ -1917,7 -1973,7 +1979,7 @@@ int filter_refs(struct ref_array *array else if (filter->kind == FILTER_REFS_TAGS) ret = for_each_fullref_in("refs/tags/", ref_filter_handler, &ref_cbdata, broken); else if (filter->kind & FILTER_REFS_ALL) - ret = for_each_fullref_in("", ref_filter_handler, &ref_cbdata, broken); + ret = for_each_fullref_in_pattern(filter, ref_filter_handler, &ref_cbdata, broken); if (!ret && (filter->kind & FILTER_REFS_DETACHED_HEAD)) head_ref(ref_filter_handler, &ref_cbdata); }