Merge branch 'mh/packed-ref-store-prep'
authorJunio C Hamano <gitster@pobox.com>
Mon, 5 Jun 2017 00:18:11 +0000 (09:18 +0900)
committerJunio C Hamano <gitster@pobox.com>
Mon, 5 Jun 2017 00:18:11 +0000 (09:18 +0900)
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
...

1  2 
builtin/remote.c
ref-filter.c
diff --combined builtin/remote.c
index 9054e2858e324aca5d6ce062331cf0ad9ccf0819,5f52c5a6d6dfdb2202b9e86991b64bd1a5bd552d..f1a88fe2658986af2e33d3979af1764f6decc43b
@@@ -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 af5c0edb483a3975e17685fdc06bae2ff58d59e4,25ca56d62f109ade97d7106ebbba6e40a828c2ab..ab32bc9c3145c85c839c660c54b61f13fe9cb51a
@@@ -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;
        { "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);
        }