Merge branch 'mh/ref-iterators'
authorJunio C Hamano <gitster@pobox.com>
Mon, 25 Jul 2016 21:13:33 +0000 (14:13 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 25 Jul 2016 21:13:33 +0000 (14:13 -0700)
The API to iterate over all the refs (i.e. for_each_ref(), etc.)
has been revamped.

* mh/ref-iterators:
for_each_reflog(): reimplement using iterators
dir_iterator: new API for iterating over a directory tree
for_each_reflog(): don't abort for bad references
do_for_each_ref(): reimplement using reference iteration
refs: introduce an iterator interface
ref_resolves_to_object(): new function
entry_resolves_to_object(): rename function from ref_resolves_to_object()
get_ref_cache(): only create an instance if there is a submodule
remote rm: handle symbolic refs correctly
delete_refs(): add a flags argument
refs: use name "prefix" consistently
do_for_each_ref(): move docstring to the header file
refs: remove unnecessary "extern" keywords

1  2 
Makefile
builtin/fetch.c
builtin/remote.c
refs.h
refs/files-backend.c
diff --combined Makefile
index c1e88dfcdd53f46ea742212f15863e63ef5e1d65,b4ffc11b86faa48affc19c6824e8ee7428f1301a..bfe85595cd0877924aa3cd3dca7b24ab17945d83
+++ b/Makefile
@@@ -375,7 -375,13 +375,7 @@@ GIT-VERSION-FILE: FORC
  # CFLAGS and LDFLAGS are for the users to override from the command line.
  
  CFLAGS = -g -O2 -Wall
 -LDFLAGS =
 -ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 -ALL_LDFLAGS = $(LDFLAGS)
 -STRIP ?= strip
 -
 -ifdef DEVELOPER
 -CFLAGS += -Werror \
 +DEVELOPER_CFLAGS = -Werror \
        -Wdeclaration-after-statement \
        -Wno-format-zero-length \
        -Wold-style-definition \
        -Wstrict-prototypes \
        -Wunused \
        -Wvla
 -endif
 +LDFLAGS =
 +ALL_CFLAGS = $(CPPFLAGS) $(CFLAGS)
 +ALL_LDFLAGS = $(LDFLAGS)
 +STRIP ?= strip
  
  # Create as necessary, replace existing, make ranlib unneeded.
  ARFLAGS = rcs
@@@ -437,6 -440,7 +437,6 @@@ DIFF = dif
  TAR = tar
  FIND = find
  INSTALL = install
 -RPMBUILD = rpmbuild
  TCL_PATH = tclsh
  TCLTK_PATH = wish
  XGETTEXT = xgettext
@@@ -617,7 -621,7 +617,7 @@@ TEST_PROGRAMS_NEED_X += test-svn-f
  TEST_PROGRAMS_NEED_X += test-urlmatch-normalization
  TEST_PROGRAMS_NEED_X += test-wildmatch
  
 -TEST_PROGRAMS = $(patsubst %,%$X,$(TEST_PROGRAMS_NEED_X))
 +TEST_PROGRAMS = $(patsubst %,t/helper/%$X,$(TEST_PROGRAMS_NEED_X))
  
  # List built-in command $C whose implementation cmd_$C() is not in
  # builtin/$C.o but is linked in as part of some other command.
@@@ -718,6 -722,7 +718,7 @@@ LIB_OBJS += diff-lib.
  LIB_OBJS += diff-no-index.o
  LIB_OBJS += diff.o
  LIB_OBJS += dir.o
+ LIB_OBJS += dir-iterator.o
  LIB_OBJS += editor.o
  LIB_OBJS += entry.o
  LIB_OBJS += environment.o
@@@ -782,6 -787,7 +783,7 @@@ LIB_OBJS += read-cache.
  LIB_OBJS += reflog-walk.o
  LIB_OBJS += refs.o
  LIB_OBJS += refs/files-backend.o
+ LIB_OBJS += refs/iterator.o
  LIB_OBJS += ref-filter.o
  LIB_OBJS += remote.o
  LIB_OBJS += replace_object.o
@@@ -939,7 -945,7 +941,7 @@@ BUILTIN_OBJS += builtin/verify-tag.
  BUILTIN_OBJS += builtin/worktree.o
  BUILTIN_OBJS += builtin/write-tree.o
  
 -GITLIBS = $(LIB_FILE) $(XDIFF_LIB)
 +GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB)
  EXTLIBS =
  
  GIT_USER_AGENT = git/$(GIT_VERSION)
@@@ -948,10 -954,6 +950,10 @@@ include config.mak.unam
  -include config.mak.autogen
  -include config.mak
  
 +ifdef DEVELOPER
 +CFLAGS += $(DEVELOPER_CFLAGS)
 +endif
 +
  ifndef sysconfdir
  ifeq ($(prefix),/usr)
  sysconfdir = /etc
@@@ -1572,15 -1574,7 +1574,15 @@@ TCLTK_PATH_SQ = $(subst ','\'',$(TCLTK_
  DIFF_SQ = $(subst ','\'',$(DIFF))
  PERLLIB_EXTRA_SQ = $(subst ','\'',$(PERLLIB_EXTRA))
  
 -LIBS = $(GITLIBS) $(EXTLIBS)
 +# We must filter out any object files from $(GITLIBS),
 +# as it is typically used like:
 +#
 +#   foo: foo.o $(GITLIBS)
 +#     $(CC) $(filter %.o,$^) $(LIBS)
 +#
 +# where we use it as a dependency. Since we also pull object files
 +# from the dependency list, that would make each entry appear twice.
 +LIBS = $(filter-out %.o, $(GITLIBS)) $(EXTLIBS)
  
  BASIC_CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER_SQ)' \
        $(COMPAT_CFLAGS)
@@@ -1716,8 -1710,8 +1718,8 @@@ git.sp git.s git.o: EXTRA_CPPFLAGS = 
        '-DGIT_INFO_PATH="$(infodir_relative_SQ)"'
  
  git$X: git.o GIT-LDFLAGS $(BUILTIN_OBJS) $(GITLIBS)
 -      $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) git.o \
 -              $(BUILTIN_OBJS) $(LIBS)
 +      $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) \
 +              $(filter %.o,$^) $(LIBS)
  
  help.sp help.s help.o: common-cmds.h
  
@@@ -1906,11 -1900,10 +1908,11 @@@ VCSSVN_OBJS += vcs-svn/fast_export.
  VCSSVN_OBJS += vcs-svn/svndiff.o
  VCSSVN_OBJS += vcs-svn/svndump.o
  
 -TEST_OBJS := $(patsubst test-%$X,test-%.o,$(TEST_PROGRAMS))
 +TEST_OBJS := $(patsubst %$X,%.o,$(TEST_PROGRAMS))
  OBJECTS := $(LIB_OBJS) $(BUILTIN_OBJS) $(PROGRAM_OBJS) $(TEST_OBJS) \
        $(XDIFF_OBJS) \
        $(VCSSVN_OBJS) \
 +      common-main.o \
        git.o
  ifndef NO_CURL
        OBJECTS += http.o http-walker.o remote-curl.o
@@@ -2073,9 -2066,6 +2075,9 @@@ XGETTEXT_FLAGS_SH = $(XGETTEXT_FLAGS) -
  XGETTEXT_FLAGS_PERL = $(XGETTEXT_FLAGS) --keyword=__ --language=Perl
  LOCALIZED_C = $(C_OBJ:o=c) $(LIB_H) $(GENERATED_H)
  LOCALIZED_SH = $(SCRIPT_SH)
 +LOCALIZED_SH += git-parse-remote.sh
 +LOCALIZED_SH += git-rebase--interactive.sh
 +LOCALIZED_SH += git-sh-setup.sh
  LOCALIZED_PERL = $(SCRIPT_PERL)
  
  ifdef XGETTEXT_INCLUDE_TESTS
@@@ -2217,7 -2207,7 +2219,7 @@@ bin-wrappers/%: wrap-for-bin.s
        @mkdir -p bin-wrappers
        $(QUIET_GEN)sed -e '1s|#!.*/sh|#!$(SHELL_PATH_SQ)|' \
             -e 's|@@BUILD_DIR@@|$(shell pwd)|' \
 -           -e 's|@@PROG@@|$(@F)|' < $< > $@ && \
 +           -e 's|@@PROG@@|$(patsubst test-%,t/helper/test-%,$(@F))|' < $< > $@ && \
        chmod +x $@
  
  # GNU make supports exporting all variables by "export" without parameters.
@@@ -2237,25 -2227,25 +2239,25 @@@ perf: al
  
  .PHONY: test perf
  
 -test-ctype$X: ctype.o
 +t/helper/test-ctype$X: ctype.o
  
 -test-date$X: date.o ctype.o
 +t/helper/test-date$X: date.o ctype.o
  
 -test-delta$X: diff-delta.o patch-delta.o
 +t/helper/test-delta$X: diff-delta.o patch-delta.o
  
 -test-line-buffer$X: vcs-svn/lib.a
 +t/helper/test-line-buffer$X: vcs-svn/lib.a
  
 -test-parse-options$X: parse-options.o parse-options-cb.o
 +t/helper/test-parse-options$X: parse-options.o parse-options-cb.o
  
 -test-svn-fe$X: vcs-svn/lib.a
 +t/helper/test-svn-fe$X: vcs-svn/lib.a
  
  .PRECIOUS: $(TEST_OBJS)
  
 -test-%$X: test-%.o GIT-LDFLAGS $(GITLIBS)
 +t/helper/test-%$X: t/helper/test-%.o GIT-LDFLAGS $(GITLIBS)
        $(QUIET_LINK)$(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(filter %.a,$^) $(LIBS)
  
 -check-sha1:: test-sha1$X
 -      ./test-sha1.sh
 +check-sha1:: t/helper/test-sha1$X
 +      t/helper/test-sha1.sh
  
  SP_OBJ = $(patsubst %.o,%.sp,$(C_OBJ))
  
@@@ -2402,25 -2392,31 +2404,25 @@@ quick-install-html
  
  ### Maintainer's dist rules
  
 -git.spec: git.spec.in GIT-VERSION-FILE
 -      sed -e 's/@@VERSION@@/$(GIT_VERSION)/g' < $< > $@+
 -      mv $@+ $@
 -
  GIT_TARNAME = git-$(GIT_VERSION)
 -dist: git.spec git-archive$(X) configure
 +dist: git-archive$(X) configure
        ./git-archive --format=tar \
                --prefix=$(GIT_TARNAME)/ HEAD^{tree} > $(GIT_TARNAME).tar
        @mkdir -p $(GIT_TARNAME)
 -      @cp git.spec configure $(GIT_TARNAME)
 +      @cp configure $(GIT_TARNAME)
        @echo $(GIT_VERSION) > $(GIT_TARNAME)/version
        @$(MAKE) -C git-gui TARDIR=../$(GIT_TARNAME)/git-gui dist-version
        $(TAR) rf $(GIT_TARNAME).tar \
 -              $(GIT_TARNAME)/git.spec \
                $(GIT_TARNAME)/configure \
                $(GIT_TARNAME)/version \
                $(GIT_TARNAME)/git-gui/version
        @$(RM) -r $(GIT_TARNAME)
        gzip -f -9 $(GIT_TARNAME).tar
  
 -rpm: dist
 -      $(RPMBUILD) \
 -              --define "_source_filedigest_algorithm md5" \
 -              --define "_binary_filedigest_algorithm md5" \
 -              -ta $(GIT_TARNAME).tar.gz
 +rpm::
 +      @echo >&2 "Use distro packaged sources to run rpmbuild"
 +      @false
 +.PHONY: rpm
  
  htmldocs = git-htmldocs-$(GIT_VERSION)
  manpages = git-manpages-$(GIT_VERSION)
@@@ -2456,8 -2452,8 +2458,8 @@@ profile-clean
        $(RM) $(addsuffix *.gcno,$(addprefix $(PROFILE_DIR)/, $(object_dirs)))
  
  clean: profile-clean coverage-clean
 -      $(RM) *.o *.res refs/*.o block-sha1/*.o ppc/*.o compat/*.o compat/*/*.o
 -      $(RM) xdiff/*.o vcs-svn/*.o ewah/*.o builtin/*.o
 +      $(RM) *.res
 +      $(RM) $(OBJECTS)
        $(RM) $(LIB_FILE) $(XDIFF_LIB) $(VCSSVN_LIB)
        $(RM) $(ALL_PROGRAMS) $(SCRIPT_LIB) $(BUILT_INS) git$X
        $(RM) $(TEST_PROGRAMS) $(NO_INSTALL)
@@@ -2496,7 -2492,6 +2498,7 @@@ ALL_COMMANDS += git-gui git-citoo
  
  .PHONY: check-docs
  check-docs::
 +      $(MAKE) -C Documentation lint-docs
        @(for v in $(ALL_COMMANDS); \
        do \
                case "$$v" in \
diff --combined builtin/fetch.c
index d9ea6f392a158d9a7e12910fa8c7aeba5a6eb41a,b55c83c46891651abc569999e5e6463d158b907c..acd0cf1755eb5afec9dc179b8dc1a93050579023
@@@ -15,7 -15,6 +15,7 @@@
  #include "submodule.h"
  #include "connected.h"
  #include "argv-array.h"
 +#include "utf8.h"
  
  static const char * const builtin_fetch_usage[] = {
        N_("git fetch [<options>] [<repository> [<refspec>...]]"),
@@@ -450,132 -449,7 +450,132 @@@ fail
                           : STORE_REF_ERROR_OTHER;
  }
  
 -#define REFCOL_WIDTH  10
 +static int refcol_width = 10;
 +static int compact_format;
 +
 +static void adjust_refcol_width(const struct ref *ref)
 +{
 +      int max, rlen, llen, len;
 +
 +      /* uptodate lines are only shown on high verbosity level */
 +      if (!verbosity && !oidcmp(&ref->peer_ref->old_oid, &ref->old_oid))
 +              return;
 +
 +      max    = term_columns();
 +      rlen   = utf8_strwidth(prettify_refname(ref->name));
 +
 +      llen   = utf8_strwidth(prettify_refname(ref->peer_ref->name));
 +
 +      /*
 +       * rough estimation to see if the output line is too long and
 +       * should not be counted (we can't do precise calculation
 +       * anyway because we don't know if the error explanation part
 +       * will be printed in update_local_ref)
 +       */
 +      if (compact_format) {
 +              llen = 0;
 +              max = max * 2 / 3;
 +      }
 +      len = 21 /* flag and summary */ + rlen + 4 /* -> */ + llen;
 +      if (len >= max)
 +              return;
 +
 +      /*
 +       * Not precise calculation for compact mode because '*' can
 +       * appear on the left hand side of '->' and shrink the column
 +       * back.
 +       */
 +      if (refcol_width < rlen)
 +              refcol_width = rlen;
 +}
 +
 +static void prepare_format_display(struct ref *ref_map)
 +{
 +      struct ref *rm;
 +      const char *format = "full";
 +
 +      git_config_get_string_const("fetch.output", &format);
 +      if (!strcasecmp(format, "full"))
 +              compact_format = 0;
 +      else if (!strcasecmp(format, "compact"))
 +              compact_format = 1;
 +      else
 +              die(_("configuration fetch.output contains invalid value %s"),
 +                  format);
 +
 +      for (rm = ref_map; rm; rm = rm->next) {
 +              if (rm->status == REF_STATUS_REJECT_SHALLOW ||
 +                  !rm->peer_ref ||
 +                  !strcmp(rm->name, "HEAD"))
 +                      continue;
 +
 +              adjust_refcol_width(rm);
 +      }
 +}
 +
 +static void print_remote_to_local(struct strbuf *display,
 +                                const char *remote, const char *local)
 +{
 +      strbuf_addf(display, "%-*s -> %s", refcol_width, remote, local);
 +}
 +
 +static int find_and_replace(struct strbuf *haystack,
 +                          const char *needle,
 +                          const char *placeholder)
 +{
 +      const char *p = strstr(haystack->buf, needle);
 +      int plen, nlen;
 +
 +      if (!p)
 +              return 0;
 +
 +      if (p > haystack->buf && p[-1] != '/')
 +              return 0;
 +
 +      plen = strlen(p);
 +      nlen = strlen(needle);
 +      if (plen > nlen && p[nlen] != '/')
 +              return 0;
 +
 +      strbuf_splice(haystack, p - haystack->buf, nlen,
 +                    placeholder, strlen(placeholder));
 +      return 1;
 +}
 +
 +static void print_compact(struct strbuf *display,
 +                        const char *remote, const char *local)
 +{
 +      struct strbuf r = STRBUF_INIT;
 +      struct strbuf l = STRBUF_INIT;
 +
 +      if (!strcmp(remote, local)) {
 +              strbuf_addf(display, "%-*s -> *", refcol_width, remote);
 +              return;
 +      }
 +
 +      strbuf_addstr(&r, remote);
 +      strbuf_addstr(&l, local);
 +
 +      if (!find_and_replace(&r, local, "*"))
 +              find_and_replace(&l, remote, "*");
 +      print_remote_to_local(display, r.buf, l.buf);
 +
 +      strbuf_release(&r);
 +      strbuf_release(&l);
 +}
 +
 +static void format_display(struct strbuf *display, char code,
 +                         const char *summary, const char *error,
 +                         const char *remote, const char *local)
 +{
 +      strbuf_addf(display, "%c %-*s ", code, TRANSPORT_SUMMARY(summary));
 +      if (!compact_format)
 +              print_remote_to_local(display, remote, local);
 +      else
 +              print_compact(display, remote, local);
 +      if (error)
 +              strbuf_addf(display, "  (%s)", error);
 +}
  
  static int update_local_ref(struct ref *ref,
                            const char *remote,
  
        if (!oidcmp(&ref->old_oid, &ref->new_oid)) {
                if (verbosity > 0)
 -                      strbuf_addf(display, "= %-*s %-*s -> %s",
 -                                  TRANSPORT_SUMMARY(_("[up to date]")),
 -                                  REFCOL_WIDTH, remote, pretty_ref);
 +                      format_display(display, '=', _("[up to date]"), NULL,
 +                                     remote, pretty_ref);
                return 0;
        }
  
                 * If this is the head, and it's not okay to update
                 * the head, and the old value of the head isn't empty...
                 */
 -              strbuf_addf(display,
 -                          _("! %-*s %-*s -> %s  (can't fetch in current branch)"),
 -                          TRANSPORT_SUMMARY(_("[rejected]")),
 -                          REFCOL_WIDTH, remote, pretty_ref);
 +              format_display(display, '!', _("[rejected]"),
 +                             _("can't fetch in current branch"),
 +                             remote, pretty_ref);
                return 1;
        }
  
            starts_with(ref->name, "refs/tags/")) {
                int r;
                r = s_update_ref("updating tag", ref, 0);
 -              strbuf_addf(display, "%c %-*s %-*s -> %s%s",
 -                          r ? '!' : '-',
 -                          TRANSPORT_SUMMARY(_("[tag update]")),
 -                          REFCOL_WIDTH, remote, pretty_ref,
 -                          r ? _("  (unable to update local ref)") : "");
 +              format_display(display, r ? '!' : 't', _("[tag update]"),
 +                             r ? _("unable to update local ref") : NULL,
 +                             remote, pretty_ref);
                return r;
        }
  
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(ref->new_oid.hash);
                r = s_update_ref(msg, ref, 0);
 -              strbuf_addf(display, "%c %-*s %-*s -> %s%s",
 -                          r ? '!' : '*',
 -                          TRANSPORT_SUMMARY(what),
 -                          REFCOL_WIDTH, remote, pretty_ref,
 -                          r ? _("  (unable to update local ref)") : "");
 +              format_display(display, r ? '!' : '*', what,
 +                             r ? _("unable to update local ref") : NULL,
 +                             remote, pretty_ref);
                return r;
        }
  
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(ref->new_oid.hash);
                r = s_update_ref("fast-forward", ref, 1);
 -              strbuf_addf(display, "%c %-*s %-*s -> %s%s",
 -                          r ? '!' : ' ',
 -                          TRANSPORT_SUMMARY_WIDTH, quickref.buf,
 -                          REFCOL_WIDTH, remote, pretty_ref,
 -                          r ? _("  (unable to update local ref)") : "");
 +              format_display(display, r ? '!' : ' ', quickref.buf,
 +                             r ? _("unable to update local ref") : NULL,
 +                             remote, pretty_ref);
                strbuf_release(&quickref);
                return r;
        } else if (force || ref->force) {
                    (recurse_submodules != RECURSE_SUBMODULES_ON))
                        check_for_new_submodule_commits(ref->new_oid.hash);
                r = s_update_ref("forced-update", ref, 1);
 -              strbuf_addf(display, "%c %-*s %-*s -> %s  (%s)",
 -                          r ? '!' : '+',
 -                          TRANSPORT_SUMMARY_WIDTH, quickref.buf,
 -                          REFCOL_WIDTH, remote, pretty_ref,
 -                          r ? _("unable to update local ref") : _("forced update"));
 +              format_display(display, r ? '!' : '+', quickref.buf,
 +                             r ? _("unable to update local ref") : _("forced update"),
 +                             remote, pretty_ref);
                strbuf_release(&quickref);
                return r;
        } else {
 -              strbuf_addf(display, "! %-*s %-*s -> %s  %s",
 -                          TRANSPORT_SUMMARY(_("[rejected]")),
 -                          REFCOL_WIDTH, remote, pretty_ref,
 -                          _("(non-fast-forward)"));
 +              format_display(display, '!', _("[rejected]"), _("non-fast-forward"),
 +                             remote, pretty_ref);
                return 1;
        }
  }
