Merge branch 'dt/refs-backend-preamble'
authorJunio C Hamano <gitster@pobox.com>
Mon, 3 Aug 2015 18:01:29 +0000 (11:01 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 3 Aug 2015 18:01:29 +0000 (11:01 -0700)
In preparation for allowing different "backends" to store the refs
in a way different from the traditional "one ref per file in $GIT_DIR
or in a $GIT_DIR/packed-refs file" filesystem storage, reduce
direct filesystem access to ref-like things like CHERRY_PICK_HEAD
from scripts and programs.

* dt/refs-backend-preamble:
git-stash: use update-ref --create-reflog instead of creating files
update-ref and tag: add --create-reflog arg
refs: add REF_FORCE_CREATE_REFLOG flag
git-reflog: add exists command
refs: new public ref function: safe_create_reflog
refs: break out check for reflog autocreation
refs.c: add err arguments to reflog functions

1  2 
Documentation/git-tag.txt
builtin/checkout.c
builtin/update-ref.c
refs.c
refs.h
index 4b04c2b7d500521f1cf963a89ed010512faa29c6,231298065fa0d2a2c94b022f7e0ecc348479ce95..84f6496bf228454acaa04e570f7857ba1975cda4
@@@ -13,7 -13,8 +13,7 @@@ SYNOPSI
        <tagname> [<commit> | <object>]
  'git tag' -d <tagname>...
  'git tag' [-n[<num>]] -l [--contains <commit>] [--points-at <object>]
-       [--column[=<options>] | --no-column] [<pattern>...]
+       [--column[=<options>] | --no-column] [--create-reflog] [<pattern>...]
 -      [<pattern>...]
  'git tag' -v <tagname>...
  
  DESCRIPTION
@@@ -142,6 -143,9 +142,9 @@@ This option is only applicable when lis
        all, 'whitespace' removes just leading/trailing whitespace lines and
        'strip' removes both whitespace and commentary.
  
+ --create-reflog::
+       Create a reflog for the tag.
  <tagname>::
        The name of the tag to create, delete, or describe.
        The new tag name must pass all checks defined by
diff --combined builtin/checkout.c
index f71844a23a9d4bda0664bec709648911bc0f2609,3eaa73b983f8b209ccfa94f7d436fc7296856c87..9ff5ca4cbe97dd2dcd2cfa261d7f778809a88133
@@@ -19,6 -19,8 +19,6 @@@
  #include "ll-merge.h"
  #include "resolve-undo.h"
  #include "submodule.h"
 -#include "argv-array.h"
 -#include "sigchain.h"
  
  static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
@@@ -49,6 -51,8 +49,6 @@@ struct checkout_opts 
        struct pathspec pathspec;
        struct tree *source_tree;
  
 -      const char *new_worktree;
 -      const char **saved_argv;
        int new_worktree_mode;
  };
  
@@@ -269,6 -273,9 +269,6 @@@ static int checkout_paths(const struct 
                die(_("Cannot update paths and switch to branch '%s' at the same time."),
                    opts->new_branch);
  
 -      if (opts->new_worktree)
 -              die(_("'%s' cannot be used with updating paths"), "--to");
 -
        if (opts->patch_mode)
                return run_add_interactive(revision, "--patch=checkout",
                                           &opts->pathspec);
@@@ -612,22 -619,20 +612,20 @@@ static void update_refs_for_switch(cons
        if (opts->new_branch) {
                if (opts->new_orphan_branch) {
                        if (opts->new_branch_log && !log_all_ref_updates) {
-                               int temp;
-                               struct strbuf log_file = STRBUF_INIT;
                                int ret;
-                               const char *ref_name;
-                               ref_name = mkpath("refs/heads/%s", opts->new_orphan_branch);
-                               temp = log_all_ref_updates;
-                               log_all_ref_updates = 1;
-                               ret = log_ref_setup(ref_name, &log_file);
-                               log_all_ref_updates = temp;
-                               strbuf_release(&log_file);
+                               char *refname;
+                               struct strbuf err = STRBUF_INIT;
+                               refname = mkpathdup("refs/heads/%s", opts->new_orphan_branch);
+                               ret = safe_create_reflog(refname, 1, &err);
+                               free(refname);
                                if (ret) {
-                                       fprintf(stderr, _("Can not do reflog for '%s'\n"),
-                                           opts->new_orphan_branch);
+                                       fprintf(stderr, _("Can not do reflog for '%s': %s\n"),
+                                               opts->new_orphan_branch, err.buf);
+                                       strbuf_release(&err);
                                        return;
                                }
+                               strbuf_release(&err);
                        }
                }
                else
@@@ -843,6 -848,138 +841,6 @@@ static int switch_branches(const struc
        return ret || writeout_error;
  }
  
 -static char *junk_work_tree;
 -static char *junk_git_dir;
 -static int is_junk;
 -static pid_t junk_pid;
 -
 -static void remove_junk(void)
 -{
 -      struct strbuf sb = STRBUF_INIT;
 -      if (!is_junk || getpid() != junk_pid)
 -              return;
 -      if (junk_git_dir) {
 -              strbuf_addstr(&sb, junk_git_dir);
 -              remove_dir_recursively(&sb, 0);
 -              strbuf_reset(&sb);
 -      }
 -      if (junk_work_tree) {
 -              strbuf_addstr(&sb, junk_work_tree);
 -              remove_dir_recursively(&sb, 0);
 -      }
 -      strbuf_release(&sb);
 -}
 -
 -static void remove_junk_on_signal(int signo)
 -{
 -      remove_junk();
 -      sigchain_pop(signo);
 -      raise(signo);
 -}
 -
 -static int prepare_linked_checkout(const struct checkout_opts *opts,
 -                                 struct branch_info *new)
 -{
 -      struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
 -      struct strbuf sb = STRBUF_INIT;
 -      const char *path = opts->new_worktree, *name;
 -      struct stat st;
 -      struct child_process cp;
 -      int counter = 0, len, ret;
 -
 -      if (!new->commit)
 -              die(_("no branch specified"));
 -      if (file_exists(path) && !is_empty_dir(path))
 -              die(_("'%s' already exists"), path);
 -
 -      len = strlen(path);
 -      while (len && is_dir_sep(path[len - 1]))
 -              len--;
 -
 -      for (name = path + len - 1; name > path; name--)
 -              if (is_dir_sep(*name)) {
 -                      name++;
 -                      break;
 -              }
 -      strbuf_addstr(&sb_repo,
 -                    git_path("worktrees/%.*s", (int)(path + len - name), name));
 -      len = sb_repo.len;
 -      if (safe_create_leading_directories_const(sb_repo.buf))
 -              die_errno(_("could not create leading directories of '%s'"),
 -                        sb_repo.buf);
 -      while (!stat(sb_repo.buf, &st)) {
 -              counter++;
 -              strbuf_setlen(&sb_repo, len);
 -              strbuf_addf(&sb_repo, "%d", counter);
 -      }
 -      name = strrchr(sb_repo.buf, '/') + 1;
 -
 -      junk_pid = getpid();
 -      atexit(remove_junk);
 -      sigchain_push_common(remove_junk_on_signal);
 -
 -      if (mkdir(sb_repo.buf, 0777))
 -              die_errno(_("could not create directory of '%s'"), sb_repo.buf);
 -      junk_git_dir = xstrdup(sb_repo.buf);
 -      is_junk = 1;
 -
 -      /*
 -       * lock the incomplete repo so prune won't delete it, unlock
 -       * after the preparation is over.
 -       */
 -      strbuf_addf(&sb, "%s/locked", sb_repo.buf);
 -      write_file(sb.buf, 1, "initializing\n");
 -
 -      strbuf_addf(&sb_git, "%s/.git", path);
 -      if (safe_create_leading_directories_const(sb_git.buf))
 -              die_errno(_("could not create leading directories of '%s'"),
 -                        sb_git.buf);
 -      junk_work_tree = xstrdup(path);
 -
 -      strbuf_reset(&sb);
 -      strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
 -      write_file(sb.buf, 1, "%s\n", real_path(sb_git.buf));
 -      write_file(sb_git.buf, 1, "gitdir: %s/worktrees/%s\n",
 -                 real_path(get_git_common_dir()), name);
 -      /*
 -       * This is to keep resolve_ref() happy. We need a valid HEAD
 -       * or is_git_directory() will reject the directory. Any valid
 -       * value would do because this value will be ignored and
 -       * replaced at the next (real) checkout.
 -       */
 -      strbuf_reset(&sb);
 -      strbuf_addf(&sb, "%s/HEAD", sb_repo.buf);
 -      write_file(sb.buf, 1, "%s\n", sha1_to_hex(new->commit->object.sha1));
 -      strbuf_reset(&sb);
 -      strbuf_addf(&sb, "%s/commondir", sb_repo.buf);
 -      write_file(sb.buf, 1, "../..\n");
 -
 -      if (!opts->quiet)
 -              fprintf_ln(stderr, _("Enter %s (identifier %s)"), path, name);
 -
 -      setenv("GIT_CHECKOUT_NEW_WORKTREE", "1", 1);
 -      setenv(GIT_DIR_ENVIRONMENT, sb_git.buf, 1);
 -      setenv(GIT_WORK_TREE_ENVIRONMENT, path, 1);
 -      memset(&cp, 0, sizeof(cp));
 -      cp.git_cmd = 1;
 -      cp.argv = opts->saved_argv;
 -      ret = run_command(&cp);
 -      if (!ret) {
 -              is_junk = 0;
 -              free(junk_work_tree);
 -              free(junk_git_dir);
 -              junk_work_tree = NULL;
 -              junk_git_dir = NULL;
 -      }
 -      strbuf_reset(&sb);
 -      strbuf_addf(&sb, "%s/locked", sb_repo.buf);
 -      unlink_or_warn(sb.buf);
 -      strbuf_release(&sb);
 -      strbuf_release(&sb_repo);
 -      strbuf_release(&sb_git);
 -      return ret;
 -}
 -
  static int git_checkout_config(const char *var, const char *value, void *cb)
  {
        if (!strcmp(var, "diff.ignoresubmodules")) {
@@@ -971,6 -1108,7 +969,6 @@@ static int parse_branchname_arg(int arg
  {
        struct tree **source_tree = &opts->source_tree;
        const char **new_branch = &opts->new_branch;
 -      int force_detach = opts->force_detach;
        int argcount = 0;
        unsigned char branch_rev[20];
        const char *arg;
        else
                new->path = NULL; /* not an existing branch */
  
 -      if (new->path && !force_detach && !*new_branch) {
 -              unsigned char sha1[20];
 -              int flag;
 -              char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
 -              if (head_ref &&
 -                  (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
 -                  !opts->ignore_other_worktrees)
 -                      check_linked_checkouts(new);
 -              free(head_ref);
 -      }
 -
        new->commit = lookup_commit_reference_gently(rev, 1);
        if (!new->commit) {
                /* not a commit */
@@@ -1170,16 -1319,8 +1168,16 @@@ static int checkout_branch(struct check
                die(_("Cannot switch branch to a non-commit '%s'"),
                    new->name);
  
 -      if (opts->new_worktree)
 -              return prepare_linked_checkout(opts, new);
 +      if (new->path && !opts->force_detach && !opts->new_branch) {
 +              unsigned char sha1[20];
 +              int flag;
 +              char *head_ref = resolve_refdup("HEAD", 0, sha1, &flag);
 +              if (head_ref &&
 +                  (!(flag & REF_ISSYMREF) || strcmp(head_ref, new->path)) &&
 +                  !opts->ignore_other_worktrees)
 +                      check_linked_checkouts(new);
 +              free(head_ref);
 +      }
  
        if (!new->commit && opts->new_branch) {
                unsigned char rev[20];
@@@ -1223,6 -1364,8 +1221,6 @@@ int cmd_checkout(int argc, const char *
                         N_("do not limit pathspecs to sparse entries only")),
                OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
                                N_("second guess 'git checkout <no-such-branch>'")),
 -              OPT_FILENAME(0, "to", &opts.new_worktree,
 -                         N_("check a branch out in a separate working directory")),
                OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
                         N_("do not check if another worktree is holding the given ref")),
                OPT_END(),
        opts.overwrite_ignore = 1;
        opts.prefix = prefix;
  
 -      opts.saved_argv = xmalloc(sizeof(const char *) * (argc + 2));
 -      memcpy(opts.saved_argv, argv, sizeof(const char *) * (argc + 1));
 -
        gitmodules_config();
        git_config(git_checkout_config, &opts);
  
        argc = parse_options(argc, argv, prefix, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
  
 -      /* recursive execution from checkout_new_worktree() */
        opts.new_worktree_mode = getenv("GIT_CHECKOUT_NEW_WORKTREE") != NULL;
 -      if (opts.new_worktree_mode)
 -              opts.new_worktree = NULL;
 -
 -      if (!opts.new_worktree)
 -              setup_work_tree();
  
        if (conflict_style) {
                opts.merge = 1; /* implied */
diff --combined builtin/update-ref.c
index 6763cf1837db99442a7140fe5bb87a0b3a1248fd,9046443731a3a4b14b4ab55b71686a2495155f87..04dd00f734166acc9c0670de061c4612877a7187
@@@ -14,6 -14,7 +14,7 @@@ static const char * const git_update_re
  
  static char line_termination = '\n';
  static int update_flags;
+ static unsigned create_reflog_flag;
  static const char *msg;
  
  /*
@@@ -200,7 -201,8 +201,8 @@@ static const char *parse_cmd_update(str
  
        if (ref_transaction_update(transaction, refname,
                                   new_sha1, have_old ? old_sha1 : NULL,
-                                  update_flags, msg, &err))
+                                  update_flags | create_reflog_flag,
+                                  msg, &err))
                die("%s", err.buf);
  
        update_flags = 0;
@@@ -231,7 -233,8 +233,8 @@@ static const char *parse_cmd_create(str
                die("create %s: extra input: %s", refname, next);
  
        if (ref_transaction_create(transaction, refname, new_sha1,
-                                  update_flags, msg, &err))
+                                  update_flags | create_reflog_flag,
+                                  msg, &err))
                die("%s", err.buf);
  
        update_flags = 0;
@@@ -354,6 -357,7 +357,7 @@@ int cmd_update_ref(int argc, const cha
        unsigned char sha1[20], oldsha1[20];
        int delete = 0, no_deref = 0, read_stdin = 0, end_null = 0;
        unsigned int flags = 0;
+       int create_reflog = 0;
        struct option options[] = {
                OPT_STRING( 'm', NULL, &msg, N_("reason"), N_("reason of the update")),
                OPT_BOOL('d', NULL, &delete, N_("delete the reference")),
                                        N_("update <refname> not the one it points to")),
                OPT_BOOL('z', NULL, &end_null, N_("stdin has NUL-terminated arguments")),
                OPT_BOOL( 0 , "stdin", &read_stdin, N_("read updates from stdin")),
+               OPT_BOOL( 0 , "create-reflog", &create_reflog, N_("create_reflog")),
                OPT_END(),
        };
  
        if (msg && !*msg)
                die("Refusing to perform update with empty message.");
  
+       create_reflog_flag = create_reflog ? REF_FORCE_CREATE_REFLOG : 0;
        if (read_stdin) {
                struct strbuf err = STRBUF_INIT;
                struct ref_transaction *transaction;
                        die("%s: not a valid SHA1", value);
        }
  
 -      hashclr(oldsha1); /* all-zero hash in case oldval is the empty string */
 -      if (oldval && *oldval && get_sha1(oldval, oldsha1))
 -              die("%s: not a valid old SHA1", oldval);
 +      if (oldval) {
 +              if (!*oldval)
 +                      /*
 +                       * The empty string implies that the reference
 +                       * must not already exist:
 +                       */
 +                      hashclr(oldsha1);
 +              else if (get_sha1(oldval, oldsha1))
 +                      die("%s: not a valid old SHA1", oldval);
 +      }
  
        if (no_deref)
                flags = REF_NODEREF;
        if (delete)
 -              return delete_ref(refname, oldval ? oldsha1 : NULL, flags);
 +              /*
 +               * For purposes of backwards compatibility, we treat
 +               * NULL_SHA1 as "don't care" here:
 +               */
 +              return delete_ref(refname,
 +                                (oldval && !is_null_sha1(oldsha1)) ? oldsha1 : NULL,
 +                                flags);
        else
                return update_ref(msg, refname, sha1, oldval ? oldsha1 : NULL,
-                                 flags, UPDATE_REFS_DIE_ON_ERR);
+                                 flags | create_reflog_flag,
+                                 UPDATE_REFS_DIE_ON_ERR);
  }
diff --combined refs.c
index ce8cd8d45001d627b58dc2bbb2c6bfdc3bc18888,97a75f3c3125d6a73e020ee2da73fcb6cce3d13c..0b96ece4ec7e3caefd5776cac4e79c573d77b3bf
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -62,6 -62,11 +62,11 @@@ static unsigned char refname_dispositio
   */
  #define REF_NEEDS_COMMIT 0x20
  
+ /*
+  * 0x40 is REF_FORCE_CREATE_REFLOG, so skip it if you're adding a
+  * value to ref_update::flags
+  */
  /*
   * Try to read one refname component from the front of refname.
   * Return the length of the component found, or -1 if the component is
@@@ -1314,13 -1319,7 +1319,13 @@@ static struct ref_dir *get_packed_refs(
        return get_packed_ref_dir(get_packed_ref_cache(refs));
  }
  
 -void add_packed_ref(const char *refname, const unsigned char *sha1)
 +/*
 + * Add a reference to the in-memory packed reference cache.  This may
 + * only be called while the packed-refs file is locked (see
 + * lock_packed_refs()).  To actually write the packed-refs file, call
 + * commit_packed_refs().
 + */
 +static void add_packed_ref(const char *refname, const unsigned char *sha1)
  {
        struct packed_ref_cache *packed_ref_cache =
                get_packed_ref_cache(&ref_cache);
@@@ -1747,11 -1746,9 +1752,11 @@@ const char *resolve_ref_unsafe(const ch
        return ret;
  }
  
 -char *resolve_refdup(const char *ref, int resolve_flags, unsigned char *sha1, int *flags)
 +char *resolve_refdup(const char *refname, int resolve_flags,
 +                   unsigned char *sha1, int *flags)
  {
 -      return xstrdup_or_null(resolve_ref_unsafe(ref, resolve_flags, sha1, flags));
 +      return xstrdup_or_null(resolve_ref_unsafe(refname, resolve_flags,
 +                                                sha1, flags));
  }
  
  /* The argument to filter_refs */
@@@ -2130,8 -2127,7 +2135,8 @@@ int for_each_remote_ref_submodule(cons
  
  int for_each_replace_ref(each_ref_fn fn, void *cb_data)
  {
 -      return do_for_each_ref(&ref_cache, "refs/replace/", fn, 13, 0, cb_data);
 +      return do_for_each_ref(&ref_cache, git_replace_ref_base, fn,
 +                             strlen(git_replace_ref_base), 0, cb_data);
  }
  
  int head_ref_namespaced(each_ref_fn fn, void *cb_data)
@@@ -2539,12 -2535,8 +2544,12 @@@ static int write_packed_entry_fn(struc
        return 0;
  }
  
 -/* This should return a meaningful errno on failure */
 -int lock_packed_refs(int flags)
 +/*
 + * Lock the packed-refs file for writing. Flags is passed to
 + * hold_lock_file_for_update(). Return 0 on success. On errors, set
 + * errno appropriately and return a nonzero value.
 + */
 +static int lock_packed_refs(int flags)
  {
        static int timeout_configured = 0;
        static int timeout_value = 1000;
  }
  
  /*
 - * Commit the packed refs changes.
 - * On error we must make sure that errno contains a meaningful value.
 + * Write the current version of the packed refs cache from memory to
 + * disk. The packed-refs file must already be locked for writing (see
 + * lock_packed_refs()). Return zero on success. On errors, set errno
 + * and return a nonzero value
   */
 -int commit_packed_refs(void)
 +static int commit_packed_refs(void)
  {
        struct packed_ref_cache *packed_ref_cache =
                get_packed_ref_cache(&ref_cache);
        return error;
  }
  
 -void rollback_packed_refs(void)
 +/*
 + * Rollback the lockfile for the packed-refs file, and discard the
 + * in-memory packed reference cache.  (The packed-refs file will be
 + * read anew if it is needed again after this function is called.)
 + */
 +static void rollback_packed_refs(void)
  {
        struct packed_ref_cache *packed_ref_cache =
                get_packed_ref_cache(&ref_cache);
@@@ -2771,14 -2756,7 +2776,14 @@@ int pack_refs(unsigned int flags
        return 0;
  }
  
 -int repack_without_refs(struct string_list *refnames, struct strbuf *err)
 +/*
 + * Rewrite the packed-refs file, omitting any refs listed in
 + * 'refnames'. On error, leave packed-refs unchanged, write an error
 + * message to 'err', and return a nonzero value.
 + *
 + * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
 + */
 +static int repack_without_refs(struct string_list *refnames, struct strbuf *err)
  {
        struct ref_dir *packed;
        struct string_list_item *refname;
@@@ -2843,15 -2821,15 +2848,15 @@@ static int delete_ref_loose(struct ref_
        return 0;
  }
  
 -int delete_ref(const char *refname, const unsigned char *sha1, unsigned int flags)
 +int delete_ref(const char *refname, const unsigned char *old_sha1,
 +             unsigned int flags)
  {
        struct ref_transaction *transaction;
        struct strbuf err = STRBUF_INIT;
  
        transaction = ref_transaction_begin(&err);
        if (!transaction ||
 -          ref_transaction_delete(transaction, refname,
 -                                 (sha1 && !is_null_sha1(sha1)) ? sha1 : NULL,
 +          ref_transaction_delete(transaction, refname, old_sha1,
                                   flags, NULL, &err) ||
            ref_transaction_commit(transaction, &err)) {
                error("%s", err.buf);
        return 0;
  }
  
 +int delete_refs(struct string_list *refnames)
 +{
 +      struct strbuf err = STRBUF_INIT;
 +      int i, result = 0;
 +
 +      if (!refnames->nr)
 +              return 0;
 +
 +      result = repack_without_refs(refnames, &err);
 +      if (result) {
 +              /*
 +               * If we failed to rewrite the packed-refs file, then
 +               * it is unsafe to try to remove loose refs, because
 +               * doing so might expose an obsolete packed value for
 +               * a reference that might even point at an object that
 +               * has been garbage collected.
 +               */
 +              if (refnames->nr == 1)
 +                      error(_("could not delete reference %s: %s"),
 +                            refnames->items[0].string, err.buf);
 +              else
 +                      error(_("could not delete references: %s"), err.buf);
 +
 +              goto out;
 +      }
 +
 +      for (i = 0; i < refnames->nr; i++) {
 +              const char *refname = refnames->items[i].string;
 +
 +              if (delete_ref(refname, NULL, 0))
 +                      result |= error(_("could not remove reference %s"), refname);
 +      }
 +
 +out:
 +      strbuf_release(&err);
 +      return result;
 +}
 +
  /*
   * People using contrib's git-new-workdir have .git/logs/refs ->
   * /some/other/path/.git/logs/refs, and that may live on another device.
@@@ -2975,9 -2915,11 +2980,11 @@@ static int rename_ref_available(const c
        return ret;
  }
  
- static int write_ref_to_lockfile(struct ref_lock *lock, const unsigned char *sha1);
+ static int write_ref_to_lockfile(struct ref_lock *lock,
+                                const unsigned char *sha1, struct strbuf *err);
  static int commit_ref_update(struct ref_lock *lock,
-                            const unsigned char *sha1, const char *logmsg);
+                            const unsigned char *sha1, const char *logmsg,
+                            int flags, struct strbuf *err);
  
  int rename_ref(const char *oldrefname, const char *newrefname, const char *logmsg)
  {
        }
        hashcpy(lock->old_oid.hash, orig_sha1);
  
-       if (write_ref_to_lockfile(lock, orig_sha1) ||
-           commit_ref_update(lock, orig_sha1, logmsg)) {
-               error("unable to write current sha1 into %s", newrefname);
+       if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
+           commit_ref_update(lock, orig_sha1, logmsg, 0, &err)) {
+               error("unable to write current sha1 into %s: %s", newrefname, err.buf);
+               strbuf_release(&err);
                goto rollback;
        }
  
  
        flag = log_all_ref_updates;
        log_all_ref_updates = 0;
-       if (write_ref_to_lockfile(lock, orig_sha1) ||
-           commit_ref_update(lock, orig_sha1, NULL))
-               error("unable to write current sha1 into %s", oldrefname);
+       if (write_ref_to_lockfile(lock, orig_sha1, &err) ||
+           commit_ref_update(lock, orig_sha1, NULL, 0, &err)) {
+               error("unable to write current sha1 into %s: %s", oldrefname, err.buf);
+               strbuf_release(&err);
+       }
        log_all_ref_updates = flag;
  
   rollbacklog:
@@@ -3113,8 -3058,23 +3123,23 @@@ static int copy_msg(char *buf, const ch
        return cp - buf;
  }
  
- /* This function must set a meaningful errno on failure */
- int log_ref_setup(const char *refname, struct strbuf *sb_logfile)
+ static int should_autocreate_reflog(const char *refname)
+ {
+       if (!log_all_ref_updates)
+               return 0;
+       return starts_with(refname, "refs/heads/") ||
+               starts_with(refname, "refs/remotes/") ||
+               starts_with(refname, "refs/notes/") ||
+               !strcmp(refname, "HEAD");
+ }
+ /*
+  * Create a reflog for a ref.  If force_create = 0, the reflog will
+  * only be created for certain refs (those for which
+  * should_autocreate_reflog returns non-zero.  Otherwise, create it
+  * regardless of the ref name.  Fill in *err and return -1 on failure.
+  */
+ static int log_ref_setup(const char *refname, struct strbuf *sb_logfile, struct strbuf *err, int force_create)
  {
        int logfd, oflags = O_APPEND | O_WRONLY;
        char *logfile;
        logfile = sb_logfile->buf;
        /* make sure the rest of the function can't change "logfile" */
        sb_logfile = NULL;
-       if (log_all_ref_updates &&
-           (starts_with(refname, "refs/heads/") ||
-            starts_with(refname, "refs/remotes/") ||
-            starts_with(refname, "refs/notes/") ||
-            !strcmp(refname, "HEAD"))) {
+       if (force_create || should_autocreate_reflog(refname)) {
                if (safe_create_leading_directories(logfile) < 0) {
-                       int save_errno = errno;
-                       error("unable to create directory for %s", logfile);
-                       errno = save_errno;
+                       strbuf_addf(err, "unable to create directory for %s: "
+                                   "%s", logfile, strerror(errno));
                        return -1;
                }
                oflags |= O_CREAT;
  
                if (errno == EISDIR) {
                        if (remove_empty_directories(logfile)) {
-                               int save_errno = errno;
-                               error("There are still logs under '%s'",
-                                     logfile);
-                               errno = save_errno;
+                               strbuf_addf(err, "There are still logs under "
+                                           "'%s'", logfile);
                                return -1;
                        }
                        logfd = open(logfile, oflags, 0666);
                }
  
                if (logfd < 0) {
-                       int save_errno = errno;
-                       error("Unable to append to %s: %s", logfile,
-                             strerror(errno));
-                       errno = save_errno;
+                       strbuf_addf(err, "unable to append to %s: %s",
+                                   logfile, strerror(errno));
                        return -1;
                }
        }
        return 0;
  }
  
+ int safe_create_reflog(const char *refname, int force_create, struct strbuf *err)
+ {
+       int ret;
+       struct strbuf sb = STRBUF_INIT;
+       ret = log_ref_setup(refname, &sb, err, force_create);
+       strbuf_release(&sb);
+       return ret;
+ }
  static int log_ref_write_fd(int fd, const unsigned char *old_sha1,
                            const unsigned char *new_sha1,
                            const char *committer, const char *msg)
  
  static int log_ref_write_1(const char *refname, const unsigned char *old_sha1,
                           const unsigned char *new_sha1, const char *msg,
-                          struct strbuf *sb_log_file)
+                          struct strbuf *sb_log_file, int flags,
+                          struct strbuf *err)
  {
        int logfd, result, oflags = O_APPEND | O_WRONLY;
        char *log_file;
        if (log_all_ref_updates < 0)
                log_all_ref_updates = !is_bare_repository();
  
-       result = log_ref_setup(refname, sb_log_file);
+       result = log_ref_setup(refname, sb_log_file, err, flags & REF_FORCE_CREATE_REFLOG);
        if (result)
                return result;
        log_file = sb_log_file->buf;
        result = log_ref_write_fd(logfd, old_sha1, new_sha1,
                                  git_committer_info(0), msg);
        if (result) {
-               int save_errno = errno;
+               strbuf_addf(err, "unable to append to %s: %s", log_file,
+                           strerror(errno));
                close(logfd);
-               error("Unable to append to %s", log_file);
-               errno = save_errno;
                return -1;
        }
        if (close(logfd)) {
-               int save_errno = errno;
-               error("Unable to append to %s", log_file);
-               errno = save_errno;
+               strbuf_addf(err, "unable to append to %s: %s", log_file,
+                           strerror(errno));
                return -1;
        }
        return 0;
  }
  
  static int log_ref_write(const char *refname, const unsigned char *old_sha1,
-                        const unsigned char *new_sha1, const char *msg)
+                        const unsigned char *new_sha1, const char *msg,
+                        int flags, struct strbuf *err)
  {
        struct strbuf sb = STRBUF_INIT;
-       int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb);
+       int ret = log_ref_write_1(refname, old_sha1, new_sha1, msg, &sb, flags,
+                                 err);
        strbuf_release(&sb);
        return ret;
  }
@@@ -3247,36 -3211,36 +3276,36 @@@ int is_branch(const char *refname
  
  /*
   * Write sha1 into the open lockfile, then close the lockfile. On
-  * errors, rollback the lockfile and set errno to reflect the problem.
+  * errors, rollback the lockfile, fill in *err and
+  * return -1.
   */
  static int write_ref_to_lockfile(struct ref_lock *lock,
-                                const unsigned char *sha1)
+                                const unsigned char *sha1, struct strbuf *err)
  {
        static char term = '\n';
        struct object *o;
  
        o = parse_object(sha1);
        if (!o) {
-               error("Trying to write ref %s with nonexistent object %s",
-                       lock->ref_name, sha1_to_hex(sha1));
+               strbuf_addf(err,
+                           "Trying to write ref %s with nonexistent object %s",
+                           lock->ref_name, sha1_to_hex(sha1));
                unlock_ref(lock);
-               errno = EINVAL;
                return -1;
        }
        if (o->type != OBJ_COMMIT && is_branch(lock->ref_name)) {
-               error("Trying to write non-commit object %s to branch %s",
-                       sha1_to_hex(sha1), lock->ref_name);
+               strbuf_addf(err,
+                           "Trying to write non-commit object %s to branch %s",
+                           sha1_to_hex(sha1), lock->ref_name);
                unlock_ref(lock);
-               errno = EINVAL;
                return -1;
        }
        if (write_in_full(lock->lk->fd, sha1_to_hex(sha1), 40) != 40 ||
            write_in_full(lock->lk->fd, &term, 1) != 1 ||
            close_ref(lock) < 0) {
-               int save_errno = errno;
-               error("Couldn't write %s", lock->lk->filename.buf);
+               strbuf_addf(err,
+                           "Couldn't write %s", lock->lk->filename.buf);
                unlock_ref(lock);
-               errno = save_errno;
                return -1;
        }
        return 0;
   * necessary, using the specified lockmsg (which can be NULL).
   */
  static int commit_ref_update(struct ref_lock *lock,
-                            const unsigned char *sha1, const char *logmsg)
+                            const unsigned char *sha1, const char *logmsg,
+                            int flags, struct strbuf *err)
  {
        clear_loose_ref_cache(&ref_cache);
-       if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg) < 0 ||
+       if (log_ref_write(lock->ref_name, lock->old_oid.hash, sha1, logmsg, flags, err) < 0 ||
            (strcmp(lock->ref_name, lock->orig_ref_name) &&
-            log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg) < 0)) {
+            log_ref_write(lock->orig_ref_name, lock->old_oid.hash, sha1, logmsg, flags, err) < 0)) {
+               char *old_msg = strbuf_detach(err, NULL);
+               strbuf_addf(err, "Cannot update the ref '%s': %s",
+                           lock->ref_name, old_msg);
+               free(old_msg);
                unlock_ref(lock);
                return -1;
        }
                head_ref = resolve_ref_unsafe("HEAD", RESOLVE_REF_READING,
                                              head_sha1, &head_flag);
                if (head_ref && (head_flag & REF_ISSYMREF) &&
-                   !strcmp(head_ref, lock->ref_name))
-                       log_ref_write("HEAD", lock->old_oid.hash, sha1, logmsg);
+                   !strcmp(head_ref, lock->ref_name)) {
+                       struct strbuf log_err = STRBUF_INIT;
+                       if (log_ref_write("HEAD", lock->old_oid.hash, sha1,
+                                         logmsg, 0, &log_err)) {
+                               error("%s", log_err.buf);
+                               strbuf_release(&log_err);
+                       }
+               }
        }
        if (commit_ref(lock)) {
                error("Couldn't set %s", lock->ref_name);
                unlock_ref(lock);
                return -1;
        }
        unlock_ref(lock);
        return 0;
  }
@@@ -3336,6 -3312,7 +3377,7 @@@ int create_symref(const char *ref_targe
        int fd, len, written;
        char *git_HEAD = git_pathdup("%s", ref_target);
        unsigned char old_sha1[20], new_sha1[20];
+       struct strbuf err = STRBUF_INIT;
  
        if (logmsg && read_ref(ref_target, old_sha1))
                hashclr(old_sha1);
  #ifndef NO_SYMLINK_HEAD
        done:
  #endif
-       if (logmsg && !read_ref(refs_heads_master, new_sha1))
-               log_ref_write(ref_target, old_sha1, new_sha1, logmsg);
+       if (logmsg && !read_ref(refs_heads_master, new_sha1) &&
+               log_ref_write(ref_target, old_sha1, new_sha1, logmsg, 0, &err)) {
+               error("%s", err.buf);
+               strbuf_release(&err);
+       }
  
        free(git_HEAD);
        return 0;
@@@ -3436,14 -3416,14 +3481,14 @@@ static int read_ref_at_ent(unsigned cha
                        hashcpy(cb->sha1, nsha1);
                        if (hashcmp(cb->osha1, nsha1))
                                warning("Log for ref %s has gap after %s.",
 -                                      cb->refname, show_date(cb->date, cb->tz, DATE_RFC2822));
 +                                      cb->refname, show_date(cb->date, cb->tz, DATE_MODE(RFC2822)));
                }
                else if (cb->date == cb->at_time)
                        hashcpy(cb->sha1, nsha1);
                else if (hashcmp(nsha1, cb->sha1))
                        warning("Log for ref %s unexpectedly ended on %s.",
                                cb->refname, show_date(cb->date, cb->tz,
 -                                                 DATE_RFC2822));
 +                                                     DATE_MODE(RFC2822)));
                hashcpy(cb->osha1, osha1);
                hashcpy(cb->nsha1, nsha1);
                cb->found_it = 1;
@@@ -4021,14 -4001,19 +4066,19 @@@ int ref_transaction_commit(struct ref_t
                                 * value, so we don't need to write it.
                                 */
                        } else if (write_ref_to_lockfile(update->lock,
-                                                        update->new_sha1)) {
+                                                        update->new_sha1,
+                                                        err)) {
+                               char *write_err = strbuf_detach(err, NULL);
                                /*
                                 * The lock was freed upon failure of
                                 * write_ref_to_lockfile():
                                 */
                                update->lock = NULL;
-                               strbuf_addf(err, "cannot update the ref '%s'.",
-                                           update->refname);
+                               strbuf_addf(err,
+                                           "cannot update the ref '%s': %s",
+                                           update->refname, write_err);
+                               free(write_err);
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
                        } else {
  
                if (update->flags & REF_NEEDS_COMMIT) {
                        if (commit_ref_update(update->lock,
-                                             update->new_sha1, update->msg)) {
+                                             update->new_sha1, update->msg,
+                                             update->flags, err)) {
                                /* freed by commit_ref_update(): */
                                update->lock = NULL;
-                               strbuf_addf(err, "Cannot update the ref '%s'.",
-                                           update->refname);
                                ret = TRANSACTION_GENERIC_ERROR;
                                goto cleanup;
                        } else {
@@@ -4103,98 -4087,6 +4152,98 @@@ cleanup
        return ret;
  }
  
 +static int ref_present(const char *refname,
 +                     const struct object_id *oid, int flags, void *cb_data)
 +{
 +      struct string_list *affected_refnames = cb_data;
 +
 +      return string_list_has_string(affected_refnames, refname);
 +}
 +
 +int initial_ref_transaction_commit(struct ref_transaction *transaction,
 +                                 struct strbuf *err)
 +{
 +      struct ref_dir *loose_refs = get_loose_refs(&ref_cache);
 +      struct ref_dir *packed_refs = get_packed_refs(&ref_cache);
 +      int ret = 0, i;
 +      int n = transaction->nr;
 +      struct ref_update **updates = transaction->updates;
 +      struct string_list affected_refnames = STRING_LIST_INIT_NODUP;
 +
 +      assert(err);
 +
 +      if (transaction->state != REF_TRANSACTION_OPEN)
 +              die("BUG: commit called for transaction that is not open");
 +
 +      /* Fail if a refname appears more than once in the transaction: */
 +      for (i = 0; i < n; i++)
 +              string_list_append(&affected_refnames, updates[i]->refname);
 +      string_list_sort(&affected_refnames);
 +      if (ref_update_reject_duplicates(&affected_refnames, err)) {
 +              ret = TRANSACTION_GENERIC_ERROR;
 +              goto cleanup;
 +      }
 +
 +      /*
 +       * It's really undefined to call this function in an active
 +       * repository or when there are existing references: we are
 +       * only locking and changing packed-refs, so (1) any
 +       * simultaneous processes might try to change a reference at
 +       * the same time we do, and (2) any existing loose versions of
 +       * the references that we are setting would have precedence
 +       * over our values. But some remote helpers create the remote
 +       * "HEAD" and "master" branches before calling this function,
 +       * so here we really only check that none of the references
 +       * that we are creating already exists.
 +       */
 +      if (for_each_rawref(ref_present, &affected_refnames))
 +              die("BUG: initial ref transaction called with existing refs");
 +
 +      for (i = 0; i < n; i++) {
 +              struct ref_update *update = updates[i];
 +
 +              if ((update->flags & REF_HAVE_OLD) &&
 +                  !is_null_sha1(update->old_sha1))
 +                      die("BUG: initial ref transaction with old_sha1 set");
 +              if (verify_refname_available(update->refname,
 +                                           &affected_refnames, NULL,
 +                                           loose_refs, err) ||
 +                  verify_refname_available(update->refname,
 +                                           &affected_refnames, NULL,
 +                                           packed_refs, err)) {
 +                      ret = TRANSACTION_NAME_CONFLICT;
 +                      goto cleanup;
 +              }
 +      }
 +
 +      if (lock_packed_refs(0)) {
 +              strbuf_addf(err, "unable to lock packed-refs file: %s",
 +                          strerror(errno));
 +              ret = TRANSACTION_GENERIC_ERROR;
 +              goto cleanup;
 +      }
 +
 +      for (i = 0; i < n; i++) {
 +              struct ref_update *update = updates[i];
 +
 +              if ((update->flags & REF_HAVE_NEW) &&
 +                  !is_null_sha1(update->new_sha1))
 +                      add_packed_ref(update->refname, update->new_sha1);
 +      }
 +
 +      if (commit_packed_refs()) {
 +              strbuf_addf(err, "unable to commit packed-refs file: %s",
 +                          strerror(errno));
 +              ret = TRANSACTION_GENERIC_ERROR;
 +              goto cleanup;
 +      }
 +
 +cleanup:
 +      transaction->state = REF_TRANSACTION_CLOSED;
 +      string_list_clear(&affected_refnames, 0);
 +      return ret;
 +}
 +
  char *shorten_unambiguous_ref(const char *refname, int strict)
  {
        int i;
diff --combined refs.h
index e82fca51f501a8297977e1315146c14cafca725b,4f1b23656892ab0cdd3ea459138df0c6e843dc4c..e4e46c3dc450d53eb299824da630bdbc4c5805cc
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
@@@ -1,98 -1,6 +1,98 @@@
  #ifndef REFS_H
  #define REFS_H
  
 +/*
 + * Resolve a reference, recursively following symbolic refererences.
 + *
 + * Store the referred-to object's name in sha1 and return the name of
 + * the non-symbolic reference that ultimately pointed at it.  The
 + * return value, if not NULL, is a pointer into either a static buffer
 + * or the input ref.
 + *
 + * If the reference cannot be resolved to an object, the behavior
 + * depends on the RESOLVE_REF_READING flag:
 + *
 + * - If RESOLVE_REF_READING is set, return NULL.
 + *
 + * - If RESOLVE_REF_READING is not set, clear sha1 and return the name of
 + *   the last reference name in the chain, which will either be a non-symbolic
 + *   reference or an undefined reference.  If this is a prelude to
 + *   "writing" to the ref, the return value is the name of the ref
 + *   that will actually be created or changed.
 + *
 + * If the RESOLVE_REF_NO_RECURSE flag is passed, only resolves one
 + * level of symbolic reference.  The value stored in sha1 for a symbolic
 + * reference will always be null_sha1 in this case, and the return
 + * value is the reference that the symref refers to directly.
 + *
 + * If flags is non-NULL, set the value that it points to the
 + * combination of REF_ISPACKED (if the reference was found among the
 + * packed references), REF_ISSYMREF (if the initial reference was a
 + * symbolic reference), REF_BAD_NAME (if the reference name is ill
 + * formed --- see RESOLVE_REF_ALLOW_BAD_NAME below), and REF_ISBROKEN
 + * (if the ref is malformed or has a bad name). See refs.h for more detail
 + * on each flag.
 + *
 + * If ref is not a properly-formatted, normalized reference, return
 + * NULL.  If more than MAXDEPTH recursive symbolic lookups are needed,
 + * give up and return NULL.
 + *
 + * RESOLVE_REF_ALLOW_BAD_NAME allows resolving refs even when their
 + * name is invalid according to git-check-ref-format(1).  If the name
 + * is bad then the value stored in sha1 will be null_sha1 and the two
 + * flags REF_ISBROKEN and REF_BAD_NAME will be set.
 + *
 + * Even with RESOLVE_REF_ALLOW_BAD_NAME, names that escape the refs/
 + * directory and do not consist of all caps and underscores cannot be
 + * resolved. The function returns NULL for such ref names.
 + * Caps and underscores refers to the special refs, such as HEAD,
 + * FETCH_HEAD and friends, that all live outside of the refs/ directory.
 + */
 +#define RESOLVE_REF_READING 0x01
 +#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);
 +
 +extern 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);
 +
 +extern int ref_exists(const char *refname);
 +
 +extern int is_branch(const char *refname);
 +
 +/*
 + * If refname is a non-symbolic reference that refers to a tag object,
 + * and the tag can be (recursively) dereferenced to a non-tag object,
 + * store the SHA1 of the referred-to object to sha1 and return 0.  If
 + * any of these conditions are not met, return a non-zero value.
 + * Symbolic references are considered unpeelable, even if they
 + * ultimately resolve to a peelable tag.
 + */
 +extern 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);
 +
 +/*
 + * 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);
 +
 +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);
 +
  /*
   * A ref_transaction represents a collection of ref updates
   * that should succeed or fail together.
@@@ -170,15 -78,15 +170,15 @@@ 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, void *);
 -extern int for_each_ref(each_ref_fn, void *);
 -extern int for_each_ref_in(const char *, each_ref_fn, void *);
 -extern int for_each_tag_ref(each_ref_fn, void *);
 -extern int for_each_branch_ref(each_ref_fn, void *);
 -extern int for_each_remote_ref(each_ref_fn, void *);
 -extern int for_each_replace_ref(each_ref_fn, void *);
 -extern int for_each_glob_ref(each_ref_fn, const char *pattern, void *);
 -extern int for_each_glob_ref_in(each_ref_fn, const char *pattern, const char* prefix, void *);
 +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_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);
@@@ -191,17 -99,47 +191,17 @@@ extern int for_each_remote_ref_submodul
  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);
  
 +/* can be used to learn about broken ref and symref */
 +extern int for_each_rawref(each_ref_fn fn, void *cb_data);
 +
  static inline const char *has_glob_specials(const char *pattern)
  {
        return strpbrk(pattern, "?*[");
  }
  
 -/* can be used to learn about broken ref and symref */
 -extern int for_each_rawref(each_ref_fn, void *);
 -
  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);
  
 -/*
 - * Lock the packed-refs file for writing.  Flags is passed to
 - * hold_lock_file_for_update().  Return 0 on success.
 - * Errno is set to something meaningful on error.
 - */
 -extern int lock_packed_refs(int flags);
 -
 -/*
 - * Add a reference to the in-memory packed reference cache.  This may
 - * only be called while the packed-refs file is locked (see
 - * lock_packed_refs()).  To actually write the packed-refs file, call
 - * commit_packed_refs().
 - */
 -extern void add_packed_ref(const char *refname, const unsigned char *sha1);
 -
 -/*
 - * Write the current version of the packed refs cache from memory to
 - * disk.  The packed-refs file must already be locked for writing (see
 - * lock_packed_refs()).  Return zero on success.
 - * Sets errno to something meaningful on error.
 - */
 -extern int commit_packed_refs(void);
 -
 -/*
 - * Rollback the lockfile for the packed-refs file, and discard the
 - * in-memory packed reference cache.  (The packed-refs file will be
 - * read anew if it is needed again after this function is called.)
 - */
 -extern void rollback_packed_refs(void);
 -
  /*
   * Flags for controlling behaviour of pack_refs()
   * PACK_REFS_PRUNE: Prune loose refs after packing
   */
  int pack_refs(unsigned int flags);
  
 -/*
 - * Rewrite the packed-refs file, omitting any refs listed in
 - * 'refnames'. On error, packed-refs will be unchanged, the return
 - * value is nonzero, and a message about the error is written to the
 - * 'err' strbuf.
 - *
 - * The refs in 'refnames' needn't be sorted. `err` must not be NULL.
 - */
 -extern int repack_without_refs(struct string_list *refnames,
 -                             struct strbuf *err);
 -
 -extern int ref_exists(const char *);
 -
 -extern int is_branch(const char *refname);
 -
 -/*
 - * If refname is a non-symbolic reference that refers to a tag object,
 - * and the tag can be (recursively) dereferenced to a non-tag object,
 - * store the SHA1 of the referred-to object to sha1 and return 0.  If
 - * any of these conditions are not met, return a non-zero value.
 - * Symbolic references are considered unpeelable, even if they
 - * ultimately resolve to a peelable tag.
 - */
 -extern int peel_ref(const char *refname, unsigned char *sha1);
 -
  /*
   * Flags controlling ref_transaction_update(), ref_transaction_create(), etc.
   * REF_NODEREF: act on the ref directly, instead of dereferencing
   * Other flags are reserved for internal use.
   */
  #define REF_NODEREF   0x01
+ #define REF_FORCE_CREATE_REFLOG 0x40
  
  /*
-  * Setup reflog before using. Set errno to something meaningful on failure.
+  * Setup reflog before using. Fill in err and return -1 on failure.
   */
- int log_ref_setup(const char *refname, struct strbuf *logfile);
+ 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,
  /** Check if a particular reflog exists */
  extern int reflog_exists(const char *refname);
  
 +/*
 + * Delete the specified reference. If old_sha1 is non-NULL, then
 + * verify that the current value of the reference is old_sha1 before
 + * deleting it. If old_sha1 is NULL, delete the reference if it
 + * 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);
 +
 +/*
 + * 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).
 + */
 +extern int delete_refs(struct string_list *refnames);
 +
  /** Delete a reflog */
  extern int delete_reflog(const char *refname);
  
@@@ -284,13 -231,17 +285,13 @@@ extern int for_each_reflog(each_ref_fn
  extern int check_refname_format(const char *refname, int flags);
  
  extern const char *prettify_refname(const char *refname);
 +
  extern 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);
  
 -/**
 - * 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);
 +extern int create_symref(const char *ref, const char *refs_heads_master, const char *logmsg);
  
  enum action_on_err {
        UPDATE_REFS_MSG_ON_ERR,
@@@ -409,20 -360,6 +410,20 @@@ int ref_transaction_verify(struct ref_t
  int ref_transaction_commit(struct ref_transaction *transaction,
                           struct strbuf *err);
  
 +/*
 + * Like ref_transaction_commit(), but optimized for creating
 + * references when originally initializing a repository (e.g., by "git
 + * clone"). It writes the new references directly to packed-refs
 + * without locking the individual references.
 + *
 + * It is a bug to call this function when there might be other
 + * processes accessing the repository or if there are existing
 + * references that might conflict with the ones being created. All
 + * old_sha1 values must either be absent or NULL_SHA1.
 + */
 +int initial_ref_transaction_commit(struct ref_transaction *transaction,
 +                                 struct strbuf *err);
 +
  /*
   * Free an existing transaction and all associated data.
   */
@@@ -441,7 -378,6 +442,7 @@@ int update_ref(const char *msg, const c
               unsigned int flags, enum action_on_err onerr);
  
  extern int parse_hide_refs_config(const char *var, const char *value, const char *);
 +
  extern int ref_is_hidden(const char *);
  
  enum expire_reflog_flags {