Merge branch 'nd/worktree-kill-parse-ref'
authorJunio C Hamano <gitster@pobox.com>
Tue, 16 May 2017 02:51:51 +0000 (11:51 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 16 May 2017 02:51:51 +0000 (11:51 +0900)
"git gc" did not interact well with "git worktree"-managed
per-worktree refs.

* nd/worktree-kill-parse-ref:
refs: kill set_worktree_head_symref()
worktree.c: kill parse_ref() in favor of refs_resolve_ref_unsafe()
refs: introduce get_worktree_ref_store()
refs: add REFS_STORE_ALL_CAPS
refs.c: make submodule ref store hashmap generic
environment.c: fix potential segfault by get_git_common_dir()

1  2 
branch.c
environment.c
refs.c
refs.h
refs/files-backend.c
refs/refs-internal.h
worktree.c
diff --combined branch.c
index ad5a2299ba2600e67c8aaa7719a2c7d54898958f,69d5eea84b04d9306aeb15fb511533e39143d68b..bb9eb60dcdb946f380ae9441caf84561a61f5dd3
+++ b/branch.c
@@@ -234,7 -234,7 +234,7 @@@ void create_branch(const char *name, co
  {
        struct commit *commit;
        unsigned char sha1[20];
 -      char *real_ref, msg[PATH_MAX + 20];
 +      char *real_ref;
        struct strbuf ref = STRBUF_INIT;
        int forcing = 0;
        int dont_change_ref = 0;
                die(_("Not a valid branch point: '%s'."), start_name);
        hashcpy(sha1, commit->object.oid.hash);
  
 -      if (forcing)
 -              snprintf(msg, sizeof msg, "branch: Reset to %s",
 -                       start_name);
 -      else if (!dont_change_ref)
 -              snprintf(msg, sizeof msg, "branch: Created from %s",
 -                       start_name);
 -
        if (reflog)
                log_all_ref_updates = LOG_REFS_NORMAL;
  
        if (!dont_change_ref) {
                struct ref_transaction *transaction;
                struct strbuf err = STRBUF_INIT;
 +              char *msg;
 +
 +              if (forcing)
 +                      msg = xstrfmt("branch: Reset to %s", start_name);
 +              else
 +                      msg = xstrfmt("branch: Created from %s", start_name);
  
                transaction = ref_transaction_begin(&err);
                if (!transaction ||
                        die("%s", err.buf);
                ref_transaction_free(transaction);
                strbuf_release(&err);
 +              free(msg);
        }
  
        if (real_ref && track)
@@@ -353,17 -353,18 +353,18 @@@ int replace_each_worktree_head_symref(c
        int i;
  
        for (i = 0; worktrees[i]; i++) {
+               struct ref_store *refs;
                if (worktrees[i]->is_detached)
                        continue;
-               if (strcmp(oldref, worktrees[i]->head_ref))
+               if (worktrees[i]->head_ref &&
+                   strcmp(oldref, worktrees[i]->head_ref))
                        continue;
  
-               if (set_worktree_head_symref(get_worktree_git_dir(worktrees[i]),
-                                            newref, logmsg)) {
-                       ret = -1;
-                       error(_("HEAD of working tree %s is not updated"),
-                             worktrees[i]->path);
-               }
+               refs = get_worktree_ref_store(worktrees[i]);
+               if (refs_create_symref(refs, "HEAD", newref, logmsg))
+                       ret = error(_("HEAD of working tree %s is not updated"),
+                                   worktrees[i]->path);
        }
  
        free_worktrees(worktrees);
diff --combined environment.c
index ff6e4f06e93d642aa53ba1812c3788b0ccad092e,2986ee7200891a00f1ca2a0bd153157450531bd5..560408953c8f76a30a093a59505e52c828d8d20b
@@@ -167,11 -167,8 +167,11 @@@ static void setup_git_env(void
        const char *replace_ref_base;
  
        git_dir = getenv(GIT_DIR_ENVIRONMENT);
 -      if (!git_dir)
 +      if (!git_dir) {
 +              if (!startup_info->have_repository)
 +                      die("BUG: setup_git_env called without repository");
                git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
 +      }
        gitfile = read_gitfile(git_dir);
        git_dir = xstrdup(gitfile ? gitfile : git_dir);
        if (get_common_dir(&sb, git_dir))
@@@ -217,6 -214,8 +217,8 @@@ const char *get_git_dir(void
  
  const char *get_git_common_dir(void)
  {
+       if (!git_dir)
+               setup_git_env();
        return git_common_dir;
  }
  
@@@ -277,7 -276,7 +279,7 @@@ char *get_object_directory(void
        return git_object_dir;
  }
  
 -int odb_mkstemp(char *template, size_t limit, const char *pattern)
 +int odb_mkstemp(struct strbuf *template, const char *pattern)
  {
        int fd;
        /*
         * restrictive except to remove write permission.
         */
        int mode = 0444;
 -      snprintf(template, limit, "%s/%s",
 -               get_object_directory(), pattern);
 -      fd = git_mkstemp_mode(template, mode);
 +      git_path_buf(template, "objects/%s", pattern);
 +      fd = git_mkstemp_mode(template->buf, mode);
        if (0 <= fd)
                return fd;
  
        /* slow path */
        /* some mkstemp implementations erase template on failure */
 -      snprintf(template, limit, "%s/%s",
 -               get_object_directory(), pattern);
 -      safe_create_leading_directories(template);
 -      return xmkstemp_mode(template, mode);
 +      git_path_buf(template, "objects/%s", pattern);
 +      safe_create_leading_directories(template->buf);
 +      return xmkstemp_mode(template->buf, mode);
  }
  
 -int odb_pack_keep(char *name, size_t namesz, const unsigned char *sha1)
 +int odb_pack_keep(const char *name)
  {
        int fd;
  
 -      snprintf(name, namesz, "%s/pack/pack-%s.keep",
 -               get_object_directory(), sha1_to_hex(sha1));
        fd = open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
        if (0 <= fd)
                return fd;
  
        /* slow path */
 -      safe_create_leading_directories(name);
 +      safe_create_leading_directories_const(name);
        return open(name, O_RDWR|O_CREAT|O_EXCL, 0600);
  }
  
diff --combined refs.c
index df75f8e0d695fc235c1a2497069a9b916a4a04e8,7972720256053a953c8c17db22b9dc323693a16c..fda450118112694ed1fedd1258cea3e283866569
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -5,12 -5,12 +5,13 @@@
  #include "cache.h"
  #include "hashmap.h"
  #include "lockfile.h"
 +#include "iterator.h"
  #include "refs.h"
  #include "refs/refs-internal.h"
  #include "object.h"
  #include "tag.h"
  #include "submodule.h"
+ #include "worktree.h"
  
  /*
   * List of all available backends
@@@ -405,11 -405,11 +406,11 @@@ int for_each_glob_ref(each_ref_fn fn, c
  
  const char *prettify_refname(const char *name)
  {
 -      return name + (
 -              starts_with(name, "refs/heads/") ? 11 :
 -              starts_with(name, "refs/tags/") ? 10 :
 -              starts_with(name, "refs/remotes/") ? 13 :
 -              0);
 +      if (skip_prefix(name, "refs/heads/", &name) ||
 +          skip_prefix(name, "refs/tags/", &name) ||
 +          skip_prefix(name, "refs/remotes/", &name))
 +              ; /* nothing */
 +      return name;
  }
  
  static const char *ref_rev_parse_rules[] = {
@@@ -468,31 -468,29 +469,31 @@@ int expand_ref(const char *str, int len
  {
        const char **p, *r;
        int refs_found = 0;
 +      struct strbuf fullref = STRBUF_INIT;
  
        *ref = NULL;
        for (p = ref_rev_parse_rules; *p; p++) {
 -              char fullref[PATH_MAX];
                unsigned char sha1_from_ref[20];
                unsigned char *this_result;
                int flag;
  
                this_result = refs_found ? sha1_from_ref : sha1;
 -              mksnpath(fullref, sizeof(fullref), *p, len, str);
 -              r = resolve_ref_unsafe(fullref, RESOLVE_REF_READING,
 +              strbuf_reset(&fullref);
 +              strbuf_addf(&fullref, *p, len, str);
 +              r = resolve_ref_unsafe(fullref.buf, RESOLVE_REF_READING,
                                       this_result, &flag);
                if (r) {
                        if (!refs_found++)
                                *ref = xstrdup(r);
                        if (!warn_ambiguous_refs)
                                break;
 -              } else if ((flag & REF_ISSYMREF) && strcmp(fullref, "HEAD")) {
 -                      warning("ignoring dangling symref %s.", fullref);
 -              } else if ((flag & REF_ISBROKEN) && strchr(fullref, '/')) {
 -                      warning("ignoring broken ref %s.", fullref);
 +              } else if ((flag & REF_ISSYMREF) && strcmp(fullref.buf, "HEAD")) {
 +                      warning("ignoring dangling symref %s.", fullref.buf);
 +              } else if ((flag & REF_ISBROKEN) && strchr(fullref.buf, '/')) {
 +                      warning("ignoring broken ref %s.", fullref.buf);
                }
        }
 +      strbuf_release(&fullref);
        return refs_found;
  }
  
@@@ -501,22 -499,21 +502,22 @@@ int dwim_log(const char *str, int len, 
        char *last_branch = substitute_branch_name(&str, &len);
        const char **p;
        int logs_found = 0;
 +      struct strbuf path = STRBUF_INIT;
  
        *log = NULL;
        for (p = ref_rev_parse_rules; *p; p++) {
                unsigned char hash[20];
 -              char path[PATH_MAX];
                const char *ref, *it;
  
 -              mksnpath(path, sizeof(path), *p, len, str);
 -              ref = resolve_ref_unsafe(path, RESOLVE_REF_READING,
 +              strbuf_reset(&path);
 +              strbuf_addf(&path, *p, len, str);
 +              ref = resolve_ref_unsafe(path.buf, RESOLVE_REF_READING,
                                         hash, NULL);
                if (!ref)
                        continue;
 -              if (reflog_exists(path))
 -                      it = path;
 -              else if (strcmp(ref, path) && reflog_exists(ref))
 +              if (reflog_exists(path.buf))
 +                      it = path.buf;
 +              else if (strcmp(ref, path.buf) && reflog_exists(ref))
                        it = ref;
                else
                        continue;
                if (!warn_ambiguous_refs)
                        break;
        }
 +      strbuf_release(&path);
        free(last_branch);
        return logs_found;
  }
@@@ -1018,7 -1014,6 +1019,7 @@@ char *shorten_unambiguous_ref(const cha
        static char **scanf_fmts;
        static int nr_rules;
        char *short_name;
 +      struct strbuf resolved_buf = STRBUF_INIT;
  
        if (!nr_rules) {
                /*
                 */
                for (j = 0; j < rules_to_fail; j++) {
                        const char *rule = ref_rev_parse_rules[j];
 -                      char refname[PATH_MAX];
  
                        /* skip matched rule */
                        if (i == j)
                         * (with this previous rule) to a valid ref
                         * read_ref() returns 0 on success
                         */
 -                      mksnpath(refname, sizeof(refname),
 -                               rule, short_name_len, short_name);
 -                      if (ref_exists(refname))
 +                      strbuf_reset(&resolved_buf);
 +                      strbuf_addf(&resolved_buf, rule,
 +                                  short_name_len, short_name);
 +                      if (ref_exists(resolved_buf.buf))
                                break;
                }
  
                 * short name is non-ambiguous if all previous rules
                 * haven't resolved to a valid ref
                 */
 -              if (j == rules_to_fail)
 +              if (j == rules_to_fail) {
 +                      strbuf_release(&resolved_buf);
                        return short_name;
 +              }
        }
  
 +      strbuf_release(&resolved_buf);
        free(short_name);
        return xstrdup(refname);
  }
@@@ -1239,18 -1231,6 +1240,18 @@@ int head_ref(each_ref_fn fn, void *cb_d
        return head_ref_submodule(NULL, fn, cb_data);
  }
  
 +struct ref_iterator *refs_ref_iterator_begin(
 +              struct ref_store *refs,
 +              const char *prefix, int trim, int flags)
 +{
 +      struct ref_iterator *iter;
 +
 +      iter = refs->be->iterator_begin(refs, prefix, flags);
 +      iter = prefix_ref_iterator_begin(iter, prefix, trim);
 +
 +      return iter;
 +}
 +
  /*
   * Call fn for each reference in the specified submodule for which the
   * refname begins with prefix. If trim is non-zero, then trim that
@@@ -1268,7 -1248,8 +1269,7 @@@ static int do_for_each_ref(struct ref_s
        if (!refs)
                return 0;
  
 -      iter = refs->be->iterator_begin(refs, prefix, flags);
 -      iter = prefix_ref_iterator_begin(iter, prefix, trim);
 +      iter = refs_ref_iterator_begin(refs, prefix, trim, flags);
  
        return do_for_each_ref_iterator(iter, fn, cb_data);
  }
@@@ -1346,13 -1327,6 +1347,13 @@@ int for_each_rawref(each_ref_fn fn, voi
        return refs_for_each_rawref(get_main_ref_store(), fn, cb_data);
  }
  
 +int refs_read_raw_ref(struct ref_store *ref_store,
 +                    const char *refname, unsigned char *sha1,
 +                    struct strbuf *referent, unsigned int *type)
 +{
 +      return ref_store->be->read_raw_ref(ref_store, refname, sha1, referent, type);
 +}
 +
  /* This function needs to return a meaningful errno on failure */
  const char *refs_resolve_ref_unsafe(struct ref_store *refs,
                                    const char *refname,
        for (symref_count = 0; symref_count < SYMREF_MAXDEPTH; symref_count++) {
                unsigned int read_flags = 0;
  
 -              if (refs->be->read_raw_ref(refs, refname,
 -                                         sha1, &sb_refname, &read_flags)) {
 +              if (refs_read_raw_ref(refs, refname,
 +                                    sha1, &sb_refname, &read_flags)) {
                        *flags |= read_flags;
                        if (errno != ENOENT || (resolve_flags & RESOLVE_REF_READING))
                                return NULL;
@@@ -1477,32 -1451,32 +1478,32 @@@ int resolve_gitlink_ref(const char *sub
        return 0;
  }
  
- struct submodule_hash_entry
+ struct ref_store_hash_entry
  {
        struct hashmap_entry ent; /* must be the first member! */
  
        struct ref_store *refs;
  
-       /* NUL-terminated name of submodule: */
-       char submodule[FLEX_ARRAY];
+       /* NUL-terminated identifier of the ref store: */
+       char name[FLEX_ARRAY];
  };
  
- static int submodule_hash_cmp(const void *entry, const void *entry_or_key,
+ static int ref_store_hash_cmp(const void *entry, const void *entry_or_key,
                              const void *keydata)
  {
-       const struct submodule_hash_entry *e1 = entry, *e2 = entry_or_key;
-       const char *submodule = keydata ? keydata : e2->submodule;
+       const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key;
+       const char *name = keydata ? keydata : e2->name;
  
-       return strcmp(e1->submodule, submodule);
+       return strcmp(e1->name, name);
  }
  
- static struct submodule_hash_entry *alloc_submodule_hash_entry(
-               const char *submodule, struct ref_store *refs)
+ static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
+               const char *name, struct ref_store *refs)
  {
-       struct submodule_hash_entry *entry;
+       struct ref_store_hash_entry *entry;
  
-       FLEX_ALLOC_STR(entry, submodule, submodule);
-       hashmap_entry_init(entry, strhash(submodule));
+       FLEX_ALLOC_STR(entry, name, name);
+       hashmap_entry_init(entry, strhash(name));
        entry->refs = refs;
        return entry;
  }
@@@ -1513,20 -1487,23 +1514,23 @@@ static struct ref_store *main_ref_store
  /* A hashmap of ref_stores, stored by submodule name: */
  static struct hashmap submodule_ref_stores;
  
+ /* A hashmap of ref_stores, stored by worktree id: */
+ static struct hashmap worktree_ref_stores;
  /*
-  * Return the ref_store instance for the specified submodule. If that
-  * ref_store hasn't been initialized yet, return NULL.
+  * Look up a ref store by name. If that ref_store hasn't been
+  * registered yet, return NULL.
   */
- static struct ref_store *lookup_submodule_ref_store(const char *submodule)
+ static struct ref_store *lookup_ref_store_map(struct hashmap *map,
+                                             const char *name)
  {
-       struct submodule_hash_entry *entry;
+       struct ref_store_hash_entry *entry;
  
-       if (!submodule_ref_stores.tablesize)
+       if (!map->tablesize)
                /* It's initialized on demand in register_ref_store(). */
                return NULL;
  
-       entry = hashmap_get_from_hash(&submodule_ref_stores,
-                                     strhash(submodule), submodule);
+       entry = hashmap_get_from_hash(map, strhash(name), name);
        return entry ? entry->refs : NULL;
  }
  
@@@ -1553,29 -1530,24 +1557,24 @@@ struct ref_store *get_main_ref_store(vo
        if (main_ref_store)
                return main_ref_store;
  
-       main_ref_store = ref_store_init(get_git_dir(),
-                                       (REF_STORE_READ |
-                                        REF_STORE_WRITE |
-                                        REF_STORE_ODB |
-                                        REF_STORE_MAIN));
+       main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS);
        return main_ref_store;
  }
  
  /*
-  * Register the specified ref_store to be the one that should be used
-  * for submodule. It is a fatal error to call this function twice for
-  * the same submodule.
+  * Associate a ref store with a name. It is a fatal error to call this
+  * function twice for the same name.
   */
- static void register_submodule_ref_store(struct ref_store *refs,
-                                        const char *submodule)
+ static void register_ref_store_map(struct hashmap *map,
+                                  const char *type,
+                                  struct ref_store *refs,
+                                  const char *name)
  {
-       if (!submodule_ref_stores.tablesize)
-               hashmap_init(&submodule_ref_stores, submodule_hash_cmp, 0);
+       if (!map->tablesize)
+               hashmap_init(map, ref_store_hash_cmp, 0);
  
-       if (hashmap_put(&submodule_ref_stores,
-                       alloc_submodule_hash_entry(submodule, refs)))
-               die("BUG: ref_store for submodule '%s' initialized twice",
-                   submodule);
+       if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
+               die("BUG: %s ref_store '%s' initialized twice", type, name);
  }
  
  struct ref_store *get_submodule_ref_store(const char *submodule)
                return get_main_ref_store();
        }
  
-       refs = lookup_submodule_ref_store(submodule);
+       refs = lookup_ref_store_map(&submodule_ref_stores, submodule);
        if (refs)
                return refs;
  
        /* assume that add_submodule_odb() has been called */
        refs = ref_store_init(submodule_sb.buf,
                              REF_STORE_READ | REF_STORE_ODB);
-       register_submodule_ref_store(refs, submodule);
+       register_ref_store_map(&submodule_ref_stores, "submodule",
+                              refs, submodule);
  
        strbuf_release(&submodule_sb);
        return refs;
  }
  
+ struct ref_store *get_worktree_ref_store(const struct worktree *wt)
+ {
+       struct ref_store *refs;
+       const char *id;
+       if (wt->is_current)
+               return get_main_ref_store();
+       id = wt->id ? wt->id : "/";
+       refs = lookup_ref_store_map(&worktree_ref_stores, id);
+       if (refs)
+               return refs;
+       if (wt->id)
+               refs = ref_store_init(git_common_path("worktrees/%s", wt->id),
+                                     REF_STORE_ALL_CAPS);
+       else
+               refs = ref_store_init(get_git_common_dir(),
+                                     REF_STORE_ALL_CAPS);
+       if (refs)
+               register_ref_store_map(&worktree_ref_stores, "worktree",
+                                      refs, id);
+       return refs;
+ }
  void base_ref_store_init(struct ref_store *refs,
                         const struct ref_storage_be *be)
  {
@@@ -1662,102 -1661,16 +1688,102 @@@ int ref_transaction_commit(struct ref_t
  {
        struct ref_store *refs = transaction->ref_store;
  
 +      if (getenv(GIT_QUARANTINE_ENVIRONMENT)) {
 +              strbuf_addstr(err,
 +                            _("ref updates forbidden inside quarantine environment"));
 +              return -1;
 +      }
 +
        return refs->be->transaction_commit(refs, transaction, err);
  }
  
  int refs_verify_refname_available(struct ref_store *refs,
                                  const char *refname,
 -                                const struct string_list *extra,
 +                                const struct string_list *extras,
                                  const struct string_list *skip,
                                  struct strbuf *err)
  {
 -      return refs->be->verify_refname_available(refs, refname, extra, skip, err);
 +      const char *slash;
 +      const char *extra_refname;
 +      struct strbuf dirname = STRBUF_INIT;
 +      struct strbuf referent = STRBUF_INIT;
 +      struct object_id oid;
 +      unsigned int type;
 +      struct ref_iterator *iter;
 +      int ok;
 +      int ret = -1;
 +
 +      /*
 +       * For the sake of comments in this function, suppose that
 +       * refname is "refs/foo/bar".
 +       */
 +
 +      assert(err);
 +
 +      strbuf_grow(&dirname, strlen(refname) + 1);
 +      for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
 +              /* Expand dirname to the new prefix, not including the trailing slash: */
 +              strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len);
 +
 +              /*
 +               * We are still at a leading dir of the refname (e.g.,
 +               * "refs/foo"; if there is a reference with that name,
 +               * it is a conflict, *unless* it is in skip.
 +               */
 +              if (skip && string_list_has_string(skip, dirname.buf))
 +                      continue;
 +
 +              if (!refs_read_raw_ref(refs, dirname.buf, oid.hash, &referent, &type)) {
 +                      strbuf_addf(err, "'%s' exists; cannot create '%s'",
 +                                  dirname.buf, refname);
 +                      goto cleanup;
 +              }
 +
 +              if (extras && string_list_has_string(extras, dirname.buf)) {
 +                      strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
 +                                  refname, dirname.buf);
 +                      goto cleanup;
 +              }
 +      }
 +
 +      /*
 +       * We are at the leaf of our refname (e.g., "refs/foo/bar").
 +       * There is no point in searching for a reference with that
 +       * name, because a refname isn't considered to conflict with
 +       * itself. But we still need to check for references whose
 +       * names are in the "refs/foo/bar/" namespace, because they
 +       * *do* conflict.
 +       */
 +      strbuf_addstr(&dirname, refname + dirname.len);
 +      strbuf_addch(&dirname, '/');
 +
 +      iter = refs_ref_iterator_begin(refs, dirname.buf, 0,
 +                                     DO_FOR_EACH_INCLUDE_BROKEN);
 +      while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
 +              if (skip &&
 +                  string_list_has_string(skip, iter->refname))
 +                      continue;
 +
 +              strbuf_addf(err, "'%s' exists; cannot create '%s'",
 +                          iter->refname, refname);
 +              ref_iterator_abort(iter);
 +              goto cleanup;
 +      }
 +
 +      if (ok != ITER_DONE)
 +              die("BUG: error while iterating over references");
 +
 +      extra_refname = find_descendant_ref(dirname.buf, extras, skip);
 +      if (extra_refname)
 +              strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
 +                          refname, extra_refname);
 +      else
 +              ret = 0;
 +
 +cleanup:
 +      strbuf_release(&referent);
 +      strbuf_release(&dirname);
 +      return ret;
  }
  
  int refs_for_each_reflog(struct ref_store *refs, each_ref_fn fn, void *cb_data)
diff --combined refs.h
index 07cf4cd41b15ee5dafdb5c99983b136db84aaa81,447381d37806236d48dfaa560e25297e97509b6c..aca805168abd98149bc1725721fe2d53b6ed5802
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
@@@ -5,6 -5,7 +5,7 @@@ struct object_id
  struct ref_store;
  struct strbuf;
  struct string_list;
+ struct worktree;
  
  /*
   * Resolve a reference, recursively following symbolic refererences.
@@@ -97,7 -98,7 +98,7 @@@ int read_ref(const char *refname, unsig
  
  int refs_verify_refname_available(struct ref_store *refs,
                                  const char *refname,
 -                                const struct string_list *extra,
 +                                const struct string_list *extras,
                                  const struct string_list *skip,
                                  struct strbuf *err);
  
@@@ -401,16 -402,6 +402,6 @@@ int refs_create_symref(struct ref_stor
                       const char *target, const char *logmsg);
  int create_symref(const char *refname, const char *target, const char *logmsg);
  
- /*
-  * Update HEAD of the specified gitdir.
-  * Similar to create_symref("relative-git-dir/HEAD", target, NULL), but
-  * this can update the main working tree's HEAD regardless of where
-  * $GIT_DIR points to.
-  * Return 0 if successful, non-zero otherwise.
-  * */
- int set_worktree_head_symref(const char *gitdir, const char *target,
-                            const char *logmsg);
  enum action_on_err {
        UPDATE_REFS_MSG_ON_ERR,
        UPDATE_REFS_DIE_ON_ERR,
@@@ -655,5 -646,6 +646,6 @@@ struct ref_store *get_main_ref_store(vo
   * submodule==NULL.
   */
  struct ref_store *get_submodule_ref_store(const char *submodule);
+ struct ref_store *get_worktree_ref_store(const struct worktree *wt);
  
  #endif /* REFS_H */
diff --combined refs/files-backend.c
index 83ea080e013f90e95d1897258dd80b44ac9b5db6,4149943a6ee4e064756f496037d2e9d308688304..9d08e84ded1e93c3f43b74f4dd92934d190fabf1
@@@ -1,7 -1,6 +1,7 @@@
  #include "../cache.h"
  #include "../refs.h"
  #include "refs-internal.h"
 +#include "ref-cache.h"
  #include "../iterator.h"
  #include "../dir-iterator.h"
  #include "../lockfile.h"
@@@ -14,6 -13,511 +14,6 @@@ struct ref_lock 
        struct object_id old_oid;
  };
  
 -struct ref_entry;
 -
 -/*
 - * Information used (along with the information in ref_entry) to
 - * describe a single cached reference.  This data structure only
 - * occurs embedded in a union in struct ref_entry, and only when
 - * (ref_entry->flag & REF_DIR) is zero.
 - */
 -struct ref_value {
 -      /*
 -       * The name of the object to which this reference resolves
 -       * (which may be a tag object).  If REF_ISBROKEN, this is
 -       * null.  If REF_ISSYMREF, then this is the name of the object
 -       * referred to by the last reference in the symlink chain.
 -       */
 -      struct object_id oid;
 -
 -      /*
 -       * If REF_KNOWS_PEELED, then this field holds the peeled value
 -       * of this reference, or null if the reference is known not to
 -       * be peelable.  See the documentation for peel_ref() for an
 -       * exact definition of "peelable".
 -       */
 -      struct object_id peeled;
 -};
 -
 -struct files_ref_store;
 -
 -/*
 - * Information used (along with the information in ref_entry) to
 - * describe a level in the hierarchy of references.  This data
 - * structure only occurs embedded in a union in struct ref_entry, and
 - * only when (ref_entry.flag & REF_DIR) is set.  In that case,
 - * (ref_entry.flag & REF_INCOMPLETE) determines whether the references
 - * in the directory have already been read:
 - *
 - *     (ref_entry.flag & REF_INCOMPLETE) unset -- a directory of loose
 - *         or packed references, already read.
 - *
 - *     (ref_entry.flag & REF_INCOMPLETE) set -- a directory of loose
 - *         references that hasn't been read yet (nor has any of its
 - *         subdirectories).
 - *
 - * Entries within a directory are stored within a growable array of
 - * pointers to ref_entries (entries, nr, alloc).  Entries 0 <= i <
 - * sorted are sorted by their component name in strcmp() order and the
 - * remaining entries are unsorted.
 - *
 - * Loose references are read lazily, one directory at a time.  When a
 - * directory of loose references is read, then all of the references
 - * in that directory are stored, and REF_INCOMPLETE stubs are created
 - * for any subdirectories, but the subdirectories themselves are not
 - * read.  The reading is triggered by get_ref_dir().
 - */
 -struct ref_dir {
 -      int nr, alloc;
 -
 -      /*
 -       * Entries with index 0 <= i < sorted are sorted by name.  New
 -       * entries are appended to the list unsorted, and are sorted
 -       * only when required; thus we avoid the need to sort the list
 -       * after the addition of every reference.
 -       */
 -      int sorted;
 -
 -      /* A pointer to the files_ref_store that contains this ref_dir. */
 -      struct files_ref_store *ref_store;
 -
 -      struct ref_entry **entries;
 -};
 -
 -/*
 - * Bit values for ref_entry::flag.  REF_ISSYMREF=0x01,
 - * REF_ISPACKED=0x02, REF_ISBROKEN=0x04 and REF_BAD_NAME=0x08 are
 - * public values; see refs.h.
 - */
 -
 -/*
 - * The field ref_entry->u.value.peeled of this value entry contains
 - * the correct peeled value for the reference, which might be
 - * null_sha1 if the reference is not a tag or if it is broken.
 - */
 -#define REF_KNOWS_PEELED 0x10
 -
 -/* ref_entry represents a directory of references */
 -#define REF_DIR 0x20
 -
 -/*
 - * Entry has not yet been read from disk (used only for REF_DIR
 - * entries representing loose references)
 - */
 -#define REF_INCOMPLETE 0x40
 -
 -/*
 - * A ref_entry represents either a reference or a "subdirectory" of
 - * references.
 - *
 - * Each directory in the reference namespace is represented by a
 - * ref_entry with (flags & REF_DIR) set and containing a subdir member
 - * that holds the entries in that directory that have been read so
 - * far.  If (flags & REF_INCOMPLETE) is set, then the directory and
 - * its subdirectories haven't been read yet.  REF_INCOMPLETE is only
 - * used for loose reference directories.
 - *
 - * References are represented by a ref_entry with (flags & REF_DIR)
 - * unset and a value member that describes the reference's value.  The
 - * flag member is at the ref_entry level, but it is also needed to
 - * interpret the contents of the value field (in other words, a
 - * ref_value object is not very much use without the enclosing
 - * ref_entry).
 - *
 - * Reference names cannot end with slash and directories' names are
 - * always stored with a trailing slash (except for the top-level
 - * directory, which is always denoted by "").  This has two nice
 - * consequences: (1) when the entries in each subdir are sorted
 - * lexicographically by name (as they usually are), the references in
 - * a whole tree can be generated in lexicographic order by traversing
 - * the tree in left-to-right, depth-first order; (2) the names of
 - * references and subdirectories cannot conflict, and therefore the
 - * presence of an empty subdirectory does not block the creation of a
 - * similarly-named reference.  (The fact that reference names with the
 - * same leading components can conflict *with each other* is a
 - * separate issue that is regulated by verify_refname_available().)
 - *
 - * Please note that the name field contains the fully-qualified
 - * reference (or subdirectory) name.  Space could be saved by only
 - * storing the relative names.  But that would require the full names
 - * to be generated on the fly when iterating in do_for_each_ref(), and
 - * would break callback functions, who have always been able to assume
 - * that the name strings that they are passed will not be freed during
 - * the iteration.
 - */
 -struct ref_entry {
 -      unsigned char flag; /* ISSYMREF? ISPACKED? */
 -      union {
 -              struct ref_value value; /* if not (flags&REF_DIR) */
 -              struct ref_dir subdir; /* if (flags&REF_DIR) */
 -      } u;
 -      /*
 -       * The full name of the reference (e.g., "refs/heads/master")
 -       * or the full name of the directory with a trailing slash
 -       * (e.g., "refs/heads/"):
 -       */
 -      char name[FLEX_ARRAY];
 -};
 -
 -static void read_loose_refs(const char *dirname, struct ref_dir *dir);
 -static int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len);
 -static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store,
 -                                        const char *dirname, size_t len,
 -                                        int incomplete);
 -static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry);
 -static int files_log_ref_write(struct files_ref_store *refs,
 -                             const char *refname, const unsigned char *old_sha1,
 -                             const unsigned char *new_sha1, const char *msg,
 -                             int flags, struct strbuf *err);
 -
 -static struct ref_dir *get_ref_dir(struct ref_entry *entry)
 -{
 -      struct ref_dir *dir;
 -      assert(entry->flag & REF_DIR);
 -      dir = &entry->u.subdir;
 -      if (entry->flag & REF_INCOMPLETE) {
 -              read_loose_refs(entry->name, dir);
 -
 -              /*
 -               * Manually add refs/bisect, which, being
 -               * per-worktree, might not appear in the directory
 -               * listing for refs/ in the main repo.
 -               */
 -              if (!strcmp(entry->name, "refs/")) {
 -                      int pos = search_ref_dir(dir, "refs/bisect/", 12);
 -                      if (pos < 0) {
 -                              struct ref_entry *child_entry;
 -                              child_entry = create_dir_entry(dir->ref_store,
 -                                                             "refs/bisect/",
 -                                                             12, 1);
 -                              add_entry_to_dir(dir, child_entry);
 -                              read_loose_refs("refs/bisect",
 -                                              &child_entry->u.subdir);
 -                      }
 -              }
 -              entry->flag &= ~REF_INCOMPLETE;
 -      }
 -      return dir;
 -}
 -
 -static struct ref_entry *create_ref_entry(const char *refname,
 -                                        const unsigned char *sha1, int flag,
 -                                        int check_name)
 -{
 -      struct ref_entry *ref;
 -
 -      if (check_name &&
 -          check_refname_format(refname, REFNAME_ALLOW_ONELEVEL))
 -              die("Reference has invalid format: '%s'", refname);
 -      FLEX_ALLOC_STR(ref, name, refname);
 -      hashcpy(ref->u.value.oid.hash, sha1);
 -      oidclr(&ref->u.value.peeled);
 -      ref->flag = flag;
 -      return ref;
 -}
 -
 -static void clear_ref_dir(struct ref_dir *dir);
 -
 -static void free_ref_entry(struct ref_entry *entry)
 -{
 -      if (entry->flag & REF_DIR) {
 -              /*
 -               * Do not use get_ref_dir() here, as that might
 -               * trigger the reading of loose refs.
 -               */
 -              clear_ref_dir(&entry->u.subdir);
 -      }
 -      free(entry);
 -}
 -
 -/*
 - * Add a ref_entry to the end of dir (unsorted).  Entry is always
 - * stored directly in dir; no recursion into subdirectories is
 - * done.
 - */
 -static void add_entry_to_dir(struct ref_dir *dir, struct ref_entry *entry)
 -{
 -      ALLOC_GROW(dir->entries, dir->nr + 1, dir->alloc);
 -      dir->entries[dir->nr++] = entry;
 -      /* optimize for the case that entries are added in order */
 -      if (dir->nr == 1 ||
 -          (dir->nr == dir->sorted + 1 &&
 -           strcmp(dir->entries[dir->nr - 2]->name,
 -                  dir->entries[dir->nr - 1]->name) < 0))
 -              dir->sorted = dir->nr;
 -}
 -
 -/*
 - * Clear and free all entries in dir, recursively.
 - */
 -static void clear_ref_dir(struct ref_dir *dir)
 -{
 -      int i;
 -      for (i = 0; i < dir->nr; i++)
 -              free_ref_entry(dir->entries[i]);
 -      free(dir->entries);
 -      dir->sorted = dir->nr = dir->alloc = 0;
 -      dir->entries = NULL;
 -}
 -
 -/*
 - * Create a struct ref_entry object for the specified dirname.
 - * dirname is the name of the directory with a trailing slash (e.g.,
 - * "refs/heads/") or "" for the top-level directory.
 - */
 -static struct ref_entry *create_dir_entry(struct files_ref_store *ref_store,
 -                                        const char *dirname, size_t len,
 -                                        int incomplete)
 -{
 -      struct ref_entry *direntry;
 -      FLEX_ALLOC_MEM(direntry, name, dirname, len);
 -      direntry->u.subdir.ref_store = ref_store;
 -      direntry->flag = REF_DIR | (incomplete ? REF_INCOMPLETE : 0);
 -      return direntry;
 -}
 -
 -static int ref_entry_cmp(const void *a, const void *b)
 -{
 -      struct ref_entry *one = *(struct ref_entry **)a;
 -      struct ref_entry *two = *(struct ref_entry **)b;
 -      return strcmp(one->name, two->name);
 -}
 -
 -static void sort_ref_dir(struct ref_dir *dir);
 -
 -struct string_slice {
 -      size_t len;
 -      const char *str;
 -};
 -
 -static int ref_entry_cmp_sslice(const void *key_, const void *ent_)
 -{
 -      const struct string_slice *key = key_;
 -      const struct ref_entry *ent = *(const struct ref_entry * const *)ent_;
 -      int cmp = strncmp(key->str, ent->name, key->len);
 -      if (cmp)
 -              return cmp;
 -      return '\0' - (unsigned char)ent->name[key->len];
 -}
 -
 -/*
 - * Return the index of the entry with the given refname from the
 - * ref_dir (non-recursively), sorting dir if necessary.  Return -1 if
 - * no such entry is found.  dir must already be complete.
 - */
 -static int search_ref_dir(struct ref_dir *dir, const char *refname, size_t len)
 -{
 -      struct ref_entry **r;
 -      struct string_slice key;
 -
 -      if (refname == NULL || !dir->nr)
 -              return -1;
 -
 -      sort_ref_dir(dir);
 -      key.len = len;
 -      key.str = refname;
 -      r = bsearch(&key, dir->entries, dir->nr, sizeof(*dir->entries),
 -                  ref_entry_cmp_sslice);
 -
 -      if (r == NULL)
 -              return -1;
 -
 -      return r - dir->entries;
 -}
 -
 -/*
 - * Search for a directory entry directly within dir (without
 - * recursing).  Sort dir if necessary.  subdirname must be a directory
 - * name (i.e., end in '/').  If mkdir is set, then create the
 - * directory if it is missing; otherwise, return NULL if the desired
 - * directory cannot be found.  dir must already be complete.
 - */
 -static struct ref_dir *search_for_subdir(struct ref_dir *dir,
 -                                       const char *subdirname, size_t len,
 -                                       int mkdir)
 -{
 -      int entry_index = search_ref_dir(dir, subdirname, len);
 -      struct ref_entry *entry;
 -      if (entry_index == -1) {
 -              if (!mkdir)
 -                      return NULL;
 -              /*
 -               * Since dir is complete, the absence of a subdir
 -               * means that the subdir really doesn't exist;
 -               * therefore, create an empty record for it but mark
 -               * the record complete.
 -               */
 -              entry = create_dir_entry(dir->ref_store, subdirname, len, 0);
 -              add_entry_to_dir(dir, entry);
 -      } else {
 -              entry = dir->entries[entry_index];
 -      }
 -      return get_ref_dir(entry);
 -}
 -
 -/*
 - * If refname is a reference name, find the ref_dir within the dir
 - * tree that should hold refname.  If refname is a directory name
 - * (i.e., ends in '/'), then return that ref_dir itself.  dir must
 - * represent the top-level directory and must already be complete.
 - * Sort ref_dirs and recurse into subdirectories as necessary.  If
 - * mkdir is set, then create any missing directories; otherwise,
 - * return NULL if the desired directory cannot be found.
 - */
 -static struct ref_dir *find_containing_dir(struct ref_dir *dir,
 -                                         const char *refname, int mkdir)
 -{
 -      const char *slash;
 -      for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
 -              size_t dirnamelen = slash - refname + 1;
 -              struct ref_dir *subdir;
 -              subdir = search_for_subdir(dir, refname, dirnamelen, mkdir);
 -              if (!subdir) {
 -                      dir = NULL;
 -                      break;
 -              }
 -              dir = subdir;
 -      }
 -
 -      return dir;
 -}
 -
 -/*
 - * Find the value entry with the given name in dir, sorting ref_dirs
 - * and recursing into subdirectories as necessary.  If the name is not
 - * found or it corresponds to a directory entry, return NULL.
 - */
 -static struct ref_entry *find_ref(struct ref_dir *dir, const char *refname)
 -{
 -      int entry_index;
 -      struct ref_entry *entry;
 -      dir = find_containing_dir(dir, refname, 0);
 -      if (!dir)
 -              return NULL;
 -      entry_index = search_ref_dir(dir, refname, strlen(refname));
 -      if (entry_index == -1)
 -              return NULL;
 -      entry = dir->entries[entry_index];
 -      return (entry->flag & REF_DIR) ? NULL : entry;
 -}
 -
 -/*
 - * Remove the entry with the given name from dir, recursing into
 - * subdirectories as necessary.  If refname is the name of a directory
 - * (i.e., ends with '/'), then remove the directory and its contents.
 - * If the removal was successful, return the number of entries
 - * remaining in the directory entry that contained the deleted entry.
 - * If the name was not found, return -1.  Please note that this
 - * function only deletes the entry from the cache; it does not delete
 - * it from the filesystem or ensure that other cache entries (which
 - * might be symbolic references to the removed entry) are updated.
 - * Nor does it remove any containing dir entries that might be made
 - * empty by the removal.  dir must represent the top-level directory
 - * and must already be complete.
 - */
 -static int remove_entry(struct ref_dir *dir, const char *refname)
 -{
 -      int refname_len = strlen(refname);
 -      int entry_index;
 -      struct ref_entry *entry;
 -      int is_dir = refname[refname_len - 1] == '/';
 -      if (is_dir) {
 -              /*
 -               * refname represents a reference directory.  Remove
 -               * the trailing slash; otherwise we will get the
 -               * directory *representing* refname rather than the
 -               * one *containing* it.
 -               */
 -              char *dirname = xmemdupz(refname, refname_len - 1);
 -              dir = find_containing_dir(dir, dirname, 0);
 -              free(dirname);
 -      } else {
 -              dir = find_containing_dir(dir, refname, 0);
 -      }
 -      if (!dir)
 -              return -1;
 -      entry_index = search_ref_dir(dir, refname, refname_len);
 -      if (entry_index == -1)
 -              return -1;
 -      entry = dir->entries[entry_index];
 -
 -      memmove(&dir->entries[entry_index],
 -              &dir->entries[entry_index + 1],
 -              (dir->nr - entry_index - 1) * sizeof(*dir->entries)
 -              );
 -      dir->nr--;
 -      if (dir->sorted > entry_index)
 -              dir->sorted--;
 -      free_ref_entry(entry);
 -      return dir->nr;
 -}
 -
 -/*
 - * Add a ref_entry to the ref_dir (unsorted), recursing into
 - * subdirectories as necessary.  dir must represent the top-level
 - * directory.  Return 0 on success.
 - */
 -static int add_ref(struct ref_dir *dir, struct ref_entry *ref)
 -{
 -      dir = find_containing_dir(dir, ref->name, 1);
 -      if (!dir)
 -              return -1;
 -      add_entry_to_dir(dir, ref);
 -      return 0;
 -}
 -
 -/*
 - * Emit a warning and return true iff ref1 and ref2 have the same name
 - * and the same sha1.  Die if they have the same name but different
 - * sha1s.
 - */
 -static int is_dup_ref(const struct ref_entry *ref1, const struct ref_entry *ref2)
 -{
 -      if (strcmp(ref1->name, ref2->name))
 -              return 0;
 -
 -      /* Duplicate name; make sure that they don't conflict: */
 -
 -      if ((ref1->flag & REF_DIR) || (ref2->flag & REF_DIR))
 -              /* This is impossible by construction */
 -              die("Reference directory conflict: %s", ref1->name);
 -
 -      if (oidcmp(&ref1->u.value.oid, &ref2->u.value.oid))
 -              die("Duplicated ref, and SHA1s don't match: %s", ref1->name);
 -
 -      warning("Duplicated ref: %s", ref1->name);
 -      return 1;
 -}
 -
 -/*
 - * Sort the entries in dir non-recursively (if they are not already
 - * sorted) and remove any duplicate entries.
 - */
 -static void sort_ref_dir(struct ref_dir *dir)
 -{
 -      int i, j;
 -      struct ref_entry *last = NULL;
 -
 -      /*
 -       * This check also prevents passing a zero-length array to qsort(),
 -       * which is a problem on some platforms.
 -       */
 -      if (dir->sorted == dir->nr)
 -              return;
 -
 -      QSORT(dir->entries, dir->nr, ref_entry_cmp);
 -
 -      /* Remove any duplicates: */
 -      for (i = 0, j = 0; j < dir->nr; j++) {
 -              struct ref_entry *entry = dir->entries[j];
 -              if (last && is_dup_ref(last, entry))
 -                      free_ref_entry(entry);
 -              else
 -                      last = dir->entries[i++] = entry;
 -      }
 -      dir->sorted = dir->nr = i;
 -}
 -
  /*
   * Return true if refname, which has the specified oid and flags, can
   * be resolved to an object in the database. If the referred-to object
@@@ -32,8 -536,358 +32,8 @@@ static int ref_resolves_to_object(cons
        return 1;
  }
  
 -/*
 - * Return true if the reference described by entry can be resolved to
 - * an object in the database; otherwise, emit a warning and return
 - * false.
 - */
 -static int entry_resolves_to_object(struct ref_entry *entry)
 -{
 -      return ref_resolves_to_object(entry->name,
 -                                    &entry->u.value.oid, entry->flag);
 -}
 -
 -typedef int each_ref_entry_fn(struct ref_entry *entry, void *cb_data);
 -
 -/*
 - * Call fn for each reference in dir that has index in the range
 - * offset <= index < dir->nr.  Recurse into subdirectories that are in
 - * that index range, sorting them before iterating.  This function
 - * does not sort dir itself; it should be sorted beforehand.  fn is
 - * called for all references, including broken ones.
 - */
 -static int do_for_each_entry_in_dir(struct ref_dir *dir, int offset,
 -                                  each_ref_entry_fn fn, void *cb_data)
 -{
 -      int i;
 -      assert(dir->sorted == dir->nr);
 -      for (i = offset; i < dir->nr; i++) {
 -              struct ref_entry *entry = dir->entries[i];
 -              int retval;
 -              if (entry->flag & REF_DIR) {
 -                      struct ref_dir *subdir = get_ref_dir(entry);
 -                      sort_ref_dir(subdir);
 -                      retval = do_for_each_entry_in_dir(subdir, 0, fn, cb_data);
 -              } else {
 -                      retval = fn(entry, cb_data);
 -              }
 -              if (retval)
 -                      return retval;
 -      }
 -      return 0;
 -}
 -
 -/*
 - * Load all of the refs from the dir into our in-memory cache. The hard work
 - * of loading loose refs is done by get_ref_dir(), so we just need to recurse
 - * through all of the sub-directories. We do not even need to care about
 - * sorting, as traversal order does not matter to us.
 - */
 -static void prime_ref_dir(struct ref_dir *dir)
 -{
 -      int i;
 -      for (i = 0; i < dir->nr; i++) {
 -              struct ref_entry *entry = dir->entries[i];
 -              if (entry->flag & REF_DIR)
 -                      prime_ref_dir(get_ref_dir(entry));
 -      }
 -}
 -
 -/*
 - * A level in the reference hierarchy that is currently being iterated
 - * through.
 - */
 -struct cache_ref_iterator_level {
 -      /*
 -       * The ref_dir being iterated over at this level. The ref_dir
 -       * is sorted before being stored here.
 -       */
 -      struct ref_dir *dir;
 -
 -      /*
 -       * The index of the current entry within dir (which might
 -       * itself be a directory). If index == -1, then the iteration
 -       * hasn't yet begun. If index == dir->nr, then the iteration
 -       * through this level is over.
 -       */
 -      int index;
 -};
 -
 -/*
 - * Represent an iteration through a ref_dir in the memory cache. The
 - * iteration recurses through subdirectories.
 - */
 -struct cache_ref_iterator {
 -      struct ref_iterator base;
 -
 -      /*
 -       * The number of levels currently on the stack. This is always
 -       * at least 1, because when it becomes zero the iteration is
 -       * ended and this struct is freed.
 -       */
 -      size_t levels_nr;
 -
 -      /* The number of levels that have been allocated on the stack */
 -      size_t levels_alloc;
 -
 -      /*
 -       * A stack of levels. levels[0] is the uppermost level that is
 -       * being iterated over in this iteration. (This is not
 -       * necessary the top level in the references hierarchy. If we
 -       * are iterating through a subtree, then levels[0] will hold
 -       * the ref_dir for that subtree, and subsequent levels will go
 -       * on from there.)
 -       */
 -      struct cache_ref_iterator_level *levels;
 -};
 -
 -static int cache_ref_iterator_advance(struct ref_iterator *ref_iterator)
 -{
 -      struct cache_ref_iterator *iter =
 -              (struct cache_ref_iterator *)ref_iterator;
 -
 -      while (1) {
 -              struct cache_ref_iterator_level *level =
 -                      &iter->levels[iter->levels_nr - 1];
 -              struct ref_dir *dir = level->dir;
 -              struct ref_entry *entry;
 -
 -              if (level->index == -1)
 -                      sort_ref_dir(dir);
 -
 -              if (++level->index == level->dir->nr) {
 -                      /* This level is exhausted; pop up a level */
 -                      if (--iter->levels_nr == 0)
 -                              return ref_iterator_abort(ref_iterator);
 -
 -                      continue;
 -              }
 -
 -              entry = dir->entries[level->index];
 -
 -              if (entry->flag & REF_DIR) {
 -                      /* push down a level */
 -                      ALLOC_GROW(iter->levels, iter->levels_nr + 1,
 -                                 iter->levels_alloc);
 -
 -                      level = &iter->levels[iter->levels_nr++];
 -                      level->dir = get_ref_dir(entry);
 -                      level->index = -1;
 -              } else {
 -                      iter->base.refname = entry->name;
 -                      iter->base.oid = &entry->u.value.oid;
 -                      iter->base.flags = entry->flag;
 -                      return ITER_OK;
 -              }
 -      }
 -}
 -
 -static enum peel_status peel_entry(struct ref_entry *entry, int repeel);
 -
 -static int cache_ref_iterator_peel(struct ref_iterator *ref_iterator,
 -                                 struct object_id *peeled)
 -{
 -      struct cache_ref_iterator *iter =
 -              (struct cache_ref_iterator *)ref_iterator;
 -      struct cache_ref_iterator_level *level;
 -      struct ref_entry *entry;
 -
 -      level = &iter->levels[iter->levels_nr - 1];
 -
 -      if (level->index == -1)
 -              die("BUG: peel called before advance for cache iterator");
 -
 -      entry = level->dir->entries[level->index];
 -
 -      if (peel_entry(entry, 0))
 -              return -1;
 -      oidcpy(peeled, &entry->u.value.peeled);
 -      return 0;
 -}
 -
 -static int cache_ref_iterator_abort(struct ref_iterator *ref_iterator)
 -{
 -      struct cache_ref_iterator *iter =
 -              (struct cache_ref_iterator *)ref_iterator;
 -
 -      free(iter->levels);
 -      base_ref_iterator_free(ref_iterator);
 -      return ITER_DONE;
 -}
 -
 -static struct ref_iterator_vtable cache_ref_iterator_vtable = {
 -      cache_ref_iterator_advance,
 -      cache_ref_iterator_peel,
 -      cache_ref_iterator_abort
 -};
 -
 -static struct ref_iterator *cache_ref_iterator_begin(struct ref_dir *dir)
 -{
 -      struct cache_ref_iterator *iter;
 -      struct ref_iterator *ref_iterator;
 -      struct cache_ref_iterator_level *level;
 -
 -      iter = xcalloc(1, sizeof(*iter));
 -      ref_iterator = &iter->base;
 -      base_ref_iterator_init(ref_iterator, &cache_ref_iterator_vtable);
 -      ALLOC_GROW(iter->levels, 10, iter->levels_alloc);
 -
 -      iter->levels_nr = 1;
 -      level = &iter->levels[0];
 -      level->index = -1;
 -      level->dir = dir;
 -
 -      return ref_iterator;
 -}
 -
 -struct nonmatching_ref_data {
 -      const struct string_list *skip;
 -      const char *conflicting_refname;
 -};
 -
 -static int nonmatching_ref_fn(struct ref_entry *entry, void *vdata)
 -{
 -      struct nonmatching_ref_data *data = vdata;
 -
 -      if (data->skip && string_list_has_string(data->skip, entry->name))
 -              return 0;
 -
 -      data->conflicting_refname = entry->name;
 -      return 1;
 -}
 -
 -/*
 - * Return 0 if a reference named refname could be created without
 - * conflicting with the name of an existing reference in dir.
 - * See verify_refname_available for more information.
 - */
 -static int verify_refname_available_dir(const char *refname,
 -                                      const struct string_list *extras,
 -                                      const struct string_list *skip,
 -                                      struct ref_dir *dir,
 -                                      struct strbuf *err)
 -{
 -      const char *slash;
 -      const char *extra_refname;
 -      int pos;
 -      struct strbuf dirname = STRBUF_INIT;
 -      int ret = -1;
 -
 -      /*
 -       * For the sake of comments in this function, suppose that
 -       * refname is "refs/foo/bar".
 -       */
 -
 -      assert(err);
 -
 -      strbuf_grow(&dirname, strlen(refname) + 1);
 -      for (slash = strchr(refname, '/'); slash; slash = strchr(slash + 1, '/')) {
 -              /* Expand dirname to the new prefix, not including the trailing slash: */
 -              strbuf_add(&dirname, refname + dirname.len, slash - refname - dirname.len);
 -
 -              /*
 -               * We are still at a leading dir of the refname (e.g.,
 -               * "refs/foo"; if there is a reference with that name,
 -               * it is a conflict, *unless* it is in skip.
 -               */
 -              if (dir) {
 -                      pos = search_ref_dir(dir, dirname.buf, dirname.len);
 -                      if (pos >= 0 &&
 -                          (!skip || !string_list_has_string(skip, dirname.buf))) {
 -                              /*
 -                               * We found a reference whose name is
 -                               * a proper prefix of refname; e.g.,
 -                               * "refs/foo", and is not in skip.
 -                               */
 -                              strbuf_addf(err, "'%s' exists; cannot create '%s'",
 -                                          dirname.buf, refname);
 -                              goto cleanup;
 -                      }
 -              }
 -
 -              if (extras && string_list_has_string(extras, dirname.buf) &&
 -                  (!skip || !string_list_has_string(skip, dirname.buf))) {
 -                      strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
 -                                  refname, dirname.buf);
 -                      goto cleanup;
 -              }
 -
 -              /*
 -               * Otherwise, we can try to continue our search with
 -               * the next component. So try to look up the
 -               * directory, e.g., "refs/foo/". If we come up empty,
 -               * we know there is nothing under this whole prefix,
 -               * but even in that case we still have to continue the
 -               * search for conflicts with extras.
 -               */
 -              strbuf_addch(&dirname, '/');
 -              if (dir) {
 -                      pos = search_ref_dir(dir, dirname.buf, dirname.len);
 -                      if (pos < 0) {
 -                              /*
 -                               * There was no directory "refs/foo/",
 -                               * so there is nothing under this
 -                               * whole prefix. So there is no need
 -                               * to continue looking for conflicting
 -                               * references. But we need to continue
 -                               * looking for conflicting extras.
 -                               */
 -                              dir = NULL;
 -                      } else {
 -                              dir = get_ref_dir(dir->entries[pos]);
 -                      }
 -              }
 -      }
 -
 -      /*
 -       * We are at the leaf of our refname (e.g., "refs/foo/bar").
 -       * There is no point in searching for a reference with that
 -       * name, because a refname isn't considered to conflict with
 -       * itself. But we still need to check for references whose
 -       * names are in the "refs/foo/bar/" namespace, because they
 -       * *do* conflict.
 -       */
 -      strbuf_addstr(&dirname, refname + dirname.len);
 -      strbuf_addch(&dirname, '/');
 -
 -      if (dir) {
 -              pos = search_ref_dir(dir, dirname.buf, dirname.len);
 -
 -              if (pos >= 0) {
 -                      /*
 -                       * We found a directory named "$refname/"
 -                       * (e.g., "refs/foo/bar/"). It is a problem
 -                       * iff it contains any ref that is not in
 -                       * "skip".
 -                       */
 -                      struct nonmatching_ref_data data;
 -
 -                      data.skip = skip;
 -                      data.conflicting_refname = NULL;
 -                      dir = get_ref_dir(dir->entries[pos]);
 -                      sort_ref_dir(dir);
 -                      if (do_for_each_entry_in_dir(dir, 0, nonmatching_ref_fn, &data)) {
 -                              strbuf_addf(err, "'%s' exists; cannot create '%s'",
 -                                          data.conflicting_refname, refname);
 -                              goto cleanup;
 -                      }
 -              }
 -      }
 -
 -      extra_refname = find_descendant_ref(dirname.buf, extras, skip);
 -      if (extra_refname)
 -              strbuf_addf(err, "cannot process '%s' and '%s' at the same time",
 -                          refname, extra_refname);
 -      else
 -              ret = 0;
 -
 -cleanup:
 -      strbuf_release(&dirname);
 -      return ret;
 -}
 -
  struct packed_ref_cache {
 -      struct ref_entry *root;
 +      struct ref_cache *cache;
  
        /*
         * Count of references to the data structure in this instance,
@@@ -68,7 -922,7 +68,7 @@@ struct files_ref_store 
        char *gitcommondir;
        char *packed_refs_path;
  
 -      struct ref_entry *loose;
 +      struct ref_cache *loose;
        struct packed_ref_cache *packed;
  };
  
@@@ -90,7 -944,7 +90,7 @@@ static void acquire_packed_ref_cache(st
  static int release_packed_ref_cache(struct packed_ref_cache *packed_refs)
  {
        if (!--packed_refs->referrers) {
 -              free_ref_entry(packed_refs->root);
 +              free_ref_cache(packed_refs->cache);
                stat_validity_clear(&packed_refs->validity);
                free(packed_refs);
                return 1;
@@@ -114,7 -968,7 +114,7 @@@ static void clear_packed_ref_cache(stru
  static void clear_loose_ref_cache(struct files_ref_store *refs)
  {
        if (refs->loose) {
 -              free_ref_entry(refs->loose);
 +              free_ref_cache(refs->loose);
                refs->loose = NULL;
        }
  }
@@@ -287,7 -1141,7 +287,7 @@@ static void read_packed_refs(FILE *f, s
                        if (peeled == PEELED_FULLY ||
                            (peeled == PEELED_TAGS && starts_with(refname, "refs/tags/")))
                                last->flag |= REF_KNOWS_PEELED;
 -                      add_ref(dir, last);
 +                      add_ref_entry(dir, last);
                        continue;
                }
                if (last &&
@@@ -375,12 -1229,11 +375,12 @@@ static struct packed_ref_cache *get_pac
  
                refs->packed = xcalloc(1, sizeof(*refs->packed));
                acquire_packed_ref_cache(refs->packed);
 -              refs->packed->root = create_dir_entry(refs, "", 0, 0);
 +              refs->packed->cache = create_ref_cache(&refs->base, NULL);
 +              refs->packed->cache->root->flag &= ~REF_INCOMPLETE;
                f = fopen(packed_refs_file, "r");
                if (f) {
                        stat_validity_update(&refs->packed->validity, fileno(f));
 -                      read_packed_refs(f, get_ref_dir(refs->packed->root));
 +                      read_packed_refs(f, get_ref_dir(refs->packed->cache->root));
                        fclose(f);
                }
        }
  
  static struct ref_dir *get_packed_ref_dir(struct packed_ref_cache *packed_ref_cache)
  {
 -      return get_ref_dir(packed_ref_cache->root);
 +      return get_ref_dir(packed_ref_cache->cache->root);
  }
  
  static struct ref_dir *get_packed_refs(struct files_ref_store *refs)
@@@ -410,8 -1263,8 +410,8 @@@ static void add_packed_ref(struct files
  
        if (!packed_ref_cache->lock)
                die("internal error: packed refs not locked");
 -      add_ref(get_packed_ref_dir(packed_ref_cache),
 -              create_ref_entry(refname, sha1, REF_ISPACKED, 1));
 +      add_ref_entry(get_packed_ref_dir(packed_ref_cache),
 +                    create_ref_entry(refname, sha1, REF_ISPACKED, 1));
  }
  
  /*
   * (without recursing).  dirname must end with '/'.  dir must be the
   * directory entry corresponding to dirname.
   */
 -static void read_loose_refs(const char *dirname, struct ref_dir *dir)
 +static void loose_fill_ref_dir(struct ref_store *ref_store,
 +                             struct ref_dir *dir, const char *dirname)
  {
 -      struct files_ref_store *refs = dir->ref_store;
 +      struct files_ref_store *refs =
 +              files_downcast(ref_store, REF_STORE_READ, "fill_ref_dir");
        DIR *d;
        struct dirent *de;
        int dirnamelen = strlen(dirname);
                } else if (S_ISDIR(st.st_mode)) {
                        strbuf_addch(&refname, '/');
                        add_entry_to_dir(dir,
 -                                       create_dir_entry(refs, refname.buf,
 +                                       create_dir_entry(dir->cache, refname.buf,
                                                          refname.len, 1));
                } else {
                        if (!refs_resolve_ref_unsafe(&refs->base,
        strbuf_release(&refname);
        strbuf_release(&path);
        closedir(d);
 +
 +      /*
 +       * Manually add refs/bisect, which, being per-worktree, might
 +       * not appear in the directory listing for refs/ in the main
 +       * repo.
 +       */
 +      if (!strcmp(dirname, "refs/")) {
 +              int pos = search_ref_dir(dir, "refs/bisect/", 12);
 +
 +              if (pos < 0) {
 +                      struct ref_entry *child_entry = create_dir_entry(
 +                                      dir->cache, "refs/bisect/", 12, 1);
 +                      add_entry_to_dir(dir, child_entry);
 +              }
 +      }
  }
  
 -static struct ref_dir *get_loose_refs(struct files_ref_store *refs)
 +static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)
  {
        if (!refs->loose) {
                /*
                 * are about to read the only subdirectory that can
                 * hold references:
                 */
 -              refs->loose = create_dir_entry(refs, "", 0, 0);
 +              refs->loose = create_ref_cache(&refs->base, loose_fill_ref_dir);
 +
 +              /* We're going to fill the top level ourselves: */
 +              refs->loose->root->flag &= ~REF_INCOMPLETE;
 +
                /*
 -               * Create an incomplete entry for "refs/":
 +               * Add an incomplete entry for "refs/" (to be filled
 +               * lazily):
                 */
 -              add_entry_to_dir(get_ref_dir(refs->loose),
 -                               create_dir_entry(refs, "refs/", 5, 1));
 +              add_entry_to_dir(get_ref_dir(refs->loose->root),
 +                               create_dir_entry(refs->loose, "refs/", 5, 1));
        }
 -      return get_ref_dir(refs->loose);
 +      return refs->loose;
  }
  
  /*
  static struct ref_entry *get_packed_ref(struct files_ref_store *refs,
                                        const char *refname)
  {
 -      return find_ref(get_packed_refs(refs), refname);
 +      return find_ref_entry(get_packed_refs(refs), refname);
  }
  
  /*
@@@ -733,7 -1564,7 +733,7 @@@ static void unlock_ref(struct ref_lock 
   *
   * If the reference doesn't already exist, verify that refname doesn't
   * have a D/F conflict with any existing references. extras and skip
 - * are passed to verify_refname_available_dir() for this check.
 + * are passed to refs_verify_refname_available() for this check.
   *
   * If mustexist is not set and the reference is not found or is
   * broken, lock the reference anyway but clear sha1.
   *
   * but it includes a lot more code to
   * - Deal with possible races with other processes
 - * - Avoid calling verify_refname_available_dir() when it can be
 + * - Avoid calling refs_verify_refname_available() when it can be
   *   avoided, namely if we were successfully able to read the ref
   * - Generate informative error messages in the case of failure
   */
@@@ -805,8 -1636,7 +805,8 @@@ retry
                        } else {
                                /*
                                 * The error message set by
 -                               * verify_refname_available_dir() is OK.
 +                               * refs_verify_refname_available() is
 +                               * OK.
                                 */
                                ret = TRANSACTION_NAME_CONFLICT;
                        }
                                goto error_return;
                        } else if (remove_dir_recursively(&ref_file,
                                                          REMOVE_DIR_EMPTY_ONLY)) {
 -                              if (verify_refname_available_dir(
 -                                                  refname, extras, skip,
 -                                                  get_loose_refs(refs),
 -                                                  err)) {
 +                              if (refs_verify_refname_available(
 +                                                  &refs->base, refname,
 +                                                  extras, skip, err)) {
                                        /*
                                         * The error message set by
                                         * verify_refname_available() is OK.
  
                /*
                 * If the ref did not exist and we are creating it,
 -               * make sure there is no existing packed ref whose
 -               * name begins with our refname, nor a packed ref
 -               * whose name is a proper prefix of our refname.
 +               * make sure there is no existing ref that conflicts
 +               * with refname:
                 */
 -              if (verify_refname_available_dir(
 -                                  refname, extras, skip,
 -                                  get_packed_refs(refs),
 -                                  err)) {
 +              if (refs_verify_refname_available(
 +                                  &refs->base, refname,
 +                                  extras, skip, err))
                        goto error_return;
 -              }
        }
  
        ret = 0;
@@@ -951,6 -1785,41 +951,6 @@@ out
        return ret;
  }
  
 -/*
 - * Peel the entry (if possible) and return its new peel_status.  If
 - * repeel is true, re-peel the entry even if there is an old peeled
 - * value that is already stored in it.
 - *
 - * It is OK to call this function with a packed reference entry that
 - * might be stale and might even refer to an object that has since
 - * been garbage-collected.  In such a case, if the entry has
 - * REF_KNOWS_PEELED then leave the status unchanged and return
 - * PEEL_PEELED or PEEL_NON_TAG; otherwise, return PEEL_INVALID.
 - */
 -static enum peel_status peel_entry(struct ref_entry *entry, int repeel)
 -{
 -      enum peel_status status;
 -
 -      if (entry->flag & REF_KNOWS_PEELED) {
 -              if (repeel) {
 -                      entry->flag &= ~REF_KNOWS_PEELED;
 -                      oidclr(&entry->u.value.peeled);
 -              } else {
 -                      return is_null_oid(&entry->u.value.peeled) ?
 -                              PEEL_NON_TAG : PEEL_PEELED;
 -              }
 -      }
 -      if (entry->flag & REF_ISBROKEN)
 -              return PEEL_BROKEN;
 -      if (entry->flag & REF_ISSYMREF)
 -              return PEEL_IS_SYMREF;
 -
 -      status = peel_object(entry->u.value.oid.hash, entry->u.value.peeled.hash);
 -      if (status == PEEL_PEELED || status == PEEL_NON_TAG)
 -              entry->flag |= REF_KNOWS_PEELED;
 -      return status;
 -}
 -
  static int files_peel_ref(struct ref_store *ref_store,
                          const char *refname, unsigned char *sha1)
  {
@@@ -1066,6 -1935,7 +1066,6 @@@ static struct ref_iterator *files_ref_i
                const char *prefix, unsigned int flags)
  {
        struct files_ref_store *refs;
 -      struct ref_dir *loose_dir, *packed_dir;
        struct ref_iterator *loose_iter, *packed_iter;
        struct files_ref_iterator *iter;
        struct ref_iterator *ref_iterator;
         * condition if loose refs are migrated to the packed-refs
         * file by a simultaneous process, but our in-memory view is
         * from before the migration. We ensure this as follows:
 -       * First, we call prime_ref_dir(), which pre-reads the loose
 -       * references for the subtree into the cache. (If they've
 -       * already been read, that's OK; we only need to guarantee
 -       * that they're read before the packed refs, not *how much*
 -       * before.) After that, we call get_packed_ref_cache(), which
 -       * internally checks whether the packed-ref cache is up to
 -       * date with what is on disk, and re-reads it if not.
 +       * First, we call start the loose refs iteration with its
 +       * `prime_ref` argument set to true. This causes the loose
 +       * references in the subtree to be pre-read into the cache.
 +       * (If they've already been read, that's OK; we only need to
 +       * guarantee that they're read before the packed refs, not
 +       * *how much* before.) After that, we call
 +       * get_packed_ref_cache(), which internally checks whether the
 +       * packed-ref cache is up to date with what is on disk, and
 +       * re-reads it if not.
         */
  
 -      loose_dir = get_loose_refs(refs);
 -
 -      if (prefix && *prefix)
 -              loose_dir = find_containing_dir(loose_dir, prefix, 0);
 -
 -      if (loose_dir) {
 -              prime_ref_dir(loose_dir);
 -              loose_iter = cache_ref_iterator_begin(loose_dir);
 -      } else {
 -              /* There's nothing to iterate over. */
 -              loose_iter = empty_ref_iterator_begin();
 -      }
 +      loose_iter = cache_ref_iterator_begin(get_loose_ref_cache(refs),
 +                                            prefix, 1);
  
        iter->packed_ref_cache = get_packed_ref_cache(refs);
        acquire_packed_ref_cache(iter->packed_ref_cache);
 -      packed_dir = get_packed_ref_dir(iter->packed_ref_cache);
 -
 -      if (prefix && *prefix)
 -              packed_dir = find_containing_dir(packed_dir, prefix, 0);
 -
 -      if (packed_dir) {
 -              packed_iter = cache_ref_iterator_begin(packed_dir);
 -      } else {
 -              /* There's nothing to iterate over. */
 -              packed_iter = empty_ref_iterator_begin();
 -      }
 +      packed_iter = cache_ref_iterator_begin(iter->packed_ref_cache->cache,
 +                                             prefix, 0);
  
        iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter);
        iter->flags = flags;
@@@ -1209,9 -2096,9 +1209,9 @@@ static struct ref_lock *lock_ref_sha1_b
                 */
                if (remove_empty_directories(&ref_file)) {
                        last_errno = errno;
 -                      if (!verify_refname_available_dir(
 -                                          refname, extras, skip,
 -                                          get_loose_refs(refs), err))
 +                      if (!refs_verify_refname_available(
 +                                          &refs->base,
 +                                          refname, extras, skip, err))
                                strbuf_addf(err, "there are still refs under '%s'",
                                            refname);
                        goto error_return;
        if (!resolved) {
                last_errno = errno;
                if (last_errno != ENOTDIR ||
 -                  !verify_refname_available_dir(
 -                                  refname, extras, skip,
 -                                  get_loose_refs(refs), err))
 +                  !refs_verify_refname_available(&refs->base, refname,
 +                                                 extras, skip, err))
                        strbuf_addf(err, "unable to resolve reference '%s': %s",
                                    refname, strerror(last_errno));
  
         * our refname.
         */
        if (is_null_oid(&lock->old_oid) &&
 -          verify_refname_available_dir(refname, extras, skip,
 -                                       get_packed_refs(refs),
 -                                       err)) {
 +          refs_verify_refname_available(&refs->base, refname,
 +                                        extras, skip, err)) {
                last_errno = ENOTDIR;
                goto error_return;
        }
   * Write an entry to the packed-refs file for the specified refname.
   * If peeled is non-NULL, write it as the entry's peeled value.
   */
 -static void write_packed_entry(FILE *fh, char *refname, unsigned char *sha1,
 -                             unsigned char *peeled)
 +static void write_packed_entry(FILE *fh, const char *refname,
 +                             const unsigned char *sha1,
 +                             const unsigned char *peeled)
  {
        fprintf_or_die(fh, "%s %s\n", sha1_to_hex(sha1), refname);
        if (peeled)
                fprintf_or_die(fh, "^%s\n", sha1_to_hex(peeled));
  }
  
 -/*
 - * An each_ref_entry_fn that writes the entry to a packed-refs file.
 - */
 -static int write_packed_entry_fn(struct ref_entry *entry, void *cb_data)
 -{
 -      enum peel_status peel_status = peel_entry(entry, 0);
 -
 -      if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
 -              error("internal error: %s is not a valid packed reference!",
 -                    entry->name);
 -      write_packed_entry(cb_data, entry->name, entry->u.value.oid.hash,
 -                         peel_status == PEEL_PEELED ?
 -                         entry->u.value.peeled.hash : NULL);
 -      return 0;
 -}
 -
  /*
   * Lock the packed-refs file for writing. Flags is passed to
   * hold_lock_file_for_update(). Return 0 on success. On errors, set
@@@ -1328,10 -2232,9 +1328,10 @@@ static int commit_packed_refs(struct fi
  {
        struct packed_ref_cache *packed_ref_cache =
                get_packed_ref_cache(refs);
 -      int error = 0;
 +      int ok, error = 0;
        int save_errno = 0;
        FILE *out;
 +      struct ref_iterator *iter;
  
        files_assert_main_repository(refs, "commit_packed_refs");
  
                die_errno("unable to fdopen packed-refs descriptor");
  
        fprintf_or_die(out, "%s", PACKED_REFS_HEADER);
 -      do_for_each_entry_in_dir(get_packed_ref_dir(packed_ref_cache),
 -                               0, write_packed_entry_fn, out);
 +
 +      iter = cache_ref_iterator_begin(packed_ref_cache->cache, NULL, 0);
 +      while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
 +              struct object_id peeled;
 +              int peel_error = ref_iterator_peel(iter, &peeled);
 +
 +              write_packed_entry(out, iter->refname, iter->oid->hash,
 +                                 peel_error ? NULL : peeled.hash);
 +      }
 +
 +      if (ok != ITER_DONE)
 +              die("error while iterating over references");
  
        if (commit_lock_file(packed_ref_cache->lock)) {
                save_errno = errno;
@@@ -1392,6 -2285,65 +1392,6 @@@ struct ref_to_prune 
        char name[FLEX_ARRAY];
  };
  
 -struct pack_refs_cb_data {
 -      unsigned int flags;
 -      struct ref_dir *packed_refs;
 -      struct ref_to_prune *ref_to_prune;
 -};
 -
 -/*
 - * An each_ref_entry_fn that is run over loose references only.  If
 - * the loose reference can be packed, add an entry in the packed ref
 - * cache.  If the reference should be pruned, also add it to
 - * ref_to_prune in the pack_refs_cb_data.
 - */
 -static int pack_if_possible_fn(struct ref_entry *entry, void *cb_data)
 -{
 -      struct pack_refs_cb_data *cb = cb_data;
 -      enum peel_status peel_status;
 -      struct ref_entry *packed_entry;
 -      int is_tag_ref = starts_with(entry->name, "refs/tags/");
 -
 -      /* Do not pack per-worktree refs: */
 -      if (ref_type(entry->name) != REF_TYPE_NORMAL)
 -              return 0;
 -
 -      /* ALWAYS pack tags */
 -      if (!(cb->flags & PACK_REFS_ALL) && !is_tag_ref)
 -              return 0;
 -
 -      /* Do not pack symbolic or broken refs: */
 -      if ((entry->flag & REF_ISSYMREF) || !entry_resolves_to_object(entry))
 -              return 0;
 -
 -      /* Add a packed ref cache entry equivalent to the loose entry. */
 -      peel_status = peel_entry(entry, 1);
 -      if (peel_status != PEEL_PEELED && peel_status != PEEL_NON_TAG)
 -              die("internal error peeling reference %s (%s)",
 -                  entry->name, oid_to_hex(&entry->u.value.oid));
 -      packed_entry = find_ref(cb->packed_refs, entry->name);
 -      if (packed_entry) {
 -              /* Overwrite existing packed entry with info from loose entry */
 -              packed_entry->flag = REF_ISPACKED | REF_KNOWS_PEELED;
 -              oidcpy(&packed_entry->u.value.oid, &entry->u.value.oid);
 -      } else {
 -              packed_entry = create_ref_entry(entry->name, entry->u.value.oid.hash,
 -                                              REF_ISPACKED | REF_KNOWS_PEELED, 0);
 -              add_ref(cb->packed_refs, packed_entry);
 -      }
 -      oidcpy(&packed_entry->u.value.peeled, &entry->u.value.peeled);
 -
 -      /* Schedule the loose reference for pruning if requested. */
 -      if ((cb->flags & PACK_REFS_PRUNE)) {
 -              struct ref_to_prune *n;
 -              FLEX_ALLOC_STR(n, name, entry->name);
 -              hashcpy(n->sha1, entry->u.value.oid.hash);
 -              n->next = cb->ref_to_prune;
 -              cb->ref_to_prune = n;
 -      }
 -      return 0;
 -}
 -
  enum {
        REMOVE_EMPTY_PARENTS_REF = 0x01,
        REMOVE_EMPTY_PARENTS_REFLOG = 0x02
@@@ -1481,73 -2433,21 +1481,73 @@@ static int files_pack_refs(struct ref_s
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE | REF_STORE_ODB,
                               "pack_refs");
 -      struct pack_refs_cb_data cbdata;
 -
 -      memset(&cbdata, 0, sizeof(cbdata));
 -      cbdata.flags = flags;
 +      struct ref_iterator *iter;
 +      struct ref_dir *packed_refs;
 +      int ok;
 +      struct ref_to_prune *refs_to_prune = NULL;
  
        lock_packed_refs(refs, LOCK_DIE_ON_ERROR);
 -      cbdata.packed_refs = get_packed_refs(refs);
 +      packed_refs = get_packed_refs(refs);
 +
 +      iter = cache_ref_iterator_begin(get_loose_ref_cache(refs), NULL, 0);
 +      while ((ok = ref_iterator_advance(iter)) == ITER_OK) {
 +              /*
 +               * If the loose reference can be packed, add an entry
 +               * in the packed ref cache. If the reference should be
 +               * pruned, also add it to refs_to_prune.
 +               */
 +              struct ref_entry *packed_entry;
 +              int is_tag_ref = starts_with(iter->refname, "refs/tags/");
  
 -      do_for_each_entry_in_dir(get_loose_refs(refs), 0,
 -                               pack_if_possible_fn, &cbdata);
 +              /* Do not pack per-worktree refs: */
 +              if (ref_type(iter->refname) != REF_TYPE_NORMAL)
 +                      continue;
 +
 +              /* ALWAYS pack tags */
 +              if (!(flags & PACK_REFS_ALL) && !is_tag_ref)
 +                      continue;
 +
 +              /* Do not pack symbolic or broken refs: */
 +              if (iter->flags & REF_ISSYMREF)
 +                      continue;
 +
 +              if (!ref_resolves_to_object(iter->refname, iter->oid, iter->flags))
 +                      continue;
 +
 +              /*
 +               * Create an entry in the packed-refs cache equivalent
 +               * to the one from the loose ref cache, except that
 +               * we don't copy the peeled status, because we want it
 +               * to be re-peeled.
 +               */
 +              packed_entry = find_ref_entry(packed_refs, iter->refname);
 +              if (packed_entry) {
 +                      /* Overwrite existing packed entry with info from loose entry */
 +                      packed_entry->flag = REF_ISPACKED;
 +                      oidcpy(&packed_entry->u.value.oid, iter->oid);
 +              } else {
 +                      packed_entry = create_ref_entry(iter->refname, iter->oid->hash,
 +                                                      REF_ISPACKED, 0);
 +                      add_ref_entry(packed_refs, packed_entry);
 +              }
 +              oidclr(&packed_entry->u.value.peeled);
 +
 +              /* Schedule the loose reference for pruning if requested. */
 +              if ((flags & PACK_REFS_PRUNE)) {
 +                      struct ref_to_prune *n;
 +                      FLEX_ALLOC_STR(n, name, iter->refname);
 +                      hashcpy(n->sha1, iter->oid->hash);
 +                      n->next = refs_to_prune;
 +                      refs_to_prune = n;
 +              }
 +      }
 +      if (ok != ITER_DONE)
 +              die("error while iterating over references");
  
        if (commit_packed_refs(refs))
                die_errno("unable to overwrite old ref-pack file");
  
 -      prune_refs(refs, cbdata.ref_to_prune);
 +      prune_refs(refs, refs_to_prune);
        return 0;
  }
  
@@@ -1588,7 -2488,7 +1588,7 @@@ static int repack_without_refs(struct f
  
        /* Remove refnames from the cache */
        for_each_string_list_item(refname, refnames)
 -              if (remove_entry(packed, refname->string) != -1)
 +              if (remove_entry_from_dir(packed, refname->string) != -1)
                        removed = 1;
        if (!removed) {
                /*
@@@ -1708,6 -2608,26 +1708,6 @@@ static int rename_tmp_log(struct files_
        return ret;
  }
  
 -static int files_verify_refname_available(struct ref_store *ref_store,
 -                                        const char *newname,
 -                                        const struct string_list *extras,
 -                                        const struct string_list *skip,
 -                                        struct strbuf *err)
 -{
 -      struct files_ref_store *refs =
 -              files_downcast(ref_store, REF_STORE_READ, "verify_refname_available");
 -      struct ref_dir *packed_refs = get_packed_refs(refs);
 -      struct ref_dir *loose_refs = get_loose_refs(refs);
 -
 -      if (verify_refname_available_dir(newname, extras, skip,
 -                                       packed_refs, err) ||
 -          verify_refname_available_dir(newname, extras, skip,
 -                                       loose_refs, err))
 -              return -1;
 -
 -      return 0;
 -}
 -
  static int write_ref_to_lockfile(struct ref_lock *lock,
                                 const unsigned char *sha1, struct strbuf *err);
  static int commit_ref_update(struct files_ref_store *refs,
@@@ -2240,50 -3160,6 +2240,6 @@@ static int files_create_symref(struct r
        return ret;
  }
  
- int set_worktree_head_symref(const char *gitdir, const char *target, const char *logmsg)
- {
-       /*
-        * FIXME: this obviously will not work well for future refs
-        * backends. This function needs to die.
-        */
-       struct files_ref_store *refs =
-               files_downcast(get_main_ref_store(),
-                              REF_STORE_WRITE,
-                              "set_head_symref");
-       static struct lock_file head_lock;
-       struct ref_lock *lock;
-       struct strbuf head_path = STRBUF_INIT;
-       const char *head_rel;
-       int ret;
-       strbuf_addf(&head_path, "%s/HEAD", absolute_path(gitdir));
-       if (hold_lock_file_for_update(&head_lock, head_path.buf,
-                                     LOCK_NO_DEREF) < 0) {
-               struct strbuf err = STRBUF_INIT;
-               unable_to_lock_message(head_path.buf, errno, &err);
-               error("%s", err.buf);
-               strbuf_release(&err);
-               strbuf_release(&head_path);
-               return -1;
-       }
-       /* head_rel will be "HEAD" for the main tree, "worktrees/wt/HEAD" for
-          linked trees */
-       head_rel = remove_leading_path(head_path.buf,
-                                      absolute_path(get_git_common_dir()));
-       /* to make use of create_symref_locked(), initialize ref_lock */
-       lock = xcalloc(1, sizeof(struct ref_lock));
-       lock->lk = &head_lock;
-       lock->ref_name = xstrdup(head_rel);
-       ret = create_symref_locked(refs, lock, head_rel, target, logmsg);
-       unlock_ref(lock); /* will free lock */
-       strbuf_release(&head_path);
-       return ret;
- }
  static int files_reflog_exists(struct ref_store *ref_store,
                               const char *refname)
  {
@@@ -2374,8 -3250,8 +2330,8 @@@ static int files_for_each_reflog_ent_re
  
        /* Jump to the end */
        if (fseek(logfp, 0, SEEK_END) < 0)
 -              return error("cannot seek back reflog for %s: %s",
 -                           refname, strerror(errno));
 +              ret = error("cannot seek back reflog for %s: %s",
 +                          refname, strerror(errno));
        pos = ftell(logfp);
        while (!ret && 0 < pos) {
                int cnt;
  
                /* Fill next block from the end */
                cnt = (sizeof(buf) < pos) ? sizeof(buf) : pos;
 -              if (fseek(logfp, pos - cnt, SEEK_SET))
 -                      return error("cannot seek back reflog for %s: %s",
 -                                   refname, strerror(errno));
 +              if (fseek(logfp, pos - cnt, SEEK_SET)) {
 +                      ret = error("cannot seek back reflog for %s: %s",
 +                                  refname, strerror(errno));
 +                      break;
 +              }
                nread = fread(buf, cnt, 1, logfp);
 -              if (nread != 1)
 -                      return error("cannot read %d bytes from reflog for %s: %s",
 -                                   cnt, refname, strerror(errno));
 +              if (nread != 1) {
 +                      ret = error("cannot read %d bytes from reflog for %s: %s",
 +                                  cnt, refname, strerror(errno));
 +                      break;
 +              }
                pos -= cnt;
  
                scanp = endp = buf + cnt;
@@@ -3374,6 -4246,7 +3330,6 @@@ struct ref_storage_be refs_be_files = 
  
        files_ref_iterator_begin,
        files_read_raw_ref,
 -      files_verify_refname_available,
  
        files_reflog_iterator_begin,
        files_for_each_reflog_ent,
diff --combined refs/refs-internal.h
index 3d46131efbcc0a76cc3054a97a669bc5bdd036e7,b26f7e41ceca589b79d2d2cbc38087ff534cc24b..12cf4e471877f615f9f056ab42178e83d772a7ad
@@@ -165,10 -165,6 +165,10 @@@ struct ref_update 
        const char refname[FLEX_ARRAY];
  };
  
 +int refs_read_raw_ref(struct ref_store *ref_store,
 +                    const char *refname, unsigned char *sha1,
 +                    struct strbuf *referent, unsigned int *type);
 +
  /*
   * Add a ref_update with the specified properties to transaction, and
   * return a pointer to the new object. This function does not verify
@@@ -335,17 -331,6 +335,17 @@@ struct ref_iterator *empty_ref_iterator
   */
  int is_empty_ref_iterator(struct ref_iterator *ref_iterator);
  
 +/*
 + * Return an iterator that goes over each reference in `refs` for
 + * which the refname begins with prefix. If trim is non-zero, then
 + * trim that many characters off the beginning of each refname. flags
 + * can be DO_FOR_EACH_INCLUDE_BROKEN to include broken references in
 + * the iteration.
 + */
 +struct ref_iterator *refs_ref_iterator_begin(
 +              struct ref_store *refs,
 +              const char *prefix, int trim, int flags);
 +
  /*
   * A callback function used to instruct merge_ref_iterator how to
   * interleave the entries from iter0 and iter1. The function should
@@@ -482,6 -467,10 +482,10 @@@ struct ref_store
  #define REF_STORE_WRITE               (1 << 1) /* can perform update operations */
  #define REF_STORE_ODB         (1 << 2) /* has access to object database */
  #define REF_STORE_MAIN                (1 << 3)
+ #define REF_STORE_ALL_CAPS    (REF_STORE_READ | \
+                                REF_STORE_WRITE | \
+                                REF_STORE_ODB | \
+                                REF_STORE_MAIN)
  
  /*
   * Initialize the ref_store for the specified gitdir. These functions
@@@ -590,6 -579,12 +594,6 @@@ typedef int read_raw_ref_fn(struct ref_
                            const char *refname, unsigned char *sha1,
                            struct strbuf *referent, unsigned int *type);
  
 -typedef int verify_refname_available_fn(struct ref_store *ref_store,
 -                                      const char *newname,
 -                                      const struct string_list *extras,
 -                                      const struct string_list *skip,
 -                                      struct strbuf *err);
 -
  struct ref_storage_be {
        struct ref_storage_be *next;
        const char *name;
  
        ref_iterator_begin_fn *iterator_begin;
        read_raw_ref_fn *read_raw_ref;
 -      verify_refname_available_fn *verify_refname_available;
  
        reflog_iterator_begin_fn *reflog_iterator_begin;
        for_each_reflog_ent_fn *for_each_reflog_ent;
diff --combined worktree.c
index bae787cf8d7e968e8d5118bf54f17112c0229bf5,c1ec334b06f8b8d55b4087d1208d85731fd46543..726f732e5ecf92824c06b9f7a7dda82dfadf79f5
@@@ -19,54 -19,25 +19,25 @@@ void free_worktrees(struct worktree **w
        free (worktrees);
  }
  
- /*
-  * read 'path_to_ref' into 'ref'.  Also if is_detached is not NULL,
-  * set is_detached to 1 (0) if the ref is detached (is not detached).
-  *
-  * $GIT_COMMON_DIR/$symref (e.g. HEAD) is practically outside $GIT_DIR so
-  * for linked worktrees, `resolve_ref_unsafe()` won't work (it uses
-  * git_path). Parse the ref ourselves.
-  *
-  * return -1 if the ref is not a proper ref, 0 otherwise (success)
-  */
- static int parse_ref(char *path_to_ref, struct strbuf *ref, int *is_detached)
- {
-       if (is_detached)
-               *is_detached = 0;
-       if (!strbuf_readlink(ref, path_to_ref, 0)) {
-               /* HEAD is symbolic link */
-               if (!starts_with(ref->buf, "refs/") ||
-                               check_refname_format(ref->buf, 0))
-                       return -1;
-       } else if (strbuf_read_file(ref, path_to_ref, 0) >= 0) {
-               /* textual symref or detached */
-               if (!starts_with(ref->buf, "ref:")) {
-                       if (is_detached)
-                               *is_detached = 1;
-               } else {
-                       strbuf_remove(ref, 0, strlen("ref:"));
-                       strbuf_trim(ref);
-                       if (check_refname_format(ref->buf, 0))
-                               return -1;
-               }
-       } else
-               return -1;
-       return 0;
- }
  /**
-  * Add the head_sha1 and head_ref (if not detached) to the given worktree
+  * Update head_sha1, head_ref and is_detached of the given worktree
   */
- static void add_head_info(struct strbuf *head_ref, struct worktree *worktree)
+ static void add_head_info(struct worktree *wt)
  {
-       if (head_ref->len) {
-               if (worktree->is_detached) {
-                       get_sha1_hex(head_ref->buf, worktree->head_sha1);
-               } else {
-                       resolve_ref_unsafe(head_ref->buf, 0, worktree->head_sha1, NULL);
-                       worktree->head_ref = strbuf_detach(head_ref, NULL);
-               }
-       }
+       int flags;
+       const char *target;
+       target = refs_resolve_ref_unsafe(get_worktree_ref_store(wt),
+                                        "HEAD",
+                                        RESOLVE_REF_READING,
+                                        wt->head_sha1, &flags);
+       if (!target)
+               return;
+       if (flags & REF_ISSYMREF)
+               wt->head_ref = xstrdup(target);
+       else
+               wt->is_detached = 1;
  }
  
  /**
@@@ -77,9 -48,7 +48,7 @@@ static struct worktree *get_main_worktr
        struct worktree *worktree = NULL;
        struct strbuf path = STRBUF_INIT;
        struct strbuf worktree_path = STRBUF_INIT;
-       struct strbuf head_ref = STRBUF_INIT;
        int is_bare = 0;
-       int is_detached = 0;
  
        strbuf_add_absolute_path(&worktree_path, get_git_common_dir());
        is_bare = !strbuf_strip_suffix(&worktree_path, "/.git");
        worktree = xcalloc(1, sizeof(*worktree));
        worktree->path = strbuf_detach(&worktree_path, NULL);
        worktree->is_bare = is_bare;
-       worktree->is_detached = is_detached;
-       if (!parse_ref(path.buf, &head_ref, &is_detached))
-               add_head_info(&head_ref, worktree);
+       add_head_info(worktree);
  
        strbuf_release(&path);
        strbuf_release(&worktree_path);
-       strbuf_release(&head_ref);
        return worktree;
  }
  
@@@ -106,8 -72,6 +72,6 @@@ static struct worktree *get_linked_work
        struct worktree *worktree = NULL;
        struct strbuf path = STRBUF_INIT;
        struct strbuf worktree_path = STRBUF_INIT;
-       struct strbuf head_ref = STRBUF_INIT;
-       int is_detached = 0;
  
        if (!id)
                die("Missing linked worktree name");
        strbuf_reset(&path);
        strbuf_addf(&path, "%s/worktrees/%s/HEAD", get_git_common_dir(), id);
  
-       if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
-               goto done;
        worktree = xcalloc(1, sizeof(*worktree));
        worktree->path = strbuf_detach(&worktree_path, NULL);
        worktree->id = xstrdup(id);
-       worktree->is_detached = is_detached;
-       add_head_info(&head_ref, worktree);
+       add_head_info(worktree);
  
  done:
        strbuf_release(&path);
        strbuf_release(&worktree_path);
-       strbuf_release(&head_ref);
        return worktree;
  }
  
@@@ -250,19 -209,16 +209,19 @@@ struct worktree *find_worktree(struct w
  {
        struct worktree *wt;
        char *path;
 +      char *to_free = NULL;
  
        if ((wt = find_worktree_by_suffix(list, arg)))
                return wt;
  
 -      arg = prefix_filename(prefix, strlen(prefix), arg);
 +      if (prefix)
 +              arg = to_free = prefix_filename(prefix, arg);
        path = real_pathdup(arg, 1);
        for (; *list; list++)
                if (!fspathcmp(path, real_path((*list)->path)))
                        break;
        free(path);
 +      free(to_free);
        return *list;
  }
  
@@@ -337,8 -293,6 +296,6 @@@ const struct worktree *find_shared_symr
                                          const char *target)
  {
        const struct worktree *existing = NULL;
-       struct strbuf path = STRBUF_INIT;
-       struct strbuf sb = STRBUF_INIT;
        static struct worktree **worktrees;
        int i = 0;
  
  
        for (i = 0; worktrees[i]; i++) {
                struct worktree *wt = worktrees[i];
+               const char *symref_target;
+               unsigned char sha1[20];
+               struct ref_store *refs;
+               int flags;
                if (wt->is_bare)
                        continue;
  
                        }
                }
  
-               strbuf_reset(&path);
-               strbuf_reset(&sb);
-               strbuf_addf(&path, "%s/%s",
-                           get_worktree_git_dir(wt),
-                           symref);
-               if (parse_ref(path.buf, &sb, NULL)) {
-                       continue;
-               }
-               if (!strcmp(sb.buf, target)) {
+               refs = get_worktree_ref_store(wt);
+               symref_target = refs_resolve_ref_unsafe(refs, symref, 0,
+                                                       sha1, &flags);
+               if ((flags & REF_ISSYMREF) && !strcmp(symref_target, target)) {
                        existing = wt;
                        break;
                }
        }
  
-       strbuf_release(&path);
-       strbuf_release(&sb);
        return existing;
  }