Merge branch 'sb/object-store-replace'
authorJunio C Hamano <gitster@pobox.com>
Tue, 8 May 2018 06:59:21 +0000 (15:59 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 8 May 2018 06:59:21 +0000 (15:59 +0900)
The effort to pass the repository in-core structure throughout the
API continues.  This round deals with the code that implements the
refs/replace/ mechanism.

* sb/object-store-replace:
  replace-object: allow lookup_replace_object to handle arbitrary repositories
  replace-object: allow do_lookup_replace_object to handle arbitrary repositories
  replace-object: allow prepare_replace_object to handle arbitrary repositories
  refs: allow for_each_replace_ref to handle arbitrary repositories
  refs: store the main ref store inside the repository struct
  replace-object: add repository argument to lookup_replace_object
  replace-object: add repository argument to do_lookup_replace_object
  replace-object: add repository argument to prepare_replace_object
  refs: add repository argument to for_each_replace_ref
  refs: add repository argument to get_main_ref_store
  replace-object: check_replace_refs is safe in multi repo environment
  replace-object: eliminate replace objects prepared flag
  object-store: move lookup_replace_object to replace-object.h
  replace-object: move replace_map to object store
  replace_object: use oidmap

1  2 
cache.h
environment.c
refs.c
refs.h
refs/files-backend.c
replace-object.c
repository.h
sha1-file.c

diff --combined cache.h
+++ b/cache.h
@@@ -428,7 -428,6 +428,7 @@@ static inline enum object_type object_t
  #define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
  #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
  #define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
 +#define GIT_TEXT_DOMAIN_DIR_ENVIRONMENT "GIT_TEXTDOMAINDIR"
  
  /*
   * Environment variable used in handshaking the wire protocol.
@@@ -478,7 -477,7 +478,7 @@@ extern const char *get_git_common_dir(v
  extern char *get_object_directory(void);
  extern char *get_index_file(void);
  extern char *get_graft_file(void);
 -extern int set_git_dir(const char *path);
 +extern void set_git_dir(const char *path);
  extern int get_common_dir_noenv(struct strbuf *sb, const char *gitdir);
  extern int get_common_dir(struct strbuf *sb, const char *gitdir);
  extern const char *get_git_namespace(void);
@@@ -806,7 -805,6 +806,7 @@@ extern char *git_replace_ref_base
  
  extern int fsync_object_files;
  extern int core_preload_index;
 +extern int core_commit_graph;
  extern int core_apply_sparse_checkout;
  extern int precomposed_unicode;
  extern int protect_hfs;
@@@ -1193,25 -1191,6 +1193,6 @@@ static inline void *read_object_file(co
        return read_object_file_extended(oid, type, size, 1);
  }
  
- /*
-  * This internal function is only declared here for the benefit of
-  * lookup_replace_object().  Please do not call it directly.
-  */
- extern const struct object_id *do_lookup_replace_object(const struct object_id *oid);
- /*
-  * If object sha1 should be replaced, return the replacement object's
-  * name (replaced recursively, if necessary).  The return value is
-  * either sha1 or a pointer to a permanently-allocated value.  When
-  * object replacement is suppressed, always return sha1.
-  */
- static inline const struct object_id *lookup_replace_object(const struct object_id *oid)
- {
-       if (!check_replace_refs)
-               return oid;
-       return do_lookup_replace_object(oid);
- }
  /* Read and unpack an object file into memory, write memory to an object file */
  extern int oid_object_info(const struct object_id *, unsigned long *);
  
diff --combined environment.c
@@@ -15,7 -15,6 +15,7 @@@
  #include "commit.h"
  #include "argv-array.h"
  #include "object-store.h"
 +#include "chdir-notify.h"
  
  int trust_executable_bit = 1;
  int trust_ctime = 1;
@@@ -51,7 -50,7 +51,7 @@@ const char *editor_program
  const char *askpass_program;
  const char *excludes_file;
  enum auto_crlf auto_crlf = AUTO_CRLF_FALSE;
- int check_replace_refs = 1;
+ int check_replace_refs = 1; /* NEEDSWORK: rename to read_replace_refs */
  char *git_replace_ref_base;
  enum eol core_eol = EOL_UNSET;
  int global_conv_flags_eol = CONV_EOL_RNDTRP_WARN;
@@@ -65,7 -64,6 +65,7 @@@ enum push_default_type push_default = P
  enum object_creation_mode object_creation_mode = OBJECT_CREATION_MODE;
  char *notes_ref_name;
  int grafts_replace_parents = 1;
 +int core_commit_graph;
  int core_apply_sparse_checkout;
  int merge_log_config = -1;
  int precomposed_unicode = -1; /* see probe_utf8_pathname_composition() */
@@@ -325,31 -323,12 +325,31 @@@ char *get_graft_file(void
        return the_repository->graft_file;
  }
  
 -int set_git_dir(const char *path)
 +static void set_git_dir_1(const char *path)
  {
        if (setenv(GIT_DIR_ENVIRONMENT, path, 1))
 -              return error("Could not set GIT_DIR to '%s'", path);
 +              die("could not set GIT_DIR to '%s'", path);
        setup_git_env(path);
 -      return 0;
 +}
 +
 +static void update_relative_gitdir(const char *name,
 +                                 const char *old_cwd,
 +                                 const char *new_cwd,
 +                                 void *data)
 +{
 +      char *path = reparent_relative_path(old_cwd, new_cwd, get_git_dir());
 +      trace_printf_key(&trace_setup_key,
 +                       "setup: move $GIT_DIR to '%s'",
 +                       path);
 +      set_git_dir_1(path);
 +      free(path);
 +}
 +
 +void set_git_dir(const char *path)
 +{
 +      set_git_dir_1(path);
 +      if (!is_absolute_path(path))
 +              chdir_notify_register(NULL, update_relative_gitdir, NULL);
  }
  
  const char *get_log_output_encoding(void)
diff --combined refs.c
--- 1/refs.c
--- 2/refs.c
+++ b/refs.c
@@@ -13,7 -13,7 +13,8 @@@
  #include "tag.h"
  #include "submodule.h"
  #include "worktree.h"
 +#include "argv-array.h"
+ #include "repository.h"
  
  /*
   * List of all available backends
@@@ -207,7 -207,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);
  }
@@@ -229,7 -229,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);
  }
  
@@@ -376,7 -376,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)
@@@ -502,19 -502,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
@@@ -744,7 -731,7 +745,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);
  }
  
@@@ -942,7 -929,7 +943,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)
@@@ -1074,7 -1061,7 +1075,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);
@@@ -1113,7 -1100,7 +1114,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);
  }
  
@@@ -1334,7 -1321,7 +1335,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(
@@@ -1393,7 -1380,7 +1394,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);
  }
  
@@@ -1428,9 -1415,9 +1429,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);
@@@ -1441,7 -1428,7 +1442,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;
@@@ -1455,7 -1442,7 +1456,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,
@@@ -1561,7 -1548,7 +1562,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);
  }
  
@@@ -1621,9 -1608,6 +1622,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;
  
@@@ -1665,13 -1649,13 +1663,13 @@@ 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;
  
-       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;
  }
  
  /*
@@@ -1740,7 -1724,7 +1738,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);
@@@ -1796,7 -1780,7 +1794,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);
  }
  
@@@ -2020,7 -2004,7 +2018,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);
  }
  
@@@ -2048,7 -2032,7 +2046,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);
  }
  
@@@ -2059,7 -2043,7 +2057,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);
  }
  
@@@ -2082,7 -2066,7 +2080,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,
@@@ -2105,7 -2089,7 +2103,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);
@@@ -2128,7 -2112,7 +2126,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.h
--- 1/refs.h
--- 2/refs.h
+++ b/refs.h
@@@ -139,13 -139,6 +139,13 @@@ int resolve_gitlink_ref(const char *sub
   */
  int refname_match(const char *abbrev_name, const char *full_name);
  
 +/*
 + * Given a 'prefix' expand it by the rules in 'ref_rev_parse_rules' and add
 + * the results to 'prefixes'
 + */
 +struct argv_array;
 +void expand_ref_prefix(struct argv_array *prefixes, const char *prefix);
 +
  int expand_ref(const char *str, int len, struct object_id *oid, char **ref);
  int dwim_ref(const char *str, int len, struct object_id *oid, char **ref);
  int dwim_log(const char *str, int len, struct object_id *oid, char **ref);
@@@ -307,7 -300,7 +307,7 @@@ int for_each_fullref_in(const char *pre
  int for_each_tag_ref(each_ref_fn fn, void *cb_data);
  int for_each_branch_ref(each_ref_fn fn, void *cb_data);
  int for_each_remote_ref(each_ref_fn fn, void *cb_data);
- int for_each_replace_ref(each_ref_fn fn, void *cb_data);
+ int for_each_replace_ref(struct repository *r, each_ref_fn fn, void *cb_data);
  int for_each_glob_ref(each_ref_fn fn, const char *pattern, void *cb_data);
  int for_each_glob_ref_in(each_ref_fn fn, const char *pattern,
                         const char *prefix, void *cb_data);
@@@ -765,7 -758,7 +765,7 @@@ int reflog_expire(const char *refname, 
  
  int ref_storage_backend_exists(const char *name);
  
- struct ref_store *get_main_ref_store(void);
+ struct ref_store *get_main_ref_store(struct repository *r);
  /*
   * Return the ref_store instance for the specified submodule. For the
   * main repository, use submodule==NULL; such a call cannot fail. For
diff --combined refs/files-backend.c
@@@ -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,10 -61,6 +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;
@@@ -107,11 -102,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;
  }
  
diff --combined replace-object.c
@@@ -1,55 -1,11 +1,11 @@@
  #include "cache.h"
- #include "sha1-lookup.h"
+ #include "oidmap.h"
+ #include "object-store.h"
+ #include "replace-object.h"
  #include "refs.h"
+ #include "repository.h"
  #include "commit.h"
  
- /*
-  * An array of replacements.  The array is kept sorted by the original
-  * sha1.
-  */
- static struct replace_object {
-       struct object_id original;
-       struct object_id replacement;
- } **replace_object;
- static int replace_object_alloc, replace_object_nr;
- static const unsigned char *replace_sha1_access(size_t index, void *table)
- {
-       struct replace_object **replace = table;
-       return replace[index]->original.hash;
- }
- static int replace_object_pos(const unsigned char *sha1)
- {
-       return sha1_pos(sha1, replace_object, replace_object_nr,
-                       replace_sha1_access);
- }
- static int register_replace_object(struct replace_object *replace,
-                                  int ignore_dups)
- {
-       int pos = replace_object_pos(replace->original.hash);
-       if (0 <= pos) {
-               if (ignore_dups)
-                       free(replace);
-               else {
-                       free(replace_object[pos]);
-                       replace_object[pos] = replace;
-               }
-               return 1;
-       }
-       pos = -pos - 1;
-       ALLOC_GROW(replace_object, replace_object_nr + 1, replace_object_alloc);
-       replace_object_nr++;
-       if (pos < replace_object_nr)
-               MOVE_ARRAY(replace_object + pos + 1, replace_object + pos,
-                          replace_object_nr - pos - 1);
-       replace_object[pos] = replace;
-       return 0;
- }
  static int register_replace_ref(const char *refname,
                                const struct object_id *oid,
                                int flag, void *cb_data)
@@@ -59,7 -15,7 +15,7 @@@
        const char *hash = slash ? slash + 1 : refname;
        struct replace_object *repl_obj = xmalloc(sizeof(*repl_obj));
  
-       if (get_oid_hex(hash, &repl_obj->original)) {
+       if (get_oid_hex(hash, &repl_obj->original.oid)) {
                free(repl_obj);
                warning("bad replace ref name: %s", refname);
                return 0;
        oidcpy(&repl_obj->replacement, oid);
  
        /* Register new object */
-       if (register_replace_object(repl_obj, 1))
+       if (oidmap_put(the_repository->objects->replace_map, repl_obj))
                die("duplicate replace ref: %s", refname);
  
        return 0;
  }
  
- static void prepare_replace_object(void)
+ static void prepare_replace_object(struct repository *r)
  {
-       static int replace_object_prepared;
-       if (replace_object_prepared)
+       if (r->objects->replace_map)
                return;
  
-       for_each_replace_ref(register_replace_ref, NULL);
-       replace_object_prepared = 1;
-       if (!replace_object_nr)
-               check_replace_refs = 0;
+       r->objects->replace_map =
+               xmalloc(sizeof(*the_repository->objects->replace_map));
+       oidmap_init(r->objects->replace_map, 0);
+       for_each_replace_ref(r, register_replace_ref, NULL);
  }
  
  /* We allow "recursive" replacement. Only within reason, though */
   * permanently-allocated value.  This function always respects replace
   * references, regardless of the value of check_replace_refs.
   */
- const struct object_id *do_lookup_replace_object(const struct object_id *oid)
+ const struct object_id *do_lookup_replace_object(struct repository *r,
+                                                const struct object_id *oid)
  {
-       int pos, depth = MAXREPLACEDEPTH;
+       int depth = MAXREPLACEDEPTH;
        const struct object_id *cur = oid;
  
-       prepare_replace_object();
+       prepare_replace_object(r);
  
        /* Try to recursively replace the object */
-       do {
-               if (--depth < 0)
-                       die("replace depth too high for object %s",
-                           oid_to_hex(oid));
-               pos = replace_object_pos(cur->hash);
-               if (0 <= pos)
-                       cur = &replace_object[pos]->replacement;
-       } while (0 <= pos);
-       return cur;
+       while (depth-- > 0) {
+               struct replace_object *repl_obj =
+                       oidmap_get(r->objects->replace_map, cur);
+               if (!repl_obj)
+                       return cur;
+               cur = &repl_obj->replacement;
+       }
+       die("replace depth too high for object %s", oid_to_hex(oid));
  }
diff --combined repository.h
@@@ -26,6 -26,9 +26,9 @@@ struct repository 
         */
        struct raw_object_store *objects;
  
+       /* The store in which the refs are held. */
+       struct ref_store *refs;
        /*
         * Path to the repository's graft file.
         * Cannot be NULL after initialization.
@@@ -97,9 -100,6 +100,9 @@@ extern void repo_set_gitdir(struct repo
  extern void repo_set_worktree(struct repository *repo, const char *path);
  extern void repo_set_hash_algo(struct repository *repo, int algo);
  extern void initialize_the_repository(void);
 +extern int repo_init(struct repository *r,
 +                   const char *gitdir,
 +                   const char *worktree);
  extern int repo_submodule_init(struct repository *submodule,
                               struct repository *superproject,
                               const char *path);
diff --combined sha1-file.c
@@@ -23,6 -23,7 +23,7 @@@
  #include "sha1-lookup.h"
  #include "bulk-checkin.h"
  #include "repository.h"
+ #include "replace-object.h"
  #include "streaming.h"
  #include "dir.h"
  #include "list.h"
@@@ -1239,7 -1240,7 +1240,7 @@@ int oid_object_info_extended(const stru
        int already_retried = 0;
  
        if (flags & OBJECT_INFO_LOOKUP_REPLACE)
-               real = lookup_replace_object(oid);
+               real = lookup_replace_object(the_repository, oid);
  
        if (is_null_oid(real))
                return -1;
@@@ -1383,8 -1384,8 +1384,8 @@@ void *read_object_file_extended(const s
        const struct packed_git *p;
        const char *path;
        struct stat st;
-       const struct object_id *repl = lookup_replace ? lookup_replace_object(oid)
-                                                     : oid;
+       const struct object_id *repl = lookup_replace ?
+               lookup_replace_object(the_repository, oid) : oid;
  
        errno = 0;
        data = read_object(repl->hash, type, size);