@@@ -721,7 -607,7 +721,7 @@@ static int store_updated_refs(const cha
  
        fp = fopen(filename, "a");
        if (!fp)
 -              return error(_("cannot open %s: %s\n"), filename, strerror(errno));
 +              return error_errno(_("cannot open %s"), filename);
  
        if (raw_url)
                url = transport_anonymize_url(raw_url);
                goto abort;
        }
  
 +      prepare_format_display(ref_map);
 +
        /*
         * We do a pass for each fetch_head_status type in their enum order, so
         * merged entries are written before not-for-merge. That lets readers
                                rc |= update_local_ref(ref, what, rm, &note);
                                free(ref);
                        } else
 -                              strbuf_addf(&note, "* %-*s %-*s -> FETCH_HEAD",
 -                                          TRANSPORT_SUMMARY_WIDTH,
 -                                          *kind ? kind : "branch",
 -                                          REFCOL_WIDTH,
 -                                          *what ? what : "HEAD");
 +                              format_display(&note, '*',
 +                                             *kind ? kind : "branch", NULL,
 +                                             *what ? what : "HEAD",
 +                                             "FETCH_HEAD");
                        if (note.len) {
                                if (verbosity >= 0 && !shown_url) {
                                        fprintf(stderr, _("From %.*s\n"),
@@@ -921,21 -806,19 +921,21 @@@ static int prune_refs(struct refspec *r
                for (ref = stale_refs; ref; ref = ref->next)
                        string_list_append(&refnames, ref->name);
  
-               result = delete_refs(&refnames);
+               result = delete_refs(&refnames, 0);
                string_list_clear(&refnames, 0);
        }
  
        if (verbosity >= 0) {
                for (ref = stale_refs; ref; ref = ref->next) {
 +                      struct strbuf sb = STRBUF_INIT;
                        if (!shown_url) {
                                fprintf(stderr, _("From %.*s\n"), url_len, url);
                                shown_url = 1;
                        }
 -                      fprintf(stderr, " x %-*s %-*s -> %s\n",
 -                              TRANSPORT_SUMMARY(_("[deleted]")),
 -                              REFCOL_WIDTH, _("(none)"), prettify_refname(ref->name));
 +                      format_display(&sb, '-', _("[deleted]"), NULL,
 +                                     _("(none)"), prettify_refname(ref->name));
 +                      fprintf(stderr, " %s\n",sb.buf);
 +                      strbuf_release(&sb);
                        warn_dangling_symref(stderr, dangling_msg, ref->name);
                }
        }
@@@ -965,7 -848,7 +965,7 @@@ static int truncate_fetch_head(void
        FILE *fp = fopen_for_writing(filename);
  
        if (!fp)
 -              return error(_("cannot open %s: %s\n"), filename, strerror(errno));
 +              return error_errno(_("cannot open %s"), filename);
        fclose(fp);
        return 0;
  }
@@@ -1122,7 -1005,7 +1122,7 @@@ static int get_remote_group(const char 
                        size_t wordlen = strcspn(value, " \t\n");
  
                        if (wordlen >= 1)
 -                              string_list_append(g->list,
 +                              string_list_append_nodup(g->list,
                                                   xstrndup(value, wordlen));
                        value += wordlen + (value[wordlen] != '\0');
                }
@@@ -1260,7 -1143,7 +1260,7 @@@ static int fetch_one(struct remote *rem
  int cmd_fetch(int argc, const char **argv, const char *prefix)
  {
        int i;
 -      struct string_list list = STRING_LIST_INIT_NODUP;
 +      struct string_list list = STRING_LIST_INIT_DUP;
        struct remote *remote;
        int result = 0;
        struct argv_array argv_gc_auto = ARGV_ARRAY_INIT;
                argv_array_clear(&options);
        }
  
 -      /* All names were strdup()ed or strndup()ed */
 -      list.strdup_strings = 1;
        string_list_clear(&list, 0);
  
        close_all_packs();
diff --combined builtin/remote.c
index a4d9c1a8e9c7f0cd36136e26581ba4a3ee828fe8,c4b4d674bd139eac863253fe8c1f2d7441496447..9f6a6b3a9cea036d9a58c52f7d17c2b043a18f33
@@@ -247,7 -247,7 +247,7 @@@ struct branch_info 
        enum { NO_REBASE, NORMAL_REBASE, INTERACTIVE_REBASE } rebase;
  };
  
 -static struct string_list branch_list;
 +static struct string_list branch_list = STRING_LIST_INIT_NODUP;
  
  static const char *abbrev_ref(const char *name, const char *prefix)
  {
@@@ -539,10 -539,6 +539,6 @@@ static int add_branch_for_removal(cons
                return 0;
        }
  
-       /* make sure that symrefs are deleted */
-       if (flags & REF_ISSYMREF)
-               return unlink(git_path("%s", refname));
        string_list_append(branches->branches, refname);
  
        return 0;
@@@ -788,7 -784,7 +784,7 @@@ static int rm(int argc, const char **ar
        strbuf_release(&buf);
  
        if (!result)
-               result = delete_refs(&branches);
+               result = delete_refs(&branches, REF_NODEREF);
        string_list_clear(&branches, 0);
  
        if (skipped.nr) {
@@@ -952,7 -948,7 +948,7 @@@ static int show_local_info_item(struct 
        struct show_info *show_info = cb_data;
        struct branch_info *branch_info = item->util;
        struct string_list *merge = &branch_info->merge;
 -      const char *also;
 +      int width = show_info->width + 4;
        int i;
  
        if (branch_info->rebase && branch_info->merge.nr > 1) {
  
        printf("    %-*s ", show_info->width, item->string);
        if (branch_info->rebase) {
 -              printf_ln(_(branch_info->rebase == INTERACTIVE_REBASE ?
 -                      "rebases interactively onto remote %s" :
 -                      "rebases onto remote %s"), merge->items[0].string);
 +              printf_ln(branch_info->rebase == INTERACTIVE_REBASE
 +                        ? _("rebases interactively onto remote %s")
 +                        : _("rebases onto remote %s"), merge->items[0].string);
                return 0;
        } else if (show_info->any_rebase) {
                printf_ln(_(" merges with remote %s"), merge->items[0].string);
 -              also = _("    and with remote");
 +              width++;
        } else {
                printf_ln(_("merges with remote %s"), merge->items[0].string);
 -              also = _("   and with remote");
        }
        for (i = 1; i < merge->nr; i++)
 -              printf("    %-*s %s %s\n", show_info->width, "", also,
 +              printf(_("%-*s    and with remote %s\n"), width, "",
                       merge->items[i].string);
  
        return 0;
@@@ -1153,15 -1150,13 +1149,15 @@@ static int show(int argc, const char **
                        url_nr = states.remote->url_nr;
                }
                for (i = 0; i < url_nr; i++)
 +                      /* TRANSLATORS: the colon ':' should align with
 +                         the one in "  Fetch URL: %s" translation */
                        printf_ln(_("  Push  URL: %s"), url[i]);
                if (!i)
 -                      printf_ln(_("  Push  URL: %s"), "(no URL)");
 +                      printf_ln(_("  Push  URL: %s"), _("(no URL)"));
                if (no_query)
 -                      printf_ln(_("  HEAD branch: %s"), "(not queried)");
 +                      printf_ln(_("  HEAD branch: %s"), _("(not queried)"));
                else if (!states.heads.nr)
 -                      printf_ln(_("  HEAD branch: %s"), "(unknown)");
 +                      printf_ln(_("  HEAD branch: %s"), _("(unknown)"));
                else if (states.heads.nr == 1)
                        printf_ln(_("  HEAD branch: %s"), states.heads.items[0].string);
                else {
@@@ -1304,7 -1299,7 +1300,7 @@@ static int prune_remote(const char *rem
        string_list_sort(&refs_to_prune);
  
        if (!dry_run)
-               result |= delete_refs(&refs_to_prune);
+               result |= delete_refs(&refs_to_prune, 0);
  
        for_each_string_list_item(item, &states.stale) {
                const char *refname = item->util;
diff --combined refs.h
index 56089d57247c5a22a782848ee622871446c07089,442c1a5db8147262bf2894f3bc47b67683f838b6..1b020437586d4480377080c95adb446f28d03a46
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
  #define RESOLVE_REF_NO_RECURSE 0x02
  #define RESOLVE_REF_ALLOW_BAD_NAME 0x04
  
extern const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
-                                     unsigned char *sha1, int *flags);
+ const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
+                              unsigned char *sha1, int *flags);
  
extern char *resolve_refdup(const char *refname, int resolve_flags,
-                           unsigned char *sha1, int *flags);
+ char *resolve_refdup(const char *refname, int resolve_flags,
+                    unsigned char *sha1, int *flags);
  
extern int read_ref_full(const char *refname, int resolve_flags,
-                        unsigned char *sha1, int *flags);
extern int read_ref(const char *refname, unsigned char *sha1);
+ int read_ref_full(const char *refname, int resolve_flags,
+                 unsigned char *sha1, int *flags);
+ int read_ref(const char *refname, unsigned char *sha1);
  
extern int ref_exists(const char *refname);
+ int ref_exists(const char *refname);
  
extern int is_branch(const char *refname);
+ int is_branch(const char *refname);
  
  /*
   * If refname is a non-symbolic reference that refers to a tag object,
   * Symbolic references are considered unpeelable, even if they
   * ultimately resolve to a peelable tag.
   */
extern int peel_ref(const char *refname, unsigned char *sha1);
+ int peel_ref(const char *refname, unsigned char *sha1);
  
  /**
   * Resolve refname in the nested "gitlink" repository that is located
   * at path.  If the resolution is successful, return 0 and set sha1 to
   * the name of the object; otherwise, return a non-zero value.
   */
- extern int resolve_gitlink_ref(const char *path, const char *refname, unsigned char *sha1);
+ int resolve_gitlink_ref(const char *path, const char *refname,
+                       unsigned char *sha1);
  
  /*
   * Return true iff abbrev_name is a possible abbreviation for
   * full_name according to the rules defined by ref_rev_parse_rules in
   * refs.c.
   */
extern int refname_match(const char *abbrev_name, const char *full_name);
+ int refname_match(const char *abbrev_name, const char *full_name);
  
extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
+ int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);
+ int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);
  
  /*
   * A ref_transaction represents a collection of ref updates
  struct ref_transaction;
  
  /*
-  * Bit values set in the flags argument passed to each_ref_fn():
+  * Bit values set in the flags argument passed to each_ref_fn() and
+  * stored in ref_iterator::flags. Other bits are for internal use
+  * only:
   */
  
  /* Reference is a symbolic reference. */
@@@ -182,38 -185,45 +185,45 @@@ typedef int each_ref_fn(const char *ref
   * modifies the reference also returns a nonzero value to immediately
   * stop the iteration.
   */
- extern int head_ref(each_ref_fn fn, void *cb_data);
- extern int for_each_ref(each_ref_fn fn, void *cb_data);
- extern int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
- extern int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken);
- extern int for_each_tag_ref(each_ref_fn fn, void *cb_data);
- extern int for_each_branch_ref(each_ref_fn fn, void *cb_data);
- extern int for_each_remote_ref(each_ref_fn fn, void *cb_data);
- extern int for_each_replace_ref(each_ref_fn fn, void *cb_data);
- extern int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
- extern int for_each_glob_ref_in(each_ref_fn fn, const char *pattern, const char *prefix, void *cb_data);
- extern int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
- extern int for_each_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
- extern int for_each_ref_in_submodule(const char *submodule, const char *prefix,
+ int head_ref(each_ref_fn fn, void *cb_data);
+ int for_each_ref(each_ref_fn fn, void *cb_data);
+ int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data);
+ int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data,
+                       unsigned int broken);
+ int for_each_tag_ref(each_ref_fn fn, void *cb_data);
+ int for_each_branch_ref(each_ref_fn fn, void *cb_data);
+ int for_each_remote_ref(each_ref_fn fn, void *cb_data);
+ int for_each_replace_ref(each_ref_fn fn, void *cb_data);
+ int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
+ int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
+                        const char *prefix, void *cb_data);
+ int head_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
+ int for_each_ref_submodule(const char *submodule,
+                          each_ref_fn fn, void *cb_data);
+ int for_each_ref_in_submodule(const char *submodule, const char *prefix,
                each_ref_fn fn, void *cb_data);
- extern int for_each_tag_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
- extern int for_each_branch_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
- extern int for_each_remote_ref_submodule(const char *submodule, each_ref_fn fn, void *cb_data);
+ int for_each_tag_ref_submodule(const char *submodule,
+                              each_ref_fn fn, void *cb_data);
+ int for_each_branch_ref_submodule(const char *submodule,
+                                 each_ref_fn fn, void *cb_data);
+ int for_each_remote_ref_submodule(const char *submodule,
+                                 each_ref_fn fn, void *cb_data);
  
extern int head_ref_namespaced(each_ref_fn fn, void *cb_data);
extern int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
+ int head_ref_namespaced(each_ref_fn fn, void *cb_data);
+ int for_each_namespaced_ref(each_ref_fn fn, void *cb_data);
  
  /* can be used to learn about broken ref and symref */
extern int for_each_rawref(each_ref_fn fn, void *cb_data);
+ int for_each_rawref(each_ref_fn fn, void *cb_data);
  
  static inline const char *has_glob_specials(const char *pattern)
  {
        return strpbrk(pattern, "?*[");
  }
  
- extern void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
- extern void warn_dangling_symrefs(FILE *fp, const char *msg_fmt, const struct string_list *refnames);
+ void warn_dangling_symref(FILE *fp, const char *msg_fmt, const char *refname);
+ void warn_dangling_symrefs(FILE *fp, const char *msg_fmt,
+                          const struct string_list *refnames);
  
  /*
   * Flags for controlling behaviour of pack_refs()
@@@ -245,13 -255,13 +255,13 @@@ int pack_refs(unsigned int flags)
  int safe_create_reflog(const char *refname, int force_create, struct strbuf *err);
  
  /** Reads log for the value of ref during at_time. **/
extern int read_ref_at(const char *refname, unsigned int flags,
-                      unsigned long at_time, int cnt,
-                      unsigned char *sha1, char **msg,
-                      unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);
+ int read_ref_at(const char *refname, unsigned int flags,
+               unsigned long at_time, int cnt,
+               unsigned char *sha1, char **msg,
+               unsigned long *cutoff_time, int *cutoff_tz, int *cutoff_cnt);
  
  /** Check if a particular reflog exists */
extern int reflog_exists(const char *refname);
+ int reflog_exists(const char *refname);
  
  /*
   * Delete the specified reference. If old_sha1 is non-NULL, then
   * exists, regardless of its old value. It is an error for old_sha1 to
   * be NULL_SHA1. flags is passed through to ref_transaction_delete().
   */
extern int delete_ref(const char *refname, const unsigned char *old_sha1,
-                     unsigned int flags);
+ int delete_ref(const char *refname, const unsigned char *old_sha1,
+              unsigned int flags);
  
  /*
   * Delete the specified references. If there are any problems, emit
   * errors but attempt to keep going (i.e., the deletes are not done in
-  * an all-or-nothing transaction).
+  * an all-or-nothing transaction). flags is passed through to
+  * ref_transaction_delete().
   */
extern int delete_refs(struct string_list *refnames);
int delete_refs(struct string_list *refnames, unsigned int flags);
  
  /** Delete a reflog */
extern int delete_reflog(const char *refname);
+ int delete_reflog(const char *refname);
  
  /* iterate over reflog entries */
- typedef int each_reflog_ent_fn(unsigned char *osha1, unsigned char *nsha1, const char *, unsigned long, int, const char *, void *);
+ typedef int each_reflog_ent_fn(
+               unsigned char *old_sha1, unsigned char *new_sha1,
+               const char *committer, unsigned long timestamp,
+               int tz, const char *msg, void *cb_data);
  int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn, void *cb_data);
  int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn, void *cb_data);
  
   * Calls the specified function for each reflog file until it returns nonzero,
   * and returns the value
   */
extern int for_each_reflog(each_ref_fn, void *);
int for_each_reflog(each_ref_fn fn, void *cb_data);
  
  #define REFNAME_ALLOW_ONELEVEL 1
  #define REFNAME_REFSPEC_PATTERN 2
   * allow a single "*" wildcard character in the refspec. No leading or
   * repeated slashes are accepted.
   */
extern int check_refname_format(const char *refname, int flags);
+ int check_refname_format(const char *refname, int flags);
  
extern const char *prettify_refname(const char *refname);
+ const char *prettify_refname(const char *refname);
  
extern char *shorten_unambiguous_ref(const char *refname, int strict);
+ char *shorten_unambiguous_ref(const char *refname, int strict);
  
  /** rename ref, return 0 on success **/
extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);
+ int rename_ref(const char *oldref, const char *newref, const char *logmsg);
  
extern int create_symref(const char *refname, const char *target, const char *logmsg);
+ int create_symref(const char *refname, const char *target, const char *logmsg);
  
  /*
   * Update HEAD of the specified gitdir.
   * $GIT_DIR points to.
   * Return 0 if successful, non-zero otherwise.
   * */
extern int set_worktree_head_symref(const char *gitdir, const char *target);
+ int set_worktree_head_symref(const char *gitdir, const char *target);
  
  enum action_on_err {
        UPDATE_REFS_MSG_ON_ERR,
@@@ -345,7 -360,7 +360,7 @@@ struct ref_transaction *ref_transaction
   *     msg -- a message describing the change (for the reflog).
   *
   *     err -- a strbuf for receiving a description of any error that
 - *         might have occured.
 + *         might have occurred.
   *
   * The functions make internal copies of refname and msg, so the
   * caller retains ownership of these parameters.
@@@ -463,7 -478,7 +478,7 @@@ int update_ref(const char *msg, const c
               const unsigned char *new_sha1, const unsigned char *old_sha1,
               unsigned int flags, enum action_on_err onerr);
  
extern int parse_hide_refs_config(const char *var, const char *value, const char *);
+ int parse_hide_refs_config(const char *var, const char *value, const char *);
  
  /*
   * Check whether a ref is hidden. If no namespace is set, both the first and
   * the ref is outside that namespace, the first parameter is NULL. The second
   * parameter always points to the full ref name.
   */
extern int ref_is_hidden(const char *, const char *);
+ int ref_is_hidden(const char *, const char *);
  
  enum ref_type {
        REF_TYPE_PER_WORKTREE,
@@@ -522,11 -537,11 +537,11 @@@ typedef void reflog_expiry_cleanup_fn(v
   * enum expire_reflog_flags. The three function pointers are described
   * above. On success, return zero.
   */
extern int reflog_expire(const char *refname, const unsigned char *sha1,
-                        unsigned int flags,
-                        reflog_expiry_prepare_fn prepare_fn,
-                        reflog_expiry_should_prune_fn should_prune_fn,
-                        reflog_expiry_cleanup_fn cleanup_fn,
-                        void *policy_cb_data);
+ int reflog_expire(const char *refname, const unsigned char *sha1,
+                 unsigned int flags,
+                 reflog_expiry_prepare_fn prepare_fn,
+                 reflog_expiry_should_prune_fn should_prune_fn,
+                 reflog_expiry_cleanup_fn cleanup_fn,
+                 void *policy_cb_data);
  
  #endif /* REFS_H */
diff --combined refs/files-backend.c
index 1bf643025cf25f34f3f0ea3f28822459a0b0a11a,a9ca003bae114abb67010cd1798e89eddab4060f..12290d249643b5aaab18961ca91637910d0d7261
@@@ -1,6 -1,8 +1,8 @@@
  #include "../cache.h"
  #include "../refs.h"
  #include "refs-internal.h"
+ #include "../iterator.h"
+ #include "../dir-iterator.h"
  #include "../lockfile.h"
  #include "../object.h"
  #include "../dir.h"
@@@ -513,68 -515,36 +515,36 @@@ static void sort_ref_dir(struct ref_di
  }
  
  /*
-  * Return true iff the reference described by entry can be resolved to
-  * an object in the database.  Emit a warning if the referred-to
-  * object does not exist.
+  * 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
+  * does not exist, emit a warning and return false.
   */
- static int ref_resolves_to_object(struct ref_entry *entry)
+ static int ref_resolves_to_object(const char *refname,
+                                 const struct object_id *oid,
+                                 unsigned int flags)
  {
-       if (entry->flag & REF_ISBROKEN)
+       if (flags & REF_ISBROKEN)
                return 0;
-       if (!has_sha1_file(entry->u.value.oid.hash)) {
-               error("%s does not point to a valid object!", entry->name);
+       if (!has_sha1_file(oid->hash)) {
+               error("%s does not point to a valid object!", refname);
                return 0;
        }
        return 1;
  }
  
  /*
-  * current_ref is a performance hack: when iterating over references
-  * using the for_each_ref*() functions, current_ref is set to the
-  * current reference's entry before calling the callback function.  If
-  * the callback function calls peel_ref(), then peel_ref() first
-  * checks whether the reference to be peeled is the current reference
-  * (it usually is) and if so, returns that reference's peeled version
-  * if it is available.  This avoids a refname lookup in a common case.
+  * 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 struct ref_entry *current_ref;
- typedef int each_ref_entry_fn(struct ref_entry *entry, void *cb_data);
- struct ref_entry_cb {
-       const char *base;
-       int trim;
-       int flags;
-       each_ref_fn *fn;
-       void *cb_data;
- };
- /*
-  * Handle one reference in a do_for_each_ref*()-style iteration,
-  * calling an each_ref_fn for each entry.
-  */
- static int do_one_ref(struct ref_entry *entry, void *cb_data)
+ static int entry_resolves_to_object(struct ref_entry *entry)
  {
-       struct ref_entry_cb *data = cb_data;
-       struct ref_entry *old_current_ref;
-       int retval;
-       if (!starts_with(entry->name, data->base))
-               return 0;
-       if (!(data->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
-             !ref_resolves_to_object(entry))
-               return 0;
-       /* Store the old value, in case this is a recursive call: */
-       old_current_ref = current_ref;
-       current_ref = entry;
-       retval = data->fn(entry->name + data->trim, &entry->u.value.oid,
-                         entry->flag, data->cb_data);
-       current_ref = old_current_ref;
-       return retval;
+       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
@@@ -603,78 -573,6 +573,6 @@@ static int do_for_each_entry_in_dir(str
        return 0;
  }
  
- /*
-  * Call fn for each reference in the union of dir1 and dir2, in order
-  * by refname.  Recurse into subdirectories.  If a value entry appears
-  * in both dir1 and dir2, then only process the version that is in
-  * dir2.  The input dirs must already be sorted, but subdirs will be
-  * sorted as needed.  fn is called for all references, including
-  * broken ones.
-  */
- static int do_for_each_entry_in_dirs(struct ref_dir *dir1,
-                                    struct ref_dir *dir2,
-                                    each_ref_entry_fn fn, void *cb_data)
- {
-       int retval;
-       int i1 = 0, i2 = 0;
-       assert(dir1->sorted == dir1->nr);
-       assert(dir2->sorted == dir2->nr);
-       while (1) {
-               struct ref_entry *e1, *e2;
-               int cmp;
-               if (i1 == dir1->nr) {
-                       return do_for_each_entry_in_dir(dir2, i2, fn, cb_data);
-               }
-               if (i2 == dir2->nr) {
-                       return do_for_each_entry_in_dir(dir1, i1, fn, cb_data);
-               }
-               e1 = dir1->entries[i1];
-               e2 = dir2->entries[i2];
-               cmp = strcmp(e1->name, e2->name);
-               if (cmp == 0) {
-                       if ((e1->flag & REF_DIR) && (e2->flag & REF_DIR)) {
-                               /* Both are directories; descend them in parallel. */
-                               struct ref_dir *subdir1 = get_ref_dir(e1);
-                               struct ref_dir *subdir2 = get_ref_dir(e2);
-                               sort_ref_dir(subdir1);
-                               sort_ref_dir(subdir2);
-                               retval = do_for_each_entry_in_dirs(
-                                               subdir1, subdir2, fn, cb_data);
-                               i1++;
-                               i2++;
-                       } else if (!(e1->flag & REF_DIR) && !(e2->flag & REF_DIR)) {
-                               /* Both are references; ignore the one from dir1. */
-                               retval = fn(e2, cb_data);
-                               i1++;
-                               i2++;
-                       } else {
-                               die("conflict between reference and directory: %s",
-                                   e1->name);
-                       }
-               } else {
-                       struct ref_entry *e;
-                       if (cmp < 0) {
-                               e = e1;
-                               i1++;
-                       } else {
-                               e = e2;
-                               i2++;
-                       }
-                       if (e->flag & REF_DIR) {
-                               struct ref_dir *subdir = get_ref_dir(e);
-                               sort_ref_dir(subdir);
-                               retval = do_for_each_entry_in_dir(
-                                               subdir, 0, fn, cb_data);
-                       } else {
-                               retval = fn(e, cb_data);
-                       }
-               }
-               if (retval)
-                       return retval;
-       }
- }
  /*
   * 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
@@@ -691,6 -589,153 +589,153 @@@ static void prime_ref_dir(struct ref_di
        }
  }
  
+ /*
+  * 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;
+       hashcpy(peeled->hash, entry->u.value.peeled.hash);
+       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;
@@@ -954,15 -999,26 +999,26 @@@ static struct ref_cache *lookup_ref_cac
  
  /*
   * Return a pointer to a ref_cache for the specified submodule. For
-  * the main repository, use submodule==NULL. The returned structure
-  * will be allocated and initialized but not necessarily populated; it
-  * should not be freed.
+  * the main repository, use submodule==NULL; such a call cannot fail.
+  * For a submodule, the submodule must exist and be a nonbare
+  * repository, otherwise return NULL.
+  *
+  * The returned structure will be allocated and initialized but not
+  * necessarily populated; it should not be freed.
   */
  static struct ref_cache *get_ref_cache(const char *submodule)
  {
        struct ref_cache *refs = lookup_ref_cache(submodule);
-       if (!refs)
-               refs = create_ref_cache(submodule);
+       if (!refs) {
+               struct strbuf submodule_sb = STRBUF_INIT;
+               strbuf_addstr(&submodule_sb, submodule);
+               if (is_nonbare_repository_dir(&submodule_sb))
+                       refs = create_ref_cache(submodule);
+               strbuf_release(&submodule_sb);
+       }
        return refs;
  }
  
@@@ -1341,13 -1397,10 +1397,10 @@@ int resolve_gitlink_ref(const char *pat
                return -1;
  
        strbuf_add(&submodule, path, len);
-       refs = lookup_ref_cache(submodule.buf);
+       refs = get_ref_cache(submodule.buf);
        if (!refs) {
-               if (!is_nonbare_repository_dir(&submodule)) {
-                       strbuf_release(&submodule);
-                       return -1;
-               }
-               refs = create_ref_cache(submodule.buf);
+               strbuf_release(&submodule);
+               return -1;
        }
        strbuf_release(&submodule);
  
@@@ -1790,11 -1843,12 +1843,12 @@@ int peel_ref(const char *refname, unsig
        int flag;
        unsigned char base[20];
  
-       if (current_ref && (current_ref->name == refname
-                           || !strcmp(current_ref->name, refname))) {
-               if (peel_entry(current_ref, 0))
+       if (current_ref_iter && current_ref_iter->refname == refname) {
+               struct object_id peeled;
+               if (ref_iterator_peel(current_ref_iter, &peeled))
                        return -1;
-               hashcpy(sha1, current_ref->u.value.peeled.hash);
+               hashcpy(sha1, peeled.hash);
                return 0;
        }
  
        return peel_object(base, sha1);
  }
  
- /*
-  * Call fn for each reference in the specified ref_cache, omitting
-  * references not in the containing_dir of base.  fn is called for all
-  * references, including broken ones.  If fn ever returns a non-zero
-  * value, stop the iteration and return that value; otherwise, return
-  * 0.
-  */
- static int do_for_each_entry(struct ref_cache *refs, const char *base,
-                            each_ref_entry_fn fn, void *cb_data)
- {
+ struct files_ref_iterator {
+       struct ref_iterator base;
        struct packed_ref_cache *packed_ref_cache;
-       struct ref_dir *loose_dir;
-       struct ref_dir *packed_dir;
      int retval = 0;
+       struct ref_iterator *iter0;
+       unsigned int flags;
};
  
-       /*
-        * We must make sure that all loose refs are read before accessing the
-        * packed-refs file; this avoids a race condition in which loose refs
-        * are migrated to the packed-refs file by a simultaneous process, but
-        * our in-memory view is from before the migration. get_packed_ref_cache()
-        * takes care of making sure our view is up to date with what is on
-        * disk.
-        */
-       loose_dir = get_loose_refs(refs);
-       if (base && *base) {
-               loose_dir = find_containing_dir(loose_dir, base, 0);
-       }
-       if (loose_dir)
-               prime_ref_dir(loose_dir);
+ static int files_ref_iterator_advance(struct ref_iterator *ref_iterator)
+ {
+       struct files_ref_iterator *iter =
+               (struct files_ref_iterator *)ref_iterator;
+       int ok;
  
-       packed_ref_cache = get_packed_ref_cache(refs);
-       acquire_packed_ref_cache(packed_ref_cache);
-       packed_dir = get_packed_ref_dir(packed_ref_cache);
-       if (base && *base) {
-               packed_dir = find_containing_dir(packed_dir, base, 0);
-       }
-       if (packed_dir && loose_dir) {
-               sort_ref_dir(packed_dir);
-               sort_ref_dir(loose_dir);
-               retval = do_for_each_entry_in_dirs(
-                               packed_dir, loose_dir, fn, cb_data);
-       } else if (packed_dir) {
-               sort_ref_dir(packed_dir);
-               retval = do_for_each_entry_in_dir(
-                               packed_dir, 0, fn, cb_data);
-       } else if (loose_dir) {
-               sort_ref_dir(loose_dir);
-               retval = do_for_each_entry_in_dir(
-                               loose_dir, 0, fn, cb_data);
+       while ((ok = ref_iterator_advance(iter->iter0)) == ITER_OK) {
+               if (!(iter->flags & DO_FOR_EACH_INCLUDE_BROKEN) &&
+                   !ref_resolves_to_object(iter->iter0->refname,
+                                           iter->iter0->oid,
+                                           iter->iter0->flags))
+                       continue;
+               iter->base.refname = iter->iter0->refname;
+               iter->base.oid = iter->iter0->oid;
+               iter->base.flags = iter->iter0->flags;
+               return ITER_OK;
        }
  
-       release_packed_ref_cache(packed_ref_cache);
-       return retval;
+       iter->iter0 = NULL;
+       if (ref_iterator_abort(ref_iterator) != ITER_DONE)
+               ok = ITER_ERROR;
+       return ok;
  }
  
- /*
-  * Call fn for each reference in the specified ref_cache for which the
-  * refname begins with base.  If trim is non-zero, then trim that many
-  * characters off the beginning of each refname before passing the
-  * refname to fn.  flags can be DO_FOR_EACH_INCLUDE_BROKEN to include
-  * broken references in the iteration.  If fn ever returns a non-zero
-  * value, stop the iteration and return that value; otherwise, return
-  * 0.
-  */
- int do_for_each_ref(const char *submodule, const char *base,
-                   each_ref_fn fn, int trim, int flags, void *cb_data)
+ static int files_ref_iterator_peel(struct ref_iterator *ref_iterator,
+                                  struct object_id *peeled)
  {
-       struct ref_entry_cb data;
-       struct ref_cache *refs;
+       struct files_ref_iterator *iter =
+               (struct files_ref_iterator *)ref_iterator;
  
-       refs = get_ref_cache(submodule);
-       data.base = base;
-       data.trim = trim;
-       data.flags = flags;
-       data.fn = fn;
-       data.cb_data = cb_data;
+       return ref_iterator_peel(iter->iter0, peeled);
+ }
+ static int files_ref_iterator_abort(struct ref_iterator *ref_iterator)
+ {
+       struct files_ref_iterator *iter =
+               (struct files_ref_iterator *)ref_iterator;
+       int ok = ITER_DONE;
+       if (iter->iter0)
+               ok = ref_iterator_abort(iter->iter0);
+       release_packed_ref_cache(iter->packed_ref_cache);
+       base_ref_iterator_free(ref_iterator);
+       return ok;
+ }
+ static struct ref_iterator_vtable files_ref_iterator_vtable = {
+       files_ref_iterator_advance,
+       files_ref_iterator_peel,
+       files_ref_iterator_abort
+ };
+ struct ref_iterator *files_ref_iterator_begin(
+               const char *submodule,
+               const char *prefix, unsigned int flags)
+ {
+       struct ref_cache *refs = get_ref_cache(submodule);
+       struct ref_dir *loose_dir, *packed_dir;
+       struct ref_iterator *loose_iter, *packed_iter;
+       struct files_ref_iterator *iter;
+       struct ref_iterator *ref_iterator;
+       if (!refs)
+               return empty_ref_iterator_begin();
  
        if (ref_paranoia < 0)
                ref_paranoia = git_env_bool("GIT_REF_PARANOIA", 0);
        if (ref_paranoia)
-               data.flags |= DO_FOR_EACH_INCLUDE_BROKEN;
+               flags |= DO_FOR_EACH_INCLUDE_BROKEN;
+       iter = xcalloc(1, sizeof(*iter));
+       ref_iterator = &iter->base;
+       base_ref_iterator_init(ref_iterator, &files_ref_iterator_vtable);
+       /*
+        * We must make sure that all loose refs are read before
+        * accessing the packed-refs file; this avoids a race
+        * 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.
+        */
+       loose_dir = get_loose_refs(refs);
+       if (prefix && *prefix)
+               loose_dir = find_containing_dir(loose_dir, prefix, 0);
  
-       return do_for_each_entry(refs, base, do_one_ref, &data);
+       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();
+       }
+       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();
+       }
+       iter->iter0 = overlay_ref_iterator_begin(loose_iter, packed_iter);
+       iter->flags = flags;
+       return ref_iterator;
  }
  
  /*
@@@ -1929,14 -2030,14 +2030,14 @@@ static int verify_lock(struct ref_lock 
                        errno = save_errno;
                        return -1;
                } else {
 -                      hashclr(lock->old_oid.hash);
 +                      oidclr(&lock->old_oid);
                        return 0;
                }
        }
        if (old_sha1 && hashcmp(lock->old_oid.hash, old_sha1)) {
                strbuf_addf(err, "ref '%s' is at %s but expected %s",
                            lock->ref_name,
 -                          sha1_to_hex(lock->old_oid.hash),
 +                          oid_to_hex(&lock->old_oid),
                            sha1_to_hex(old_sha1));
                errno = EBUSY;
                return -1;
@@@ -2226,7 -2327,7 +2327,7 @@@ static int pack_if_possible_fn(struct r
                return 0;
  
        /* Do not pack symbolic or broken refs: */
-       if ((entry->flag & REF_ISSYMREF) || !ref_resolves_to_object(entry))
+       if ((entry->flag & REF_ISSYMREF) || !entry_resolves_to_object(entry))
                return 0;
  
        /* Add a packed ref cache entry equivalent to the loose entry. */
@@@ -2412,7 -2513,7 +2513,7 @@@ static int delete_ref_loose(struct ref_
        return 0;
  }
  
- int delete_refs(struct string_list *refnames)
+ int delete_refs(struct string_list *refnames, unsigned int flags)
  {
        struct strbuf err = STRBUF_INIT;
        int i, result = 0;
        for (i = 0; i < refnames->nr; i++) {
                const char *refname = refnames->items[i].string;
  
-               if (delete_ref(refname, NULL, 0))
+               if (delete_ref(refname, NULL, flags))
                        result |= error(_("could not remove reference %s"), refname);
        }
  
@@@ -3191,60 -3292,88 +3292,88 @@@ int for_each_reflog_ent(const char *ref
        strbuf_release(&sb);
        return ret;
  }
- /*
-  * Call fn for each reflog in the namespace indicated by name.  name
-  * must be empty or end with '/'.  Name will be used as a scratch
-  * space, but its contents will be restored before return.
-  */
- static int do_for_each_reflog(struct strbuf *name, each_ref_fn fn, void *cb_data)
- {
-       DIR *d = opendir(git_path("logs/%s", name->buf));
-       int retval = 0;
-       struct dirent *de;
-       int oldlen = name->len;
  
-       if (!d)
-               return name->len ? errno : 0;
+ struct files_reflog_iterator {
+       struct ref_iterator base;
  
-       while ((de = readdir(d)) != NULL) {
-               struct stat st;
+       struct dir_iterator *dir_iterator;
+       struct object_id oid;
+ };
  
-               if (de->d_name[0] == '.')
+ static int files_reflog_iterator_advance(struct ref_iterator *ref_iterator)
+ {
+       struct files_reflog_iterator *iter =
+               (struct files_reflog_iterator *)ref_iterator;
+       struct dir_iterator *diter = iter->dir_iterator;
+       int ok;
+       while ((ok = dir_iterator_advance(diter)) == ITER_OK) {
+               int flags;
+               if (!S_ISREG(diter->st.st_mode))
                        continue;
-               if (ends_with(de->d_name, ".lock"))
+               if (diter->basename[0] == '.')
+                       continue;
+               if (ends_with(diter->basename, ".lock"))
                        continue;
-               strbuf_addstr(name, de->d_name);
-               if (stat(git_path("logs/%s", name->buf), &st) < 0) {
-                       ; /* silently ignore */
-               } else {
-                       if (S_ISDIR(st.st_mode)) {
-                               strbuf_addch(name, '/');
-                               retval = do_for_each_reflog(name, fn, cb_data);
-                       } else {
-                               struct object_id oid;
  
-                               if (read_ref_full(name->buf, 0, oid.hash, NULL))
-                                       retval = error("bad ref for %s", name->buf);
-                               else
-                                       retval = fn(name->buf, &oid, 0, cb_data);
-                       }
-                       if (retval)
-                               break;
+               if (read_ref_full(diter->relative_path, 0,
+                                 iter->oid.hash, &flags)) {
+                       error("bad ref for %s", diter->path.buf);
+                       continue;
                }
-               strbuf_setlen(name, oldlen);
+               iter->base.refname = diter->relative_path;
+               iter->base.oid = &iter->oid;
+               iter->base.flags = flags;
+               return ITER_OK;
        }
-       closedir(d);
-       return retval;
+       iter->dir_iterator = NULL;
+       if (ref_iterator_abort(ref_iterator) == ITER_ERROR)
+               ok = ITER_ERROR;
+       return ok;
+ }
+ static int files_reflog_iterator_peel(struct ref_iterator *ref_iterator,
+                                  struct object_id *peeled)
+ {
+       die("BUG: ref_iterator_peel() called for reflog_iterator");
+ }
+ static int files_reflog_iterator_abort(struct ref_iterator *ref_iterator)
+ {
+       struct files_reflog_iterator *iter =
+               (struct files_reflog_iterator *)ref_iterator;
+       int ok = ITER_DONE;
+       if (iter->dir_iterator)
+               ok = dir_iterator_abort(iter->dir_iterator);
+       base_ref_iterator_free(ref_iterator);
+       return ok;
+ }
+ static struct ref_iterator_vtable files_reflog_iterator_vtable = {
+       files_reflog_iterator_advance,
+       files_reflog_iterator_peel,
+       files_reflog_iterator_abort
+ };
+ struct ref_iterator *files_reflog_iterator_begin(void)
+ {
+       struct files_reflog_iterator *iter = xcalloc(1, sizeof(*iter));
+       struct ref_iterator *ref_iterator = &iter->base;
+       base_ref_iterator_init(ref_iterator, &files_reflog_iterator_vtable);
+       iter->dir_iterator = dir_iterator_begin(git_path("logs"));
+       return ref_iterator;
  }
  
  int for_each_reflog(each_ref_fn fn, void *cb_data)
  {
-       int retval;
-       struct strbuf name;
-       strbuf_init(&name, PATH_MAX);
-       retval = do_for_each_reflog(&name, fn, cb_data);
-       strbuf_release(&name);
-       return retval;
+       return do_for_each_ref_iterator(files_reflog_iterator_begin(),
+                                       fn, cb_data);
  }
  
  static int ref_update_reject_duplicates(struct string_list *refnames,
@@@ -3388,38 -3517,6 +3517,38 @@@ static const char *original_update_refn
        return update->refname;
  }
  
 +/*
 + * Check whether the REF_HAVE_OLD and old_oid values stored in update
 + * are consistent with oid, which is the reference's current value. If
 + * everything is OK, return 0; otherwise, write an error message to
 + * err and return -1.
 + */
 +static int check_old_oid(struct ref_update *update, struct object_id *oid,
 +                       struct strbuf *err)
 +{
 +      if (!(update->flags & REF_HAVE_OLD) ||
 +                 !hashcmp(oid->hash, update->old_sha1))
 +              return 0;
 +
 +      if (is_null_sha1(update->old_sha1))
 +              strbuf_addf(err, "cannot lock ref '%s': "
 +                          "reference already exists",
 +                          original_update_refname(update));
 +      else if (is_null_oid(oid))
 +              strbuf_addf(err, "cannot lock ref '%s': "
 +                          "reference is missing but expected %s",
 +                          original_update_refname(update),
 +                          sha1_to_hex(update->old_sha1));
 +      else
 +              strbuf_addf(err, "cannot lock ref '%s': "
 +                          "is at %s but expected %s",
 +                          original_update_refname(update),
 +                          oid_to_hex(oid),
 +                          sha1_to_hex(update->old_sha1));
 +
 +      return -1;
 +}
 +
  /*
   * Prepare for carrying out update:
   * - Lock the reference referred to by update.
@@@ -3465,7 -3562,7 +3594,7 @@@ static int lock_ref_for_update(struct r
  
                reason = strbuf_detach(err, NULL);
                strbuf_addf(err, "cannot lock ref '%s': %s",
 -                          update->refname, reason);
 +                          original_update_refname(update), reason);
                free(reason);
                return ret;
        }
                         * the transaction, so we have to read it here
                         * to record and possibly check old_sha1:
                         */
 -                      if (read_ref_full(update->refname,
 -                                        mustexist ? RESOLVE_REF_READING : 0,
 +                      if (read_ref_full(referent.buf, 0,
                                          lock->old_oid.hash, NULL)) {
                                if (update->flags & REF_HAVE_OLD) {
                                        strbuf_addf(err, "cannot lock ref '%s': "
 -                                                  "can't resolve old value",
 -                                                  update->refname);
 -                                      return TRANSACTION_GENERIC_ERROR;
 -                              } else {
 -                                      hashclr(lock->old_oid.hash);
 +                                                  "error reading reference",
 +                                                  original_update_refname(update));
 +                                      return -1;
                                }
 -                      }
 -                      if ((update->flags & REF_HAVE_OLD) &&
 -                          hashcmp(lock->old_oid.hash, update->old_sha1)) {
 -                              strbuf_addf(err, "cannot lock ref '%s': "
 -                                          "is at %s but expected %s",
 -                                          update->refname,
 -                                          sha1_to_hex(lock->old_oid.hash),
 -                                          sha1_to_hex(update->old_sha1));
 +                      } else if (check_old_oid(update, &lock->old_oid, err)) {
                                return TRANSACTION_GENERIC_ERROR;
                        }
 -
                } else {
                        /*
                         * Create a new update for the reference this
        } else {
                struct ref_update *parent_update;
  
 +              if (check_old_oid(update, &lock->old_oid, err))
 +                      return TRANSACTION_GENERIC_ERROR;
 +
                /*
                 * If this update is happening indirectly because of a
                 * symref update, record the old SHA-1 in the parent
                     parent_update = parent_update->parent_update) {
                        oidcpy(&parent_update->lock->old_oid, &lock->old_oid);
                }
 -
 -              if ((update->flags & REF_HAVE_OLD) &&
 -                  hashcmp(lock->old_oid.hash, update->old_sha1)) {
 -                      if (is_null_sha1(update->old_sha1))
 -                              strbuf_addf(err, "cannot lock ref '%s': reference already exists",
 -                                          original_update_refname(update));
 -                      else
 -                              strbuf_addf(err, "cannot lock ref '%s': is at %s but expected %s",
 -                                          original_update_refname(update),
 -                                          sha1_to_hex(lock->old_oid.hash),
 -                                          sha1_to_hex(update->old_sha1));
 -
 -                      return TRANSACTION_GENERIC_ERROR;
 -              }
        }
  
        if ((update->flags & REF_HAVE_NEW) &&
                         */
                        update->lock = NULL;
                        strbuf_addf(err,
 -                                  "cannot update the ref '%s': %s",
 +                                  "cannot update ref '%s': %s",
                                    update->refname, write_err);
                        free(write_err);
                        return TRANSACTION_GENERIC_ERROR;