Merge branch 'ma/lockfile-cleanup'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:05 +0000 (14:04 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:05 +0000 (14:04 +0900)
Code clean-up to adjust to a more recent lockfile API convention that
allows lockfile instances kept on the stack.

* ma/lockfile-cleanup:
lock_file: move static locks into functions
lock_file: make function-local locks non-static
refs.c: do not die if locking fails in `delete_pseudoref()`
refs.c: do not die if locking fails in `write_pseudoref()`
t/helper/test-write-cache: clean up lock-handling

16 files changed:
1  2 
apply.c
builtin/add.c
builtin/describe.c
builtin/difftool.c
builtin/gc.c
builtin/merge.c
builtin/mv.c
builtin/receive-pack.c
builtin/rm.c
bundle.c
fast-import.c
refs.c
refs/files-backend.c
rerere.c
t/helper/test-scrap-cache-tree.c
t/helper/test-write-cache.c
diff --combined apply.c
index d80b26bc336a51f3cd356c029ef6dd51bee11af5,3d43212ab9a44067632e1176bd810b685881af90..40b3fae4f648e988b044f6d5c736b87932cad804
+++ b/apply.c
@@@ -3180,7 -3180,7 +3180,7 @@@ static int apply_binary(struct apply_st
                unsigned long size;
                char *result;
  
 -              result = read_sha1_file(oid.hash, &type, &size);
 +              result = read_object_file(&oid, &type, &size);
                if (!result)
                        return error(_("the necessary postimage %s for "
                                       "'%s' cannot be read"),
@@@ -3242,7 -3242,7 +3242,7 @@@ static int read_blob_object(struct strb
                unsigned long sz;
                char *result;
  
 -              result = read_sha1_file(oid->hash, &type, &sz);
 +              result = read_object_file(oid, &type, &sz);
                if (!result)
                        return -1;
                /* XXX read_sha1_file NUL-terminates */
@@@ -3860,9 -3860,9 +3860,9 @@@ static int check_unsafe_path(struct pat
        if (!patch->is_delete)
                new_name = patch->new_name;
  
 -      if (old_name && !verify_path(old_name))
 +      if (old_name && !verify_path(old_name, patch->old_mode))
                return error(_("invalid path '%s'"), old_name);
 -      if (new_name && !verify_path(new_name))
 +      if (new_name && !verify_path(new_name, patch->new_mode))
                return error(_("invalid path '%s'"), new_name);
        return 0;
  }
@@@ -4058,7 -4058,7 +4058,7 @@@ static int build_fake_ancestor(struct a
  {
        struct patch *patch;
        struct index_state result = { NULL };
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        int res;
  
        /* Once we start supporting the reverse patch, it may be
diff --combined builtin/add.c
index c9e2619a9ad8febc10e4132c88e7a74c6c9bbeaf,80152bcaed66890eef97bea7e79a9e9b11b22fff..8a155dd41eccd8004a55b1302111293ae59ea542
@@@ -9,7 -9,7 +9,7 @@@
  #include "lockfile.h"
  #include "dir.h"
  #include "pathspec.h"
 -#include "exec_cmd.h"
 +#include "exec-cmd.h"
  #include "cache-tree.h"
  #include "run-command.h"
  #include "parse-options.h"
@@@ -265,8 -265,6 +265,6 @@@ static int edit_patch(int argc, const c
        return 0;
  }
  
- static struct lock_file lock_file;
  static const char ignore_error[] =
  N_("The following paths are ignored by one of your .gitignore files:\n");
  
@@@ -393,6 -391,7 +391,7 @@@ int cmd_add(int argc, const char **argv
        int add_new_files;
        int require_pathspec;
        char *seen = NULL;
+       struct lock_file lock_file = LOCK_INIT;
  
        git_config(add_config, NULL);
  
diff --combined builtin/describe.c
index a4160e7f5d1321e08be78f86d63b780a1711616f,8933aa969c67cd6407bb0fcc6755f19f546ca792..cf1ae77d7c705cdfb34bdb5403bad8db4148eccf
@@@ -6,7 -6,7 +6,7 @@@
  #include "blob.h"
  #include "refs.h"
  #include "builtin.h"
 -#include "exec_cmd.h"
 +#include "exec-cmd.h"
  #include "parse-options.h"
  #include "revision.h"
  #include "diff.h"
@@@ -285,7 -285,7 +285,7 @@@ static void append_name(struct commit_n
  
  static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst)
  {
 -      strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev));
 +      strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid, abbrev));
  }
  
  static void describe_commit(struct object_id *oid, struct strbuf *dst)
        if (!match_cnt) {
                struct object_id *cmit_oid = &cmit->object.oid;
                if (always) {
 -                      strbuf_add_unique_abbrev(dst, cmit_oid->hash, abbrev);
 +                      strbuf_add_unique_abbrev(dst, cmit_oid, abbrev);
                        if (suffix)
                                strbuf_addstr(dst, suffix);
                        return;
@@@ -502,7 -502,7 +502,7 @@@ static void describe(const char *arg, i
  
        if (cmit)
                describe_commit(&oid, &sb);
 -      else if (sha1_object_info(oid.hash, NULL) == OBJ_BLOB)
 +      else if (oid_object_info(the_repository, &oid, NULL) == OBJ_BLOB)
                describe_blob(oid, &sb);
        else
                die(_("%s is neither a commit nor blob"), arg);
@@@ -612,7 -612,7 +612,7 @@@ int cmd_describe(int argc, const char *
                                suffix = broken;
                        }
                } else if (dirty) {
-                       static struct lock_file index_lock;
+                       struct lock_file index_lock = LOCK_INIT;
                        struct rev_info revs;
                        struct argv_array args = ARGV_ARRAY_INIT;
                        int fd, result;
diff --combined builtin/difftool.c
index aad0e073ee61648a73843ceddffbab6047c9721b,d9a0fecffcfb9f1169c94c321191e9319e943013..162806f2385c944a3708dd31f38a5d1e2010aa5a
@@@ -15,7 -15,7 +15,7 @@@
  #include "config.h"
  #include "builtin.h"
  #include "run-command.h"
 -#include "exec_cmd.h"
 +#include "exec-cmd.h"
  #include "parse-options.h"
  #include "argv-array.h"
  #include "strbuf.h"
@@@ -306,7 -306,7 +306,7 @@@ static char *get_symlink(const struct o
        } else {
                enum object_type type;
                unsigned long size;
 -              data = read_sha1_file(oid->hash, &type, &size);
 +              data = read_object_file(oid, &type, &size);
                if (!data)
                        die(_("could not read object %s for symlink %s"),
                                oid_to_hex(oid), path);
@@@ -610,7 -610,7 +610,7 @@@ static int run_dir_diff(const char *ext
                        continue;
  
                if (!indices_loaded) {
-                       static struct lock_file lock;
+                       struct lock_file lock = LOCK_INIT;
                        strbuf_reset(&buf);
                        strbuf_addf(&buf, "%s/wtindex", tmpdir);
                        if (hold_lock_file_for_update(&lock, buf.buf, 0) < 0 ||
diff --combined builtin/gc.c
index c4777b2449e331336bac0baea317adb7c387eefb,9b6463d4f3418b9b4e955d6e7847a6ba28584914..ccfb1ceaeb3eb9c6a8cbe9297bceac94fa54bcac
@@@ -11,7 -11,6 +11,7 @@@
   */
  
  #include "builtin.h"
 +#include "repository.h"
  #include "config.h"
  #include "tempfile.h"
  #include "lockfile.h"
  #include "argv-array.h"
  #include "commit.h"
  #include "packfile.h"
 +#include "object-store.h"
 +#include "pack.h"
 +#include "pack-objects.h"
 +#include "blob.h"
 +#include "tree.h"
  
  #define FAILED_RUN "failed to run %s"
  
@@@ -45,8 -39,6 +45,8 @@@ static timestamp_t gc_log_expire_time
  static const char *gc_log_expire = "1.day.ago";
  static const char *prune_expire = "2.weeks.ago";
  static const char *prune_worktrees_expire = "3.months.ago";
 +static unsigned long big_pack_threshold;
 +static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
  
  static struct argv_array pack_refs_cmd = ARGV_ARRAY_INIT;
  static struct argv_array reflog = ARGV_ARRAY_INIT;
@@@ -134,9 -126,6 +134,9 @@@ static void gc_config(void
        git_config_get_expiry("gc.worktreepruneexpire", &prune_worktrees_expire);
        git_config_get_expiry("gc.logexpiry", &gc_log_expire);
  
 +      git_config_get_ulong("gc.bigpackthreshold", &big_pack_threshold);
 +      git_config_get_ulong("pack.deltacachesize", &max_delta_cache_size);
 +
        git_config(git_default_config, NULL);
  }
  
@@@ -175,28 -164,6 +175,28 @@@ static int too_many_loose_objects(void
        return needed;
  }
  
 +static struct packed_git *find_base_packs(struct string_list *packs,
 +                                        unsigned long limit)
 +{
 +      struct packed_git *p, *base = NULL;
 +
 +      for (p = get_packed_git(the_repository); p; p = p->next) {
 +              if (!p->pack_local)
 +                      continue;
 +              if (limit) {
 +                      if (p->pack_size >= limit)
 +                              string_list_append(packs, p->pack_name);
 +              } else if (!base || base->pack_size < p->pack_size) {
 +                      base = p;
 +              }
 +      }
 +
 +      if (base)
 +              string_list_append(packs, base->pack_name);
 +
 +      return base;
 +}
 +
  static int too_many_packs(void)
  {
        struct packed_git *p;
        if (gc_auto_pack_limit <= 0)
                return 0;
  
 -      prepare_packed_git();
 -      for (cnt = 0, p = packed_git; p; p = p->next) {
 +      for (cnt = 0, p = get_packed_git(the_repository); p; p = p->next) {
                if (!p->pack_local)
                        continue;
                if (p->pack_keep)
        return gc_auto_pack_limit < cnt;
  }
  
 -static void add_repack_all_option(void)
 +static uint64_t total_ram(void)
 +{
 +#if defined(HAVE_SYSINFO)
 +      struct sysinfo si;
 +
 +      if (!sysinfo(&si))
 +              return si.totalram;
 +#elif defined(HAVE_BSD_SYSCTL) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM))
 +      int64_t physical_memory;
 +      int mib[2];
 +      size_t length;
 +
 +      mib[0] = CTL_HW;
 +# if defined(HW_MEMSIZE)
 +      mib[1] = HW_MEMSIZE;
 +# else
 +      mib[1] = HW_PHYSMEM;
 +# endif
 +      length = sizeof(int64_t);
 +      if (!sysctl(mib, 2, &physical_memory, &length, NULL, 0))
 +              return physical_memory;
 +#elif defined(GIT_WINDOWS_NATIVE)
 +      MEMORYSTATUSEX memInfo;
 +
 +      memInfo.dwLength = sizeof(MEMORYSTATUSEX);
 +      if (GlobalMemoryStatusEx(&memInfo))
 +              return memInfo.ullTotalPhys;
 +#endif
 +      return 0;
 +}
 +
 +static uint64_t estimate_repack_memory(struct packed_git *pack)
 +{
 +      unsigned long nr_objects = approximate_object_count();
 +      size_t os_cache, heap;
 +
 +      if (!pack || !nr_objects)
 +              return 0;
 +
 +      /*
 +       * First we have to scan through at least one pack.
 +       * Assume enough room in OS file cache to keep the entire pack
 +       * or we may accidentally evict data of other processes from
 +       * the cache.
 +       */
 +      os_cache = pack->pack_size + pack->index_size;
 +      /* then pack-objects needs lots more for book keeping */
 +      heap = sizeof(struct object_entry) * nr_objects;
 +      /*
 +       * internal rev-list --all --objects takes up some memory too,
 +       * let's say half of it is for blobs
 +       */
 +      heap += sizeof(struct blob) * nr_objects / 2;
 +      /*
 +       * and the other half is for trees (commits and tags are
 +       * usually insignificant)
 +       */
 +      heap += sizeof(struct tree) * nr_objects / 2;
 +      /* and then obj_hash[], underestimated in fact */
 +      heap += sizeof(struct object *) * nr_objects;
 +      /* revindex is used also */
 +      heap += sizeof(struct revindex_entry) * nr_objects;
 +      /*
 +       * read_sha1_file() (either at delta calculation phase, or
 +       * writing phase) also fills up the delta base cache
 +       */
 +      heap += delta_base_cache_limit;
 +      /* and of course pack-objects has its own delta cache */
 +      heap += max_delta_cache_size;
 +
 +      return os_cache + heap;
 +}
 +
 +static int keep_one_pack(struct string_list_item *item, void *data)
 +{
 +      argv_array_pushf(&repack, "--keep-pack=%s", basename(item->string));
 +      return 0;
 +}
 +
 +static void add_repack_all_option(struct string_list *keep_pack)
  {
        if (prune_expire && !strcmp(prune_expire, "now"))
                argv_array_push(&repack, "-a");
                if (prune_expire)
                        argv_array_pushf(&repack, "--unpack-unreachable=%s", prune_expire);
        }
 +
 +      if (keep_pack)
 +              for_each_string_list(keep_pack, keep_one_pack, NULL);
  }
  
  static void add_repack_incremental_option(void)
@@@ -332,35 -218,9 +332,35 @@@ static int need_to_gc(void
         * we run "repack -A -d -l".  Otherwise we tell the caller
         * there is no need.
         */
 -      if (too_many_packs())
 -              add_repack_all_option();
 -      else if (too_many_loose_objects())
 +      if (too_many_packs()) {
 +              struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 +
 +              if (big_pack_threshold) {
 +                      find_base_packs(&keep_pack, big_pack_threshold);
 +                      if (keep_pack.nr >= gc_auto_pack_limit) {
 +                              big_pack_threshold = 0;
 +                              string_list_clear(&keep_pack, 0);
 +                              find_base_packs(&keep_pack, 0);
 +                      }
 +              } else {
 +                      struct packed_git *p = find_base_packs(&keep_pack, 0);
 +                      uint64_t mem_have, mem_want;
 +
 +                      mem_have = total_ram();
 +                      mem_want = estimate_repack_memory(p);
 +
 +                      /*
 +                       * Only allow 1/2 of memory for pack-objects, leave
 +                       * the rest for the OS and other processes in the
 +                       * system.
 +                       */
 +                      if (!mem_have || mem_want < mem_have / 2)
 +                              string_list_clear(&keep_pack, 0);
 +              }
 +
 +              add_repack_all_option(&keep_pack);
 +              string_list_clear(&keep_pack, 0);
 +      } else if (too_many_loose_objects())
                add_repack_incremental_option();
        else
                return 0;
  /* return NULL on success, else hostname running the gc */
  static const char *lock_repo_for_gc(int force, pid_t* ret_pid)
  {
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        char my_host[HOST_NAME_MAX + 1];
        struct strbuf sb = STRBUF_INIT;
        struct stat st;
@@@ -493,8 -353,6 +493,8 @@@ int cmd_gc(int argc, const char **argv
        const char *name;
        pid_t pid;
        int daemonized = 0;
 +      int keep_base_pack = -1;
 +      timestamp_t dummy;
  
        struct option builtin_gc_options[] = {
                OPT__QUIET(&quiet, N_("suppress progress reporting")),
                OPT_BOOL_F(0, "force", &force,
                           N_("force running gc even if there may be another gc running"),
                           PARSE_OPT_NOCOMPLETE),
 +              OPT_BOOL(0, "keep-largest-pack", &keep_base_pack,
 +                       N_("repack all other packs except the largest pack")),
                OPT_END()
        };
  
        /* default expiry time, overwritten in gc_config */
        gc_config();
        if (parse_expiry_date(gc_log_expire, &gc_log_expire_time))
 -              die(_("Failed to parse gc.logexpiry value %s"), gc_log_expire);
 +              die(_("failed to parse gc.logexpiry value %s"), gc_log_expire);
  
        if (pack_refs < 0)
                pack_refs = !is_bare_repository();
        if (argc > 0)
                usage_with_options(builtin_gc_usage, builtin_gc_options);
  
 +      if (prune_expire && parse_expiry_date(prune_expire, &dummy))
 +              die(_("failed to parse prune expiry value %s"), prune_expire);
 +
        if (aggressive) {
                argv_array_push(&repack, "-f");
                if (aggressive_depth > 0)
                         */
                        daemonized = !daemonize();
                }
 -      } else
 -              add_repack_all_option();
 +      } else {
 +              struct string_list keep_pack = STRING_LIST_INIT_NODUP;
 +
 +              if (keep_base_pack != -1) {
 +                      if (keep_base_pack)
 +                              find_base_packs(&keep_pack, 0);
 +              } else if (big_pack_threshold) {
 +                      find_base_packs(&keep_pack, big_pack_threshold);
 +              }
 +
 +              add_repack_all_option(&keep_pack);
 +              string_list_clear(&keep_pack, 0);
 +      }
  
        name = lock_repo_for_gc(force, &pid);
        if (name) {
                return error(FAILED_RUN, rerere.argv[0]);
  
        report_garbage = report_pack_garbage;
 -      reprepare_packed_git();
 +      reprepare_packed_git(the_repository);
        if (pack_garbage.nr > 0)
                clean_pack_garbage();
  
diff --combined builtin/merge.c
index 9db5a2cf16e189bb3bd0ceec7d34c6651d630225,5be978fe727a801339c44f8e0994511a5cffd4f7..de62b2c5c6e61f55eedb9f1dc1b80898bec5e46a
@@@ -412,7 -412,7 +412,7 @@@ static void finish(struct commit *head_
                         * We ignore errors in 'gc --auto', since the
                         * user should see them.
                         */
 -                      close_all_packs();
 +                      close_all_packs(the_repository->objects);
                        run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
                }
        }
@@@ -639,7 -639,7 +639,7 @@@ static int read_tree_trivial(struct obj
  
  static void write_tree_trivial(struct object_id *oid)
  {
 -      if (write_cache_as_tree(oid->hash, 0, NULL))
 +      if (write_cache_as_tree(oid, 0, NULL))
                die(_("git write-tree failed to write a tree"));
  }
  
@@@ -647,7 -647,7 +647,7 @@@ static int try_merge_strategy(const cha
                              struct commit_list *remoteheads,
                              struct commit *head)
  {
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        const char *head_arg = "HEAD";
  
        hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
@@@ -805,7 -805,7 +805,7 @@@ static int merge_trivial(struct commit 
  {
        struct object_id result_tree, result_commit;
        struct commit_list *parents, **pptr = &parents;
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
  
        hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
        refresh_cache(REFRESH_QUIET);
@@@ -1324,7 -1324,7 +1324,7 @@@ int cmd_merge(int argc, const char **ar
  
                        check_commit_signature(commit, &signature_check);
  
 -                      find_unique_abbrev_r(hex, commit->object.oid.hash, DEFAULT_ABBREV);
 +                      find_unique_abbrev_r(hex, &commit->object.oid, DEFAULT_ABBREV);
                        switch (signature_check.result) {
                        case 'G':
                                break;
  
                if (verbosity >= 0) {
                        printf(_("Updating %s..%s\n"),
 -                             find_unique_abbrev(head_commit->object.oid.hash,
 +                             find_unique_abbrev(&head_commit->object.oid,
                                                  DEFAULT_ABBREV),
 -                             find_unique_abbrev(remoteheads->item->object.oid.hash,
 +                             find_unique_abbrev(&remoteheads->item->object.oid,
                                                  DEFAULT_ABBREV));
                }
                strbuf_addstr(&msg, "Fast-forward");
diff --combined builtin/mv.c
index 7a63667d64810c1164cf3acad3cfcc6cedf4010d,b4692409e392aa22c7176651351f04afd96ece0d..80bb967a63f154eb44ebc1a6dd7f833d01dce83e
@@@ -72,7 -72,6 +72,6 @@@ static const char *add_slash(const cha
        return path;
  }
  
- static struct lock_file lock_file;
  #define SUBMODULE_WITH_GITDIR ((const char *)1)
  
  static void prepare_move_submodule(const char *src, int first,
@@@ -131,6 -130,7 +130,7 @@@ int cmd_mv(int argc, const char **argv
        enum update_mode { BOTH = 0, WORKING_DIRECTORY, INDEX } *modes;
        struct stat st;
        struct string_list src_for_dst = STRING_LIST_INIT_NODUP;
+       struct lock_file lock_file = LOCK_INIT;
  
        git_config(git_default_config, NULL);
  
                        die_errno(_("renaming '%s' failed"), src);
                }
                if (submodule_gitfile[i]) {
 -                      if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
 -                              connect_work_tree_and_git_dir(dst, submodule_gitfile[i]);
                        if (!update_path_in_gitmodules(src, dst))
                                gitmodules_modified = 1;
 +                      if (submodule_gitfile[i] != SUBMODULE_WITH_GITDIR)
 +                              connect_work_tree_and_git_dir(dst,
 +                                                            submodule_gitfile[i],
 +                                                            1);
                }
  
                if (mode == WORKING_DIRECTORY)
diff --combined builtin/receive-pack.c
index 0dd163280d43c9d23e87fecc049ed03332aada0b,0c074b006b009dd2e2d1297f590fb653469a8eeb..132a5339a3eb9d36c0b78cd69d6e492c5b78d545
@@@ -1,5 -1,4 +1,5 @@@
  #include "builtin.h"
 +#include "repository.h"
  #include "config.h"
  #include "lockfile.h"
  #include "pack.h"
@@@ -7,7 -6,7 +7,7 @@@
  #include "pkt-line.h"
  #include "sideband.h"
  #include "run-command.h"
 -#include "exec_cmd.h"
 +#include "exec-cmd.h"
  #include "commit.h"
  #include "object.h"
  #include "remote.h"
@@@ -876,7 -875,7 +876,7 @@@ static void refuse_unconfigured_deny_de
  static int command_singleton_iterator(void *cb_data, struct object_id *oid);
  static int update_shallow_ref(struct command *cmd, struct shallow_info *si)
  {
-       static struct lock_file shallow_lock;
+       struct lock_file shallow_lock = LOCK_INIT;
        struct oid_array extra = OID_ARRAY_INIT;
        struct check_connected_options opt = CHECK_CONNECTED_INIT;
        uint32_t mask = 1 << (cmd->index % 32);
@@@ -1243,11 -1242,11 +1243,11 @@@ static void check_aliased_update(struc
        rp_error("refusing inconsistent update between symref '%s' (%s..%s) and"
                 " its target '%s' (%s..%s)",
                 cmd->ref_name,
 -               find_unique_abbrev(cmd->old_oid.hash, DEFAULT_ABBREV),
 -               find_unique_abbrev(cmd->new_oid.hash, DEFAULT_ABBREV),
 +               find_unique_abbrev(&cmd->old_oid, DEFAULT_ABBREV),
 +               find_unique_abbrev(&cmd->new_oid, DEFAULT_ABBREV),
                 dst_cmd->ref_name,
 -               find_unique_abbrev(dst_cmd->old_oid.hash, DEFAULT_ABBREV),
 -               find_unique_abbrev(dst_cmd->new_oid.hash, DEFAULT_ABBREV));
 +               find_unique_abbrev(&dst_cmd->old_oid, DEFAULT_ABBREV),
 +               find_unique_abbrev(&dst_cmd->new_oid, DEFAULT_ABBREV));
  
        cmd->error_string = dst_cmd->error_string =
                "inconsistent aliased update";
@@@ -1779,7 -1778,7 +1779,7 @@@ static const char *unpack(int err_fd, s
                status = finish_command(&child);
                if (status)
                        return "index-pack abnormal exit";
 -              reprepare_packed_git();
 +              reprepare_packed_git(the_repository);
        }
        return NULL;
  }
@@@ -1965,12 -1964,6 +1965,12 @@@ int cmd_receive_pack(int argc, const ch
                unpack_limit = receive_unpack_limit;
  
        switch (determine_protocol_version_server()) {
 +      case protocol_v2:
 +              /*
 +               * push support for protocol v2 has not been implemented yet,
 +               * so ignore the request to use v2 and fallback to using v0.
 +               */
 +              break;
        case protocol_v1:
                /*
                 * v1 is just the original protocol with a version string,
                        proc.git_cmd = 1;
                        proc.argv = argv_gc_auto;
  
 -                      close_all_packs();
 +                      close_all_packs(the_repository->objects);
                        if (!start_command(&proc)) {
                                if (use_sideband)
                                        copy_to_sideband(proc.err, -1, NULL);
diff --combined builtin/rm.c
index 5b6fc7ee818be4a4f060dc06f12fb45a25a2ea9b,0fcb952e9b1dd8a40c62c4bd2f8538a03e00b0f7..65b448ef8ee91079194841762d4b7a2193eec9a9
@@@ -178,7 -178,7 +178,7 @@@ static int check_local_mod(struct objec
                 * way as changed from the HEAD.
                 */
                if (no_head
 -                   || get_tree_entry(head->hash, name, oid.hash, &mode)
 +                   || get_tree_entry(head, name, &oid, &mode)
                     || ce->ce_mode != create_ce_mode(mode)
                     || oidcmp(&ce->oid, &oid))
                        staged_changes = 1;
        return errs;
  }
  
- static struct lock_file lock_file;
  static int show_only = 0, force = 0, index_only = 0, recursive = 0, quiet = 0;
  static int ignore_unmatch = 0;
  
@@@ -251,6 -249,7 +249,7 @@@ static struct option builtin_rm_options
  
  int cmd_rm(int argc, const char **argv, const char *prefix)
  {
+       struct lock_file lock_file = LOCK_INIT;
        int i;
        struct pathspec pathspec;
        char *seen;
diff --combined bundle.c
index 902c9b54485be2000696a697472fa10d97b36153,4fde31d210df29a590bf9773b119367f84964ccc..160bbfdc64ec2876bdc685d253bf537d1c739c1f
+++ b/bundle.c
@@@ -222,7 -222,7 +222,7 @@@ static int is_tag_in_date_range(struct 
        if (revs->max_age == -1 && revs->min_age == -1)
                goto out;
  
 -      buf = read_sha1_file(tag->oid.hash, &type, &size);
 +      buf = read_object_file(&tag->oid, &type, &size);
        if (!buf)
                goto out;
        line = memmem(buf, size, "\ntagger ", 8);
@@@ -409,7 -409,7 +409,7 @@@ static int write_bundle_refs(int bundle
  int create_bundle(struct bundle_header *header, const char *path,
                  int argc, const char **argv)
  {
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        int bundle_fd = -1;
        int bundle_to_stdout;
        int ref_count = 0;
diff --combined fast-import.c
index b2338fa8eb20d5c52d2bf03d73dca050721c292c,2bce22ae0c90c22783a135cd62aa7940c4860b96..4d55910ab9a0634a553c01643035ef9afe6034c7
@@@ -154,7 -154,6 +154,7 @@@ Format of STDIN stream
  
  #include "builtin.h"
  #include "cache.h"
 +#include "repository.h"
  #include "config.h"
  #include "lockfile.h"
  #include "object.h"
  #include "dir.h"
  #include "run-command.h"
  #include "packfile.h"
 +#include "object-store.h"
 +#include "mem-pool.h"
  
  #define PACK_ID_BITS 16
  #define MAX_PACK_ID ((1<<PACK_ID_BITS)-1)
@@@ -212,6 -209,13 +212,6 @@@ struct last_object 
        unsigned no_swap : 1;
  };
  
 -struct mem_pool {
 -      struct mem_pool *next_pool;
 -      char *next_free;
 -      char *end;
 -      uintmax_t space[FLEX_ARRAY]; /* more */
 -};
 -
  struct atom_str {
        struct atom_str *next_atom;
        unsigned short str_len;
@@@ -300,8 -304,9 +300,8 @@@ static int global_argc
  static const char **global_argv;
  
  /* Memory pools */
 -static size_t mem_pool_alloc = 2*1024*1024 - sizeof(struct mem_pool);
 -static size_t total_allocd;
 -static struct mem_pool *mem_pool;
 +static struct mem_pool fi_mem_pool =  {NULL, 2*1024*1024 -
 +                                     sizeof(struct mp_block), 0 };
  
  /* Atom management */
  static unsigned int atom_table_sz = 4451;
@@@ -336,7 -341,6 +336,7 @@@ static unsigned int tree_entry_alloc = 
  static void *avail_tree_entry;
  static unsigned int avail_tree_table_sz = 100;
  static struct avail_tree_content **avail_tree_table;
 +static size_t tree_entry_allocd;
  static struct strbuf old_tree = STRBUF_INIT;
  static struct strbuf new_tree = STRBUF_INIT;
  
@@@ -630,10 -634,49 +630,10 @@@ static unsigned int hc_str(const char *
        return r;
  }
  
 -static void *pool_alloc(size_t len)
 -{
 -      struct mem_pool *p;
 -      void *r;
 -
 -      /* round up to a 'uintmax_t' alignment */
 -      if (len & (sizeof(uintmax_t) - 1))
 -              len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
 -
 -      for (p = mem_pool; p; p = p->next_pool)
 -              if ((p->end - p->next_free >= len))
 -                      break;
 -
 -      if (!p) {
 -              if (len >= (mem_pool_alloc/2)) {
 -                      total_allocd += len;
 -                      return xmalloc(len);
 -              }
 -              total_allocd += sizeof(struct mem_pool) + mem_pool_alloc;
 -              p = xmalloc(st_add(sizeof(struct mem_pool), mem_pool_alloc));
 -              p->next_pool = mem_pool;
 -              p->next_free = (char *) p->space;
 -              p->end = p->next_free + mem_pool_alloc;
 -              mem_pool = p;
 -      }
 -
 -      r = p->next_free;
 -      p->next_free += len;
 -      return r;
 -}
 -
 -static void *pool_calloc(size_t count, size_t size)
 -{
 -      size_t len = count * size;
 -      void *r = pool_alloc(len);
 -      memset(r, 0, len);
 -      return r;
 -}
 -
  static char *pool_strdup(const char *s)
  {
        size_t len = strlen(s) + 1;
 -      char *r = pool_alloc(len);
 +      char *r = mem_pool_alloc(&fi_mem_pool, len);
        memcpy(r, s, len);
        return r;
  }
@@@ -642,7 -685,7 +642,7 @@@ static void insert_mark(uintmax_t idnum
  {
        struct mark_set *s = marks;
        while ((idnum >> s->shift) >= 1024) {
 -              s = pool_calloc(1, sizeof(struct mark_set));
 +              s = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
                s->shift = marks->shift + 10;
                s->data.sets[0] = marks;
                marks = s;
                uintmax_t i = idnum >> s->shift;
                idnum -= i << s->shift;
                if (!s->data.sets[i]) {
 -                      s->data.sets[i] = pool_calloc(1, sizeof(struct mark_set));
 +                      s->data.sets[i] = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
                        s->data.sets[i]->shift = s->shift - 10;
                }
                s = s->data.sets[i];
@@@ -689,7 -732,7 +689,7 @@@ static struct atom_str *to_atom(const c
                if (c->str_len == len && !strncmp(s, c->str_dat, len))
                        return c;
  
 -      c = pool_alloc(sizeof(struct atom_str) + len + 1);
 +      c = mem_pool_alloc(&fi_mem_pool, sizeof(struct atom_str) + len + 1);
        c->str_len = len;
        memcpy(c->str_dat, s, len);
        c->str_dat[len] = 0;
@@@ -720,7 -763,7 +720,7 @@@ static struct branch *new_branch(const 
        if (check_refname_format(name, REFNAME_ALLOW_ONELEVEL))
                die("Branch name doesn't conform to GIT standards: %s", name);
  
 -      b = pool_calloc(1, sizeof(struct branch));
 +      b = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct branch));
        b->name = pool_strdup(name);
        b->table_next_branch = branch_table[hc];
        b->branch_tree.versions[0].mode = S_IFDIR;
@@@ -756,7 -799,7 +756,7 @@@ static struct tree_content *new_tree_co
                        avail_tree_table[hc] = f->next_avail;
        } else {
                cnt = cnt & 7 ? ((cnt / 8) + 1) * 8 : cnt;
 -              f = pool_alloc(sizeof(*t) + sizeof(t->entries[0]) * cnt);
 +              f = mem_pool_alloc(&fi_mem_pool, sizeof(*t) + sizeof(t->entries[0]) * cnt);
                f->entry_capacity = cnt;
        }
  
@@@ -801,7 -844,7 +801,7 @@@ static struct tree_entry *new_tree_entr
  
        if (!avail_tree_entry) {
                unsigned int n = tree_entry_alloc;
 -              total_allocd += n * sizeof(struct tree_entry);
 +              tree_entry_allocd += n * sizeof(struct tree_entry);
                ALLOC_ARRAY(e, n);
                avail_tree_entry = e;
                while (n-- > 1) {
@@@ -973,7 -1016,7 +973,7 @@@ static void end_packfile(void
                struct tag *t;
  
                close_pack_windows(pack_data);
 -              hashclose(pack_file, cur_pack_oid.hash, 0);
 +              finalize_hashfile(pack_file, cur_pack_oid.hash, 0);
                fixup_pack_header_footer(pack_data->pack_fd, pack_data->sha1,
                                    pack_data->pack_name, object_count,
                                    cur_pack_oid.hash, pack_size);
                if (!new_p)
                        die("core git rejected index %s", idx_name);
                all_packs[pack_id] = new_p;
 -              install_packed_git(new_p);
 +              install_packed_git(the_repository, new_p);
                free(idx_name);
  
                /* Print the boundary */
@@@ -1067,8 -1110,7 +1067,8 @@@ static int store_object
        if (e->idx.offset) {
                duplicate_count_by_type[type]++;
                return 1;
 -      } else if (find_sha1_pack(oid.hash, packed_git)) {
 +      } else if (find_sha1_pack(oid.hash,
 +                                get_packed_git(the_repository))) {
                e->type = type;
                e->pack_id = MAX_PACK_ID;
                e->idx.offset = 1; /* just not zero! */
@@@ -1265,8 -1307,7 +1265,8 @@@ static void stream_blob(uintmax_t len, 
                duplicate_count_by_type[OBJ_BLOB]++;
                truncate_pack(&checkpoint);
  
 -      } else if (find_sha1_pack(oid.hash, packed_git)) {
 +      } else if (find_sha1_pack(oid.hash,
 +                                get_packed_git(the_repository))) {
                e->type = OBJ_BLOB;
                e->pack_id = MAX_PACK_ID;
                e->idx.offset = 1; /* just not zero! */
@@@ -1331,7 -1372,7 +1331,7 @@@ static void *gfi_unpack_entry
                 */
                p->pack_size = pack_size + the_hash_algo->rawsz;
        }
 -      return unpack_entry(p, oe->idx.offset, &type, sizep);
 +      return unpack_entry(the_repository, p, oe->idx.offset, &type, sizep);
  }
  
  static const char *get_mode(const char *str, uint16_t *modep)
@@@ -1371,7 -1412,7 +1371,7 @@@ static void load_tree(struct tree_entr
                        die("Can't load tree %s", oid_to_hex(oid));
        } else {
                enum object_type type;
 -              buf = read_sha1_file(oid->hash, &type, &size);
 +              buf = read_object_file(oid, &type, &size);
                if (!buf || type != OBJ_TREE)
                        die("Can't load tree %s", oid_to_hex(oid));
        }
@@@ -1817,7 -1858,7 +1817,7 @@@ static void dump_marks_helper(FILE *f
  
  static void dump_marks(void)
  {
-       static struct lock_file mark_lock;
+       struct lock_file mark_lock = LOCK_INIT;
        FILE *f;
  
        if (!export_marks_file || (import_marks_file && !import_marks_file_done))
@@@ -1872,8 -1913,7 +1872,8 @@@ static void read_marks(void
                        die("corrupt mark line: %s", line);
                e = find_object(&oid);
                if (!e) {
 -                      enum object_type type = sha1_object_info(oid.hash, NULL);
 +                      enum object_type type = oid_object_info(the_repository,
 +                                                              &oid, NULL);
                        if (type < 0)
                                die("object not found: %s", oid_to_hex(&oid));
                        e = insert_object(&oid);
@@@ -2403,8 -2443,7 +2403,8 @@@ static void file_change_m(const char *p
                enum object_type expected = S_ISDIR(mode) ?
                                                OBJ_TREE: OBJ_BLOB;
                enum object_type type = oe ? oe->type :
 -                                      sha1_object_info(oid.hash, NULL);
 +                                      oid_object_info(the_repository, &oid,
 +                                                      NULL);
                if (type < 0)
                        die("%s not found: %s",
                                        S_ISDIR(mode) ?  "Tree" : "Blob",
@@@ -2544,9 -2583,8 +2544,9 @@@ static void note_change_n(const char *p
                oidcpy(&commit_oid, &commit_oe->idx.oid);
        } else if (!get_oid(p, &commit_oid)) {
                unsigned long size;
 -              char *buf = read_object_with_reference(commit_oid.hash,
 -                      commit_type, &size, commit_oid.hash);
 +              char *buf = read_object_with_reference(&commit_oid,
 +                                                     commit_type, &size,
 +                                                     &commit_oid);
                if (!buf || size < 46)
                        die("Not a valid commit: %s", p);
                free(buf);
                        die("Not a blob (actually a %s): %s",
                                type_name(oe->type), command_buf.buf);
        } else if (!is_null_oid(&oid)) {
 -              enum object_type type = sha1_object_info(oid.hash, NULL);
 +              enum object_type type = oid_object_info(the_repository, &oid,
 +                                                      NULL);
                if (type < 0)
                        die("Blob not found: %s", command_buf.buf);
                if (type != OBJ_BLOB)
@@@ -2616,8 -2653,9 +2616,8 @@@ static void parse_from_existing(struct 
                unsigned long size;
                char *buf;
  
 -              buf = read_object_with_reference(b->oid.hash,
 -                                               commit_type, &size,
 -                                               b->oid.hash);
 +              buf = read_object_with_reference(&b->oid, commit_type, &size,
 +                                               &b->oid);
                parse_from_commit(b, buf, size);
                free(buf);
        }
@@@ -2694,9 -2732,8 +2694,9 @@@ static struct hash_list *parse_merge(un
                        oidcpy(&n->oid, &oe->idx.oid);
                } else if (!get_oid(from, &n->oid)) {
                        unsigned long size;
 -                      char *buf = read_object_with_reference(n->oid.hash,
 -                              commit_type, &size, n->oid.hash);
 +                      char *buf = read_object_with_reference(&n->oid,
 +                                                             commit_type,
 +                                                             &size, &n->oid);
                        if (!buf || size < 46)
                                die("Not a valid commit: %s", from);
                        free(buf);
@@@ -2825,7 -2862,7 +2825,7 @@@ static void parse_new_tag(const char *a
        enum object_type type;
        const char *v;
  
 -      t = pool_alloc(sizeof(struct tag));
 +      t = mem_pool_alloc(&fi_mem_pool, sizeof(struct tag));
        memset(t, 0, sizeof(struct tag));
        t->name = pool_strdup(arg);
        if (last_tag)
        } else if (!get_oid(from, &oid)) {
                struct object_entry *oe = find_object(&oid);
                if (!oe) {
 -                      type = sha1_object_info(oid.hash, NULL);
 +                      type = oid_object_info(the_repository, &oid, NULL);
                        if (type < 0)
                                die("Not a valid object: %s", from);
                } else
@@@ -2929,7 -2966,7 +2929,7 @@@ static void cat_blob(struct object_entr
        char *buf;
  
        if (!oe || oe->pack_id == MAX_PACK_ID) {
 -              buf = read_sha1_file(oid->hash, &type, &size);
 +              buf = read_object_file(oid, &type, &size);
        } else {
                type = oe->type;
                buf = gfi_unpack_entry(oe, &size);
@@@ -3011,8 -3048,7 +3011,8 @@@ static struct object_entry *dereference
        unsigned long size;
        char *buf = NULL;
        if (!oe) {
 -              enum object_type type = sha1_object_info(oid->hash, NULL);
 +              enum object_type type = oid_object_info(the_repository, oid,
 +                                                      NULL);
                if (type < 0)
                        die("object not found: %s", oid_to_hex(oid));
                /* cache it! */
                buf = gfi_unpack_entry(oe, &size);
        } else {
                enum object_type unused;
 -              buf = read_sha1_file(oid->hash, &unused, &size);
 +              buf = read_object_file(oid, &unused, &size);
        }
        if (!buf)
                die("Can't load object %s", oid_to_hex(oid));
@@@ -3425,16 -3461,17 +3425,16 @@@ int cmd_main(int argc, const char **arg
        atom_table = xcalloc(atom_table_sz, sizeof(struct atom_str*));
        branch_table = xcalloc(branch_table_sz, sizeof(struct branch*));
        avail_tree_table = xcalloc(avail_tree_table_sz, sizeof(struct avail_tree_content*));
 -      marks = pool_calloc(1, sizeof(struct mark_set));
 +      marks = mem_pool_calloc(&fi_mem_pool, 1, sizeof(struct mark_set));
  
        global_argc = argc;
        global_argv = argv;
  
 -      rc_free = pool_alloc(cmd_save * sizeof(*rc_free));
 +      rc_free = mem_pool_alloc(&fi_mem_pool, cmd_save * sizeof(*rc_free));
        for (i = 0; i < (cmd_save - 1); i++)
                rc_free[i].next = &rc_free[i + 1];
        rc_free[cmd_save - 1].next = NULL;
  
 -      prepare_packed_git();
        start_packfile();
        set_die_routine(die_nicely);
        set_checkpoint_signal();
                fprintf(stderr, "Total branches:  %10lu (%10lu loads     )\n", branch_count, branch_load_count);
                fprintf(stderr, "      marks:     %10" PRIuMAX " (%10" PRIuMAX " unique    )\n", (((uintmax_t)1) << marks->shift) * 1024, marks_set_count);
                fprintf(stderr, "      atoms:     %10u\n", atom_cnt);
 -              fprintf(stderr, "Memory total:    %10" PRIuMAX " KiB\n", (total_allocd + alloc_count*sizeof(struct object_entry))/1024);
 -              fprintf(stderr, "       pools:    %10lu KiB\n", (unsigned long)(total_allocd/1024));
 +              fprintf(stderr, "Memory total:    %10" PRIuMAX " KiB\n", (tree_entry_allocd + fi_mem_pool.pool_alloc + alloc_count*sizeof(struct object_entry))/1024);
 +              fprintf(stderr, "       pools:    %10lu KiB\n", (unsigned long)((tree_entry_allocd + fi_mem_pool.pool_alloc) /1024));
                fprintf(stderr, "     objects:    %10" PRIuMAX " KiB\n", (alloc_count*sizeof(struct object_entry))/1024);
                fprintf(stderr, "---------------------------------------------------------------------\n");
                pack_report();
diff --combined refs.c
index 1f31e6cf00dcb17c1fdf24a98e9575dbd1ba62fc,f657f4de84d850feb8d6c51e583f5dd0949209e1..7013363a902a4e4aebf6a4cbb2cd4e565230eb93
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -13,8 -13,6 +13,8 @@@
  #include "tag.h"
  #include "submodule.h"
  #include "worktree.h"
 +#include "argv-array.h"
 +#include "repository.h"
  
  /*
   * List of all available backends
@@@ -208,7 -206,7 +208,7 @@@ char *refs_resolve_refdup(struct ref_st
  char *resolve_refdup(const char *refname, int resolve_flags,
                     struct object_id *oid, int *flags)
  {
 -      return refs_resolve_refdup(get_main_ref_store(),
 +      return refs_resolve_refdup(get_main_ref_store(the_repository),
                                   refname, resolve_flags,
                                   oid, flags);
  }
@@@ -230,7 -228,7 +230,7 @@@ int refs_read_ref_full(struct ref_stor
  
  int read_ref_full(const char *refname, int resolve_flags, struct object_id *oid, int *flags)
  {
 -      return refs_read_ref_full(get_main_ref_store(), refname,
 +      return refs_read_ref_full(get_main_ref_store(the_repository), refname,
                                  resolve_flags, oid, flags);
  }
  
@@@ -303,7 -301,7 +303,7 @@@ enum peel_status peel_object(const stru
        struct object *o = lookup_unknown_object(name->hash);
  
        if (o->type == OBJ_NONE) {
 -              int type = sha1_object_info(name->hash, NULL);
 +              int type = oid_object_info(the_repository, name, NULL);
                if (type < 0 || !object_as_type(o, type, 0))
                        return PEEL_INVALID;
        }
@@@ -377,7 -375,7 +377,7 @@@ int refs_for_each_tag_ref(struct ref_st
  
  int for_each_tag_ref(each_ref_fn fn, void *cb_data)
  {
 -      return refs_for_each_tag_ref(get_main_ref_store(), fn, cb_data);
 +      return refs_for_each_tag_ref(get_main_ref_store(the_repository), fn, cb_data);
  }
  
  int refs_for_each_branch_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
  
  int for_each_branch_ref(each_ref_fn fn, void *cb_data)
  {
 -      return refs_for_each_branch_ref(get_main_ref_store(), fn, cb_data);
 +      return refs_for_each_branch_ref(get_main_ref_store(the_repository), fn, cb_data);
  }
  
  int refs_for_each_remote_ref(struct ref_store *refs, each_ref_fn fn, void *cb_data)
  
  int for_each_remote_ref(each_ref_fn fn, void *cb_data)
  {
 -      return refs_for_each_remote_ref(get_main_ref_store(), fn, cb_data);
 +      return refs_for_each_remote_ref(get_main_ref_store(the_repository), fn, cb_data);
  }
  
  int head_ref_namespaced(each_ref_fn fn, void *cb_data)
@@@ -503,19 -501,6 +503,19 @@@ int refname_match(const char *abbrev_na
        return 0;
  }
  
 +/*
 + * Given a 'prefix' expand it by the rules in 'ref_rev_parse_rules' and add
 + * the results to 'prefixes'
 + */
 +void expand_ref_prefix(struct argv_array *prefixes, const char *prefix)
 +{
 +      const char **p;
 +      int len = strlen(prefix);
 +
 +      for (p = ref_rev_parse_rules; *p; p++)
 +              argv_array_pushf(prefixes, *p, len, prefix);
 +}
 +
  /*
   * *string and *len will only be substituted, and *string returned (for
   * later free()ing) if the string passed in is a magic short-hand form
@@@ -615,8 -600,7 +615,8 @@@ int dwim_log(const char *str, int len, 
  static int is_per_worktree_ref(const char *refname)
  {
        return !strcmp(refname, "HEAD") ||
 -              starts_with(refname, "refs/bisect/");
 +              starts_with(refname, "refs/bisect/") ||
 +              starts_with(refname, "refs/rewritten/");
  }
  
  static int is_pseudoref_syntax(const char *refname)
@@@ -660,7 -644,7 +660,7 @@@ static int write_pseudoref(const char *
  {
        const char *filename;
        int fd;
-       static struct lock_file lock;
+       struct lock_file lock = LOCK_INIT;
        struct strbuf buf = STRBUF_INIT;
        int ret = -1;
  
        strbuf_addf(&buf, "%s\n", oid_to_hex(oid));
  
        filename = git_path("%s", pseudoref);
-       fd = hold_lock_file_for_update_timeout(&lock, filename,
-                                              LOCK_DIE_ON_ERROR,
+       fd = hold_lock_file_for_update_timeout(&lock, filename, 0,
                                               get_files_ref_lock_timeout_ms());
        if (fd < 0) {
                strbuf_addf(err, "could not open '%s' for writing: %s",
@@@ -706,20 -689,23 +705,23 @@@ done
  
  static int delete_pseudoref(const char *pseudoref, const struct object_id *old_oid)
  {
-       static struct lock_file lock;
        const char *filename;
  
        filename = git_path("%s", pseudoref);
  
        if (old_oid && !is_null_oid(old_oid)) {
+               struct lock_file lock = LOCK_INIT;
                int fd;
                struct object_id actual_old_oid;
  
                fd = hold_lock_file_for_update_timeout(
-                               &lock, filename, LOCK_DIE_ON_ERROR,
+                               &lock, filename, 0,
                                get_files_ref_lock_timeout_ms());
-               if (fd < 0)
-                       die_errno(_("Could not open '%s' for writing"), filename);
+               if (fd < 0) {
+                       error_errno(_("could not open '%s' for writing"),
+                                   filename);
+                       return -1;
+               }
                if (read_ref(pseudoref, &actual_old_oid))
                        die("could not read ref '%s'", pseudoref);
                if (oidcmp(&actual_old_oid, old_oid)) {
@@@ -746,7 -732,7 +748,7 @@@ int refs_delete_ref(struct ref_store *r
        struct strbuf err = STRBUF_INIT;
  
        if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
 -              assert(refs == get_main_ref_store());
 +              assert(refs == get_main_ref_store(the_repository));
                return delete_pseudoref(refname, old_oid);
        }
  
  int delete_ref(const char *msg, const char *refname,
               const struct object_id *old_oid, unsigned int flags)
  {
 -      return refs_delete_ref(get_main_ref_store(), msg, refname,
 +      return refs_delete_ref(get_main_ref_store(the_repository), msg, refname,
                               old_oid, flags);
  }
  
@@@ -944,7 -930,7 +946,7 @@@ struct ref_transaction *ref_store_trans
  
  struct ref_transaction *ref_transaction_begin(struct strbuf *err)
  {
 -      return ref_store_transaction_begin(get_main_ref_store(), err);
 +      return ref_store_transaction_begin(get_main_ref_store(the_repository), err);
  }
  
  void ref_transaction_free(struct ref_transaction *transaction)
@@@ -1076,7 -1062,7 +1078,7 @@@ int refs_update_ref(struct ref_store *r
        int ret = 0;
  
        if (ref_type(refname) == REF_TYPE_PSEUDOREF) {
 -              assert(refs == get_main_ref_store());
 +              assert(refs == get_main_ref_store(the_repository));
                ret = write_pseudoref(refname, new_oid, old_oid, &err);
        } else {
                t = ref_store_transaction_begin(refs, &err);
@@@ -1115,7 -1101,7 +1117,7 @@@ int update_ref(const char *msg, const c
               const struct object_id *old_oid,
               unsigned int flags, enum action_on_err onerr)
  {
 -      return refs_update_ref(get_main_ref_store(), msg, refname, new_oid,
 +      return refs_update_ref(get_main_ref_store(the_repository), msg, refname, new_oid,
                               old_oid, flags, onerr);
  }
  
@@@ -1336,7 -1322,7 +1338,7 @@@ int refs_head_ref(struct ref_store *ref
  
  int head_ref(each_ref_fn fn, void *cb_data)
  {
 -      return refs_head_ref(get_main_ref_store(), fn, cb_data);
 +      return refs_head_ref(get_main_ref_store(the_repository), fn, cb_data);
  }
  
  struct ref_iterator *refs_ref_iterator_begin(
@@@ -1395,7 -1381,7 +1397,7 @@@ int refs_for_each_ref(struct ref_store 
  
  int for_each_ref(each_ref_fn fn, void *cb_data)
  {
 -      return refs_for_each_ref(get_main_ref_store(), fn, cb_data);
 +      return refs_for_each_ref(get_main_ref_store(the_repository), fn, cb_data);
  }
  
  int refs_for_each_ref_in(struct ref_store *refs, const char *prefix,
  
  int for_each_ref_in(const char *prefix, each_ref_fn fn, void *cb_data)
  {
 -      return refs_for_each_ref_in(get_main_ref_store(), prefix, fn, cb_data);
 +      return refs_for_each_ref_in(get_main_ref_store(the_repository), prefix, fn, cb_data);
  }
  
  int for_each_fullref_in(const char *prefix, each_ref_fn fn, void *cb_data, unsigned int broken)
  
        if (broken)
                flag = DO_FOR_EACH_INCLUDE_BROKEN;
 -      return do_for_each_ref(get_main_ref_store(),
 +      return do_for_each_ref(get_main_ref_store(the_repository),
                               prefix, fn, 0, flag, cb_data);
  }
  
@@@ -1430,9 -1416,9 +1432,9 @@@ int refs_for_each_fullref_in(struct ref
        return do_for_each_ref(refs, prefix, fn, 0, flag, cb_data);
  }
  
 -int for_each_replace_ref(each_ref_fn fn, void *cb_data)
 +int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data)
  {
 -      return do_for_each_ref(get_main_ref_store(),
 +      return do_for_each_ref(get_main_ref_store(r),
                               git_replace_ref_base, fn,
                               strlen(git_replace_ref_base),
                               DO_FOR_EACH_INCLUDE_BROKEN, cb_data);
@@@ -1443,7 -1429,7 +1445,7 @@@ int for_each_namespaced_ref(each_ref_f
        struct strbuf buf = STRBUF_INIT;
        int ret;
        strbuf_addf(&buf, "%srefs/", get_git_namespace());
 -      ret = do_for_each_ref(get_main_ref_store(),
 +      ret = do_for_each_ref(get_main_ref_store(the_repository),
                              buf.buf, fn, 0, 0, cb_data);
        strbuf_release(&buf);
        return ret;
@@@ -1457,7 -1443,7 +1459,7 @@@ int refs_for_each_rawref(struct ref_sto
  
  int for_each_rawref(each_ref_fn fn, void *cb_data)
  {
 -      return refs_for_each_rawref(get_main_ref_store(), fn, cb_data);
 +      return refs_for_each_rawref(get_main_ref_store(the_repository), fn, cb_data);
  }
  
  int refs_read_raw_ref(struct ref_store *ref_store,
@@@ -1563,7 -1549,7 +1565,7 @@@ const char *refs_resolve_ref_unsafe(str
  /* backend functions */
  int refs_init_db(struct strbuf *err)
  {
 -      struct ref_store *refs = get_main_ref_store();
 +      struct ref_store *refs = get_main_ref_store(the_repository);
  
        return refs->be->init_db(refs, err);
  }
  const char *resolve_ref_unsafe(const char *refname, int resolve_flags,
                               struct object_id *oid, int *flags)
  {
 -      return refs_resolve_ref_unsafe(get_main_ref_store(), refname,
 +      return refs_resolve_ref_unsafe(get_main_ref_store(the_repository), refname,
                                       resolve_flags, oid, flags);
  }
  
@@@ -1623,6 -1609,9 +1625,6 @@@ static struct ref_store_hash_entry *all
        return entry;
  }
  
 -/* A pointer to the ref_store for the main repository: */
 -static struct ref_store *main_ref_store;
 -
  /* A hashmap of ref_stores, stored by submodule name: */
  static struct hashmap submodule_ref_stores;
  
@@@ -1664,16 -1653,13 +1666,16 @@@ static struct ref_store *ref_store_init
        return refs;
  }
  
 -struct ref_store *get_main_ref_store(void)
 +struct ref_store *get_main_ref_store(struct repository *r)
  {
 -      if (main_ref_store)
 -              return main_ref_store;
 +      if (r->refs)
 +              return r->refs;
 +
 +      if (!r->gitdir)
 +              BUG("attempting to get main_ref_store outside of repository");
  
 -      main_ref_store = ref_store_init(get_git_dir(), REF_STORE_ALL_CAPS);
 -      return main_ref_store;
 +      r->refs = ref_store_init(r->gitdir, REF_STORE_ALL_CAPS);
 +      return r->refs;
  }
  
  /*
@@@ -1742,7 -1728,7 +1744,7 @@@ struct ref_store *get_worktree_ref_stor
        const char *id;
  
        if (wt->is_current)
 -              return get_main_ref_store();
 +              return get_main_ref_store(the_repository);
  
        id = wt->id ? wt->id : "/";
        refs = lookup_ref_store_map(&worktree_ref_stores, id);
@@@ -1798,7 -1784,7 +1800,7 @@@ int refs_peel_ref(struct ref_store *ref
  
  int peel_ref(const char *refname, struct object_id *oid)
  {
 -      return refs_peel_ref(get_main_ref_store(), refname, oid);
 +      return refs_peel_ref(get_main_ref_store(the_repository), refname, oid);
  }
  
  int refs_create_symref(struct ref_store *refs,
  int create_symref(const char *ref_target, const char *refs_heads_master,
                  const char *logmsg)
  {
 -      return refs_create_symref(get_main_ref_store(), ref_target,
 +      return refs_create_symref(get_main_ref_store(the_repository), ref_target,
                                  refs_heads_master, logmsg);
  }
  
@@@ -2022,7 -2008,7 +2024,7 @@@ int refs_for_each_reflog(struct ref_sto
  
  int for_each_reflog(each_ref_fn fn, void *cb_data)
  {
 -      return refs_for_each_reflog(get_main_ref_store(), fn, cb_data);
 +      return refs_for_each_reflog(get_main_ref_store(the_repository), fn, cb_data);
  }
  
  int refs_for_each_reflog_ent_reverse(struct ref_store *refs,
  int for_each_reflog_ent_reverse(const char *refname, each_reflog_ent_fn fn,
                                void *cb_data)
  {
 -      return refs_for_each_reflog_ent_reverse(get_main_ref_store(),
 +      return refs_for_each_reflog_ent_reverse(get_main_ref_store(the_repository),
                                                refname, fn, cb_data);
  }
  
@@@ -2050,7 -2036,7 +2052,7 @@@ int refs_for_each_reflog_ent(struct ref
  int for_each_reflog_ent(const char *refname, each_reflog_ent_fn fn,
                        void *cb_data)
  {
 -      return refs_for_each_reflog_ent(get_main_ref_store(), refname,
 +      return refs_for_each_reflog_ent(get_main_ref_store(the_repository), refname,
                                        fn, cb_data);
  }
  
@@@ -2061,7 -2047,7 +2063,7 @@@ int refs_reflog_exists(struct ref_stor
  
  int reflog_exists(const char *refname)
  {
 -      return refs_reflog_exists(get_main_ref_store(), refname);
 +      return refs_reflog_exists(get_main_ref_store(the_repository), refname);
  }
  
  int refs_create_reflog(struct ref_store *refs, const char *refname,
  int safe_create_reflog(const char *refname, int force_create,
                       struct strbuf *err)
  {
 -      return refs_create_reflog(get_main_ref_store(), refname,
 +      return refs_create_reflog(get_main_ref_store(the_repository), refname,
                                  force_create, err);
  }
  
@@@ -2084,7 -2070,7 +2086,7 @@@ int refs_delete_reflog(struct ref_stor
  
  int delete_reflog(const char *refname)
  {
 -      return refs_delete_reflog(get_main_ref_store(), refname);
 +      return refs_delete_reflog(get_main_ref_store(the_repository), refname);
  }
  
  int refs_reflog_expire(struct ref_store *refs,
@@@ -2107,7 -2093,7 +2109,7 @@@ int reflog_expire(const char *refname, 
                  reflog_expiry_cleanup_fn cleanup_fn,
                  void *policy_cb_data)
  {
 -      return refs_reflog_expire(get_main_ref_store(),
 +      return refs_reflog_expire(get_main_ref_store(the_repository),
                                  refname, oid, flags,
                                  prepare_fn, should_prune_fn,
                                  cleanup_fn, policy_cb_data);
@@@ -2130,7 -2116,7 +2132,7 @@@ int refs_delete_refs(struct ref_store *
  int delete_refs(const char *msg, struct string_list *refnames,
                unsigned int flags)
  {
 -      return refs_delete_refs(get_main_ref_store(), msg, refnames, flags);
 +      return refs_delete_refs(get_main_ref_store(the_repository), msg, refnames, flags);
  }
  
  int refs_rename_ref(struct ref_store *refs, const char *oldref,
  
  int rename_ref(const char *oldref, const char *newref, const char *logmsg)
  {
 -      return refs_rename_ref(get_main_ref_store(), oldref, newref, logmsg);
 +      return refs_rename_ref(get_main_ref_store(the_repository), oldref, newref, logmsg);
  }
  
  int refs_copy_existing_ref(struct ref_store *refs, const char *oldref,
  
  int copy_existing_ref(const char *oldref, const char *newref, const char *logmsg)
  {
 -      return refs_copy_existing_ref(get_main_ref_store(), oldref, newref, logmsg);
 +      return refs_copy_existing_ref(get_main_ref_store(the_repository), oldref, newref, logmsg);
  }
diff --combined refs/files-backend.c
index 49d8f67bf132c2357fddcca4b449e28a54ce8f7c,197eea4084ff67cbdcb67adfa8141e982515e9b8..03fb8649c792b9eb1c1a03a405225feee29a9040
@@@ -9,7 -9,6 +9,7 @@@
  #include "../lockfile.h"
  #include "../object.h"
  #include "../dir.h"
 +#include "../chdir-notify.h"
  
  /*
   * This backend uses the following flags in `ref_update::flags` for
@@@ -62,6 -61,10 +62,6 @@@ struct ref_lock 
        struct object_id old_oid;
  };
  
 -/*
 - * Future: need to be in "struct repository"
 - * when doing a full libification.
 - */
  struct files_ref_store {
        struct ref_store base;
        unsigned int store_flags;
@@@ -103,11 -106,6 +103,11 @@@ static struct ref_store *files_ref_stor
        refs->packed_ref_store = packed_ref_store_create(sb.buf, flags);
        strbuf_release(&sb);
  
 +      chdir_notify_reparent("files-backend $GIT_DIR",
 +                            &refs->gitdir);
 +      chdir_notify_reparent("files-backend $GIT_COMMONDIR",
 +                            &refs->gitcommondir);
 +
        return ref_store;
  }
  
@@@ -2991,7 -2989,7 +2991,7 @@@ static int files_reflog_expire(struct r
  {
        struct files_ref_store *refs =
                files_downcast(ref_store, REF_STORE_WRITE, "reflog_expire");
-       static struct lock_file reflog_lock;
+       struct lock_file reflog_lock = LOCK_INIT;
        struct expire_reflog_cb cb;
        struct ref_lock *lock;
        struct strbuf log_file_sb = STRBUF_INIT;
diff --combined rerere.c
index 18cae2d11c9a86aae0ed352a8f7606b142c5c183,04d25691e4d6568d62e537f66d1651ba73a0a4fe..e0862e27786244b1a98723d09475223cc001dd62
+++ b/rerere.c
@@@ -703,10 -703,9 +703,9 @@@ out
        return ret;
  }
  
- static struct lock_file index_lock;
  static void update_paths(struct string_list *update)
  {
+       struct lock_file index_lock = LOCK_INIT;
        int i;
  
        hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
@@@ -979,8 -978,8 +978,8 @@@ static int handle_cache(const char *pat
                        break;
                i = ce_stage(ce) - 1;
                if (!mmfile[i].ptr) {
 -                      mmfile[i].ptr = read_sha1_file(ce->oid.hash, &type,
 -                                                     &size);
 +                      mmfile[i].ptr = read_object_file(&ce->oid, &type,
 +                                                       &size);
                        mmfile[i].size = size;
                }
        }
index d26d3e7c8b1a407e2cf40ce20750495f500d5170,34596201d4af7b956494bfe3fda2a95d67471fba..393f1604ff954703a2a5e075fbda1e14d0827dc0
@@@ -1,13 -1,12 +1,13 @@@
 +#include "test-tool.h"
  #include "cache.h"
  #include "lockfile.h"
  #include "tree.h"
  #include "cache-tree.h"
  
- static struct lock_file index_lock;
 -int cmd_main(int ac, const char **av)
 +int cmd__scrap_cache_tree(int ac, const char **av)
  {
+       struct lock_file index_lock = LOCK_INIT;
        setup_git_directory();
        hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
        if (read_cache() < 0)
index 017dc303800d9ba385a9836d85f81445c6b7e8b7,3d78c728a5dabe27931f6664f5b6675021f059b9..8837717d36a77c04346279b570e1a0a4506fe838
@@@ -1,23 -1,18 +1,19 @@@
 +#include "test-tool.h"
  #include "cache.h"
  #include "lockfile.h"
  
- static struct lock_file index_lock;
 -int cmd_main(int argc, const char **argv)
 +int cmd__write_cache(int argc, const char **argv)
  {
-       int i, cnt = 1, lockfd;
+       struct lock_file index_lock = LOCK_INIT;
+       int i, cnt = 1;
        if (argc == 2)
                cnt = strtol(argv[1], NULL, 0);
        setup_git_directory();
        read_cache();
        for (i = 0; i < cnt; i++) {
-               lockfd = hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
-               if (0 <= lockfd) {
-                       write_locked_index(&the_index, &index_lock, COMMIT_LOCK);
-               } else {
-                       rollback_lock_file(&index_lock);
-               }
+               hold_locked_index(&index_lock, LOCK_DIE_ON_ERROR);
+               if (write_locked_index(&the_index, &index_lock, COMMIT_LOCK))
+                       die("unable to write index file");
        }
  
        return 0;