Merge branch 'dt/pre-refs-backend'
authorJunio C Hamano <gitster@pobox.com>
Mon, 25 Apr 2016 22:17:15 +0000 (15:17 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 25 Apr 2016 22:17:15 +0000 (15:17 -0700)
Code restructuring around the "refs" area to prepare for pluggable
refs backends.

* dt/pre-refs-backend: (24 commits)
refs: on symref reflog expire, lock symref not referrent
refs: move resolve_ref_unsafe into common code
show_head_ref(): check the result of resolve_ref_namespace()
check_aliased_update(): check that dst_name is non-NULL
checkout_paths(): remove unneeded flag variable
cmd_merge(): remove unneeded flag variable
fsck_head_link(): remove unneeded flag variable
read_raw_ref(): change flags parameter to unsigned int
files-backend: inline resolve_ref_1() into resolve_ref_unsafe()
read_raw_ref(): manage own scratch space
files-backend: break out ref reading
resolve_ref_1(): eliminate local variable "bad_name"
resolve_ref_1(): reorder code
resolve_ref_1(): eliminate local variable
resolve_ref_unsafe(): ensure flags is always set
resolve_ref_unsafe(): use for loop to count up to MAXDEPTH
resolve_missing_loose_ref(): simplify semantics
t1430: improve test coverage of deletion of badly-named refs
t1430: test for-each-ref in the presence of badly-named refs
t1430: don't rely on symbolic-ref for creating broken symrefs
...

1  2 
builtin/merge.c
builtin/receive-pack.c
refs/files-backend.c
diff --combined builtin/merge.c
index 41467e427770d02f40df5e8d5ca0a27ab483c4af,c90ee51c6cfef86bfa28f40b53efb853e163d60d..1ec44f0c1b241ed7c05efefc427a7923241c1db1
@@@ -64,7 -64,6 +64,7 @@@ static int option_renormalize
  static int verbosity;
  static int allow_rerere_auto;
  static int abort_current_merge;
 +static int allow_unrelated_histories;
  static int show_progress = -1;
  static int default_to_upstream = 1;
  static const char *sign_commit;
@@@ -222,8 -221,6 +222,8 @@@ static struct option builtin_merge_opti
        OPT__VERBOSITY(&verbosity),
        OPT_BOOL(0, "abort", &abort_current_merge,
                N_("abort the current in-progress merge")),
 +      OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories,
 +               N_("allow merging unrelated histories")),
        OPT_SET_INT(0, "progress", &show_progress, N_("force progress reporting"), 1),
        { OPTION_STRING, 'S', "gpg-sign", &sign_commit, N_("key-id"),
          N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" },
@@@ -1168,7 -1165,7 +1168,7 @@@ int cmd_merge(int argc, const char **ar
        struct commit *head_commit;
        struct strbuf buf = STRBUF_INIT;
        const char *head_arg;
-       int flag, i, ret = 0, head_subsumed;
+       int i, ret = 0, head_subsumed;
        int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
        struct commit_list *common = NULL;
        const char *best_strategy = NULL, *wt_strategy = NULL;
         * Check if we are _not_ on a detached HEAD, i.e. if there is a
         * current branch.
         */
-       branch = branch_to_free = resolve_refdup("HEAD", 0, head_sha1, &flag);
+       branch = branch_to_free = resolve_refdup("HEAD", 0, head_sha1, NULL);
        if (branch && starts_with(branch, "refs/heads/"))
                branch += 11;
        if (!branch || is_null_sha1(head_sha1))
        else
                head_commit = lookup_commit_or_die(head_sha1, "HEAD");
  
 +      init_diff_ui_defaults();
        git_config(git_merge_config, NULL);
  
        if (branch_mergeoptions)
                        builtin_merge_options);
  
        if (!head_commit) {
 -              struct commit *remote_head;
                /*
                 * If the merged head is a valid one there is no reason
                 * to forbid "git merge" into a branch yet to be born.
                 * We do the same for "git pull".
                 */
 +              unsigned char *remote_head_sha1;
                if (squash)
                        die(_("Squash commit into empty head not supported yet"));
                if (fast_forward == FF_NO)
                            "an empty head"));
                remoteheads = collect_parents(head_commit, &head_subsumed,
                                              argc, argv, NULL);
 -              remote_head = remoteheads->item;
 -              if (!remote_head)
 +              if (!remoteheads)
                        die(_("%s - not something we can merge"), argv[0]);
                if (remoteheads->next)
                        die(_("Can merge only exactly one commit into empty head"));
 -              read_empty(remote_head->object.oid.hash, 0);
 -              update_ref("initial pull", "HEAD", remote_head->object.oid.hash,
 +              remote_head_sha1 = remoteheads->item->object.oid.hash;
 +              read_empty(remote_head_sha1, 0);
 +              update_ref("initial pull", "HEAD", remote_head_sha1,
                           NULL, 0, UPDATE_REFS_DIE_ON_ERR);
                goto done;
        }
        update_ref("updating ORIG_HEAD", "ORIG_HEAD", head_commit->object.oid.hash,
                   NULL, 0, UPDATE_REFS_DIE_ON_ERR);
  
 -      if (remoteheads && !common)
 -              ; /* No common ancestors found. We need a real merge. */
 -      else if (!remoteheads ||
 +      if (remoteheads && !common) {
 +              /* No common ancestors found. */
 +              if (!allow_unrelated_histories)
 +                      die(_("refusing to merge unrelated histories"));
 +              /* otherwise, we need a real merge. */
 +      } else if (!remoteheads ||
                 (!remoteheads->next && !common->next &&
                  common->item == remoteheads->item)) {
                /*
diff --combined builtin/receive-pack.c
index 220a899b960a9ddc39ab1e582847ec87d9adad6f,49cc88d72f28205bfa909408ba994444d27239ae..a744437b5876171250d4731d181f7b30e5444187
  #include "sigchain.h"
  #include "fsck.h"
  
 -static const char receive_pack_usage[] = "git receive-pack <git-dir>";
 +static const char * const receive_pack_usage[] = {
 +      N_("git receive-pack <git-dir>"),
 +      NULL
 +};
  
  enum deny_action {
        DENY_UNCONFIGURED,
@@@ -52,7 -49,7 +52,7 @@@ static int quiet
  static int prefer_ofs_delta = 1;
  static int auto_update_server_info;
  static int auto_gc = 1;
 -static int fix_thin = 1;
 +static int reject_thin;
  static int stateless_rpc;
  static const char *service_dir;
  static const char *head_name;
@@@ -1084,13 -1081,13 +1084,13 @@@ static void check_aliased_update(struc
        if (!(flag & REF_ISSYMREF))
                return;
  
-       dst_name = strip_namespace(dst_name);
        if (!dst_name) {
                rp_error("refusing update to broken symref '%s'", cmd->ref_name);
                cmd->skip_update = 1;
                cmd->error_string = "broken symref";
                return;
        }
+       dst_name = strip_namespace(dst_name);
  
        if ((item = string_list_lookup(list, dst_name)) == NULL)
                return;
@@@ -1551,7 -1548,7 +1551,7 @@@ static const char *unpack(int err_fd, s
                if (fsck_objects)
                        argv_array_pushf(&child.args, "--strict%s",
                                fsck_msg_types.buf);
 -              if (fix_thin)
 +              if (!reject_thin)
                        argv_array_push(&child.args, "--fix-thin");
                child.out = -1;
                child.err = err_fd;
@@@ -1710,29 -1707,45 +1710,29 @@@ static int delete_only(struct command *
  int cmd_receive_pack(int argc, const char **argv, const char *prefix)
  {
        int advertise_refs = 0;
 -      int i;
        struct command *commands;
        struct sha1_array shallow = SHA1_ARRAY_INIT;
        struct sha1_array ref = SHA1_ARRAY_INIT;
        struct shallow_info si;
  
 -      packet_trace_identity("receive-pack");
 +      struct option options[] = {
 +              OPT__QUIET(&quiet, N_("quiet")),
 +              OPT_HIDDEN_BOOL(0, "stateless-rpc", &stateless_rpc, NULL),
 +              OPT_HIDDEN_BOOL(0, "advertise-refs", &advertise_refs, NULL),
 +              OPT_HIDDEN_BOOL(0, "reject-thin-pack-for-testing", &reject_thin, NULL),
 +              OPT_END()
 +      };
  
 -      argv++;
 -      for (i = 1; i < argc; i++) {
 -              const char *arg = *argv++;
 +      packet_trace_identity("receive-pack");
  
 -              if (*arg == '-') {
 -                      if (!strcmp(arg, "--quiet")) {
 -                              quiet = 1;
 -                              continue;
 -                      }
 +      argc = parse_options(argc, argv, prefix, options, receive_pack_usage, 0);
  
 -                      if (!strcmp(arg, "--advertise-refs")) {
 -                              advertise_refs = 1;
 -                              continue;
 -                      }
 -                      if (!strcmp(arg, "--stateless-rpc")) {
 -                              stateless_rpc = 1;
 -                              continue;
 -                      }
 -                      if (!strcmp(arg, "--reject-thin-pack-for-testing")) {
 -                              fix_thin = 0;
 -                              continue;
 -                      }
 +      if (argc > 1)
 +              usage_msg_opt(_("Too many arguments."), receive_pack_usage, options);
 +      if (argc == 0)
 +              usage_msg_opt(_("You must specify a directory."), receive_pack_usage, options);
  
 -                      usage(receive_pack_usage);
 -              }
 -              if (service_dir)
 -                      usage(receive_pack_usage);
 -              service_dir = arg;
 -      }
 -      if (!service_dir)
 -              usage(receive_pack_usage);
 +      service_dir = argv[0];
  
        setup_path();
  
diff --combined refs/files-backend.c
index ea78ce9d90f0bb02fcd471c1c113e22053a3ba94,5e67bfae68a099a73ab6f9a21a6b337914192148..1f38076411dc62b82792b677d95fe775effc79cd
@@@ -513,9 -513,6 +513,6 @@@ static void sort_ref_dir(struct ref_di
        dir->sorted = dir->nr = i;
  }
  
- /* Include broken references in a do_for_each_ref*() iteration: */
- #define DO_FOR_EACH_INCLUDE_BROKEN 0x01
  /*
   * Return true iff the reference described by entry can be resolved to
   * an object in the database.  Emit a warning if the referred-to
@@@ -1272,8 -1269,6 +1269,6 @@@ static struct ref_dir *get_loose_refs(s
        return get_ref_dir(refs->loose);
  }
  
- /* We allow "recursive" symbolic refs. Only within reason, though */
- #define MAXDEPTH 5
  #define MAXREFLEN (1024)
  
  /*
@@@ -1303,7 -1298,7 +1298,7 @@@ static int resolve_gitlink_ref_recursiv
        char buffer[128], *p;
        char *path;
  
-       if (recursion > MAXDEPTH || strlen(refname) > MAXREFLEN)
+       if (recursion > SYMREF_MAXDEPTH || strlen(refname) > MAXREFLEN)
                return -1;
        path = *refs->name
                ? git_pathdup_submodule(refs->name, "%s", refname)
@@@ -1371,13 -1366,11 +1366,11 @@@ static struct ref_entry *get_packed_ref
  }
  
  /*
-  * A loose ref file doesn't exist; check for a packed ref.  The
-  * options are forwarded from resolve_safe_unsafe().
+  * A loose ref file doesn't exist; check for a packed ref.
   */
  static int resolve_missing_loose_ref(const char *refname,
-                                    int resolve_flags,
                                     unsigned char *sha1,
-                                    int *flags)
+                                    unsigned int *flags)
  {
        struct ref_entry *entry;
  
        entry = get_packed_ref(refname);
        if (entry) {
                hashcpy(sha1, entry->u.value.oid.hash);
-               if (flags)
-                       *flags |= REF_ISPACKED;
-               return 0;
-       }
-       /* The reference is not a packed reference, either. */
-       if (resolve_flags & RESOLVE_REF_READING) {
-               errno = ENOENT;
-               return -1;
-       } else {
-               hashclr(sha1);
+               *flags |= REF_ISPACKED;
                return 0;
        }
+       /* refname is not a packed reference. */
+       return -1;
  }
  
- /* This function needs to return a meaningful errno on failure */
- static const char *resolve_ref_1(const char *refname,
-                                int resolve_flags,
-                                unsigned char *sha1,
-                                int *flags,
-                                struct strbuf *sb_refname,
-                                struct strbuf *sb_path,
-                                struct strbuf *sb_contents)
+ /*
+  * Read a raw ref from the filesystem or packed refs file.
+  *
+  * If the ref is a sha1, fill in sha1 and return 0.
+  *
+  * If the ref is symbolic, fill in *symref with the referrent
+  * (e.g. "refs/heads/master") and return 0.  The caller is responsible
+  * for validating the referrent.  Set REF_ISSYMREF in flags.
+  *
+  * If the ref doesn't exist, set errno to ENOENT and return -1.
+  *
+  * If the ref exists but is neither a symbolic ref nor a sha1, it is
+  * broken. Set REF_ISBROKEN in flags, set errno to EINVAL, and return
+  * -1.
+  *
+  * If there is another error reading the ref, set errno appropriately and
+  * return -1.
+  *
+  * Backend-specific flags might be set in flags as well, regardless of
+  * outcome.
+  *
+  * sb_path is workspace: the caller should allocate and free it.
+  *
+  * It is OK for refname to point into symref. In this case:
+  * - if the function succeeds with REF_ISSYMREF, symref will be
+  *   overwritten and the memory pointed to by refname might be changed
+  *   or even freed.
+  * - in all other cases, symref will be untouched, and therefore
+  *   refname will still be valid and unchanged.
+  */
+ int read_raw_ref(const char *refname, unsigned char *sha1,
+                struct strbuf *symref, unsigned int *flags)
  {
-       int depth = MAXDEPTH;
-       int bad_name = 0;
+       struct strbuf sb_contents = STRBUF_INIT;
+       struct strbuf sb_path = STRBUF_INIT;
+       const char *path;
+       const char *buf;
+       struct stat st;
+       int fd;
+       int ret = -1;
+       int save_errno;
  
-       if (flags)
-               *flags = 0;
+       strbuf_reset(&sb_path);
+       strbuf_git_path(&sb_path, "%s", refname);
+       path = sb_path.buf;
  
-       if (check_refname_format(refname, REFNAME_ALLOW_ONELEVEL)) {
-               if (flags)
-                       *flags |= REF_BAD_NAME;
+ stat_ref:
+       /*
+        * We might have to loop back here to avoid a race
+        * condition: first we lstat() the file, then we try
+        * to read it as a link or as a file.  But if somebody
+        * changes the type of the file (file <-> directory
+        * <-> symlink) between the lstat() and reading, then
+        * we don't want to report that as an error but rather
+        * try again starting with the lstat().
+        */
  
-               if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
-                   !refname_is_safe(refname)) {
-                       errno = EINVAL;
-                       return NULL;
+       if (lstat(path, &st) < 0) {
+               if (errno != ENOENT)
+                       goto out;
+               if (resolve_missing_loose_ref(refname, sha1, flags)) {
+                       errno = ENOENT;
+                       goto out;
                }
-               /*
-                * dwim_ref() uses REF_ISBROKEN to distinguish between
-                * missing refs and refs that were present but invalid,
-                * to complain about the latter to stderr.
-                *
-                * We don't know whether the ref exists, so don't set
-                * REF_ISBROKEN yet.
-                */
-               bad_name = 1;
+               ret = 0;
+               goto out;
        }
-       for (;;) {
-               const char *path;
-               struct stat st;
-               char *buf;
-               int fd;
  
-               if (--depth < 0) {
-                       errno = ELOOP;
-                       return NULL;
-               }
-               strbuf_reset(sb_path);
-               strbuf_git_path(sb_path, "%s", refname);
-               path = sb_path->buf;
-               /*
-                * We might have to loop back here to avoid a race
-                * condition: first we lstat() the file, then we try
-                * to read it as a link or as a file.  But if somebody
-                * changes the type of the file (file <-> directory
-                * <-> symlink) between the lstat() and reading, then
-                * we don't want to report that as an error but rather
-                * try again starting with the lstat().
-                */
-       stat_ref:
-               if (lstat(path, &st) < 0) {
-                       if (errno != ENOENT)
-                               return NULL;
-                       if (resolve_missing_loose_ref(refname, resolve_flags,
-                                                     sha1, flags))
-                               return NULL;
-                       if (bad_name) {
-                               hashclr(sha1);
-                               if (flags)
-                                       *flags |= REF_ISBROKEN;
-                       }
-                       return refname;
-               }
-               /* Follow "normalized" - ie "refs/.." symlinks by hand */
-               if (S_ISLNK(st.st_mode)) {
-                       strbuf_reset(sb_contents);
-                       if (strbuf_readlink(sb_contents, path, 0) < 0) {
-                               if (errno == ENOENT || errno == EINVAL)
-                                       /* inconsistent with lstat; retry */
-                                       goto stat_ref;
-                               else
-                                       return NULL;
-                       }
-                       if (starts_with(sb_contents->buf, "refs/") &&
-                           !check_refname_format(sb_contents->buf, 0)) {
-                               strbuf_swap(sb_refname, sb_contents);
-                               refname = sb_refname->buf;
-                               if (flags)
-                                       *flags |= REF_ISSYMREF;
-                               if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
-                                       hashclr(sha1);
-                                       return refname;
-                               }
-                               continue;
-                       }
-               }
-               /* Is it a directory? */
-               if (S_ISDIR(st.st_mode)) {
-                       errno = EISDIR;
-                       return NULL;
-               }
-               /*
-                * Anything else, just open it and try to use it as
-                * a ref
-                */
-               fd = open(path, O_RDONLY);
-               if (fd < 0) {
-                       if (errno == ENOENT)
+       /* Follow "normalized" - ie "refs/.." symlinks by hand */
+       if (S_ISLNK(st.st_mode)) {
+               strbuf_reset(&sb_contents);
+               if (strbuf_readlink(&sb_contents, path, 0) < 0) {
+                       if (errno == ENOENT || errno == EINVAL)
                                /* inconsistent with lstat; retry */
                                goto stat_ref;
                        else
-                               return NULL;
+                               goto out;
                }
-               strbuf_reset(sb_contents);
-               if (strbuf_read(sb_contents, fd, 256) < 0) {
-                       int save_errno = errno;
-                       close(fd);
-                       errno = save_errno;
-                       return NULL;
+               if (starts_with(sb_contents.buf, "refs/") &&
+                   !check_refname_format(sb_contents.buf, 0)) {
+                       strbuf_swap(&sb_contents, symref);
+                       *flags |= REF_ISSYMREF;
+                       ret = 0;
+                       goto out;
                }
-               close(fd);
-               strbuf_rtrim(sb_contents);
+       }
  
-               /*
-                * Is it a symbolic ref?
-                */
-               if (!starts_with(sb_contents->buf, "ref:")) {
-                       /*
-                        * Please note that FETCH_HEAD has a second
-                        * line containing other data.
-                        */
-                       if (get_sha1_hex(sb_contents->buf, sha1) ||
-                           (sb_contents->buf[40] != '\0' && !isspace(sb_contents->buf[40]))) {
-                               if (flags)
-                                       *flags |= REF_ISBROKEN;
-                               errno = EINVAL;
-                               return NULL;
-                       }
-                       if (bad_name) {
-                               hashclr(sha1);
-                               if (flags)
-                                       *flags |= REF_ISBROKEN;
-                       }
-                       return refname;
-               }
-               if (flags)
-                       *flags |= REF_ISSYMREF;
-               buf = sb_contents->buf + 4;
+       /* Is it a directory? */
+       if (S_ISDIR(st.st_mode)) {
+               errno = EISDIR;
+               goto out;
+       }
+       /*
+        * Anything else, just open it and try to use it as
+        * a ref
+        */
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               if (errno == ENOENT)
+                       /* inconsistent with lstat; retry */
+                       goto stat_ref;
+               else
+                       goto out;
+       }
+       strbuf_reset(&sb_contents);
+       if (strbuf_read(&sb_contents, fd, 256) < 0) {
+               int save_errno = errno;
+               close(fd);
+               errno = save_errno;
+               goto out;
+       }
+       close(fd);
+       strbuf_rtrim(&sb_contents);
+       buf = sb_contents.buf;
+       if (starts_with(buf, "ref:")) {
+               buf += 4;
                while (isspace(*buf))
                        buf++;
-               strbuf_reset(sb_refname);
-               strbuf_addstr(sb_refname, buf);
-               refname = sb_refname->buf;
-               if (resolve_flags & RESOLVE_REF_NO_RECURSE) {
-                       hashclr(sha1);
-                       return refname;
-               }
-               if (check_refname_format(buf, REFNAME_ALLOW_ONELEVEL)) {
-                       if (flags)
-                               *flags |= REF_ISBROKEN;
-                       if (!(resolve_flags & RESOLVE_REF_ALLOW_BAD_NAME) ||
-                           !refname_is_safe(buf)) {
-                               errno = EINVAL;
-                               return NULL;
-                       }
-                       bad_name = 1;
-               }
+               strbuf_reset(symref);
+               strbuf_addstr(symref, buf);
+               *flags |= REF_ISSYMREF;
+               ret = 0;
+               goto out;
        }
- }
  
- const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
-                              unsigned char *sha1, int *flags)
- {
-       static struct strbuf sb_refname = STRBUF_INIT;
-       struct strbuf sb_contents = STRBUF_INIT;
-       struct strbuf sb_path = STRBUF_INIT;
-       const char *ret;
+       /*
+        * Please note that FETCH_HEAD has additional
+        * data after the sha.
+        */
+       if (get_sha1_hex(buf, sha1) ||
+           (buf[40] != '\0' && !isspace(buf[40]))) {
+               *flags |= REF_ISBROKEN;
+               errno = EINVAL;
+               goto out;
+       }
+       ret = 0;
  
-       ret = resolve_ref_1(refname, resolve_flags, sha1, flags,
-                           &sb_refname, &sb_path, &sb_contents);
+ out:
+       save_errno = errno;
        strbuf_release(&sb_path);
        strbuf_release(&sb_contents);
+       errno = save_errno;
        return ret;
  }
  
@@@ -1727,10 -1673,13 +1673,13 @@@ static int do_for_each_entry(struct ref
   * value, stop the iteration and return that value; otherwise, return
   * 0.
   */
static int do_for_each_ref(struct ref_cache *refs, const char *base,
-                          each_ref_fn fn, int trim, int flags, void *cb_data)
int do_for_each_ref(const char *submodule, const char *base,
+                   each_ref_fn fn, int trim, int flags, void *cb_data)
  {
        struct ref_entry_cb data;
+       struct ref_cache *refs;
+       refs = get_ref_cache(submodule);
        data.base = base;
        data.trim = trim;
        data.flags = flags;
        return do_for_each_entry(refs, base, do_one_ref, &data);
  }
  
- static int do_head_ref(const char *submodule, each_ref_fn fn, void *cb_data)
- {
-       struct object_id oid;
-       int flag;
-       if (submodule) {
-               if (resolve_gitlink_ref(submodule, "HEAD", oid.hash) == 0)
-                       return fn("HEAD", &oid, 0, cb_data);
-               return 0;
-       }
-       if (!read_ref_full("HEAD", RESOLVE_REF_READING, oid.hash, &flag))
-               return fn("HEAD", &oid, flag, cb_data);
-       return 0;
- }
- int head_ref(each_ref_fn fn, void *cb_data)
- {
-       return do_head_ref(NULL, fn, cb_data);
- }
- int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
- {
-       return do_head_ref(submodule, fn, cb_data);
- }
- int for_each_ref(each_ref_fn fn, void *cb_data)
- {
-       return do_for_each_ref(&ref_cache, "", fn, 0, 0, cb_data);
- }
- int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data)
- {
-       return do_for_each_ref(get_ref_cache(submodule), "", fn, 0, 0, cb_data);
- }
- int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
- {
-       return do_for_each_ref(&ref_cache, prefix, fn, strlen(prefix), 0, cb_data);
- }
- int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)
- {
-       unsigned int flag = 0;
-       if (broken)
-               flag = DO_FOR_EACH_INCLUDE_BROKEN;
-       return do_for_each_ref(&ref_cache, prefix, fn, 0, flag, cb_data);
- }
- int for_each_ref_in_submodule(const char *submodule, const char *prefix,
-               each_ref_fn fn, void *cb_data)
- {
-       return do_for_each_ref(get_ref_cache(submodule), prefix, fn, strlen(prefix), 0, cb_data);
- }
- int for_each_replace_ref(each_ref_fn fn, void *cb_data)
- {
-       return do_for_each_ref(&ref_cache, git_replace_ref_base, fn,
-                              strlen(git_replace_ref_base), 0, cb_data);
- }
- int for_each_namespaced_ref(each_ref_fn fn, void *cb_data)
- {
-       struct strbuf buf = STRBUF_INIT;
-       int ret;
-       strbuf_addf(&buf, "%srefs/", get_git_namespace());
-       ret = do_for_each_ref(&ref_cache, buf.buf, fn, 0, 0, cb_data);
-       strbuf_release(&buf);
-       return ret;
- }
- int for_each_rawref(each_ref_fn fn, void *cb_data)
- {
-       return do_for_each_ref(&ref_cache, "", fn, 0,
-                              DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
- }
  static void unlock_ref(struct ref_lock *lock)
  {
        /* Do not free lock->lk -- atexit() still looks at them */
@@@ -2894,42 -2763,6 +2763,42 @@@ int create_symref(const char *refname, 
        return ret;
  }
  
 +int set_worktree_head_symref(const char *gitdir, const char *target)
 +{
 +      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);
 +      lock->orig_ref_name = xstrdup(head_rel);
 +
 +      ret = create_symref_locked(lock, head_rel, target, NULL);
 +
 +      unlock_ref(lock); /* will free lock */
 +      strbuf_release(&head_path);
 +      return ret;
 +}
 +
  int reflog_exists(const char *refname)
  {
        struct stat st;
@@@ -3481,7 -3314,8 +3350,8 @@@ int reflog_expire(const char *refname, 
         * reference itself, plus we might need to update the
         * reference if --updateref was specified:
         */
-       lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, 0, &type, &err);
+       lock = lock_ref_sha1_basic(refname, sha1, NULL, NULL, REF_NODEREF,
+                                  &type, &err);
        if (!lock) {
                error("cannot lock ref '%s': %s", refname, err.buf);
                strbuf_release(&err);