Merge branch 'jm/cache-entry-from-mem-pool'
authorJunio C Hamano <gitster@pobox.com>
Thu, 2 Aug 2018 22:30:43 +0000 (15:30 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 2 Aug 2018 22:30:43 +0000 (15:30 -0700)
For a large tree, the index needs to hold many cache entries
allocated on heap. These cache entries are now allocated out of a
dedicated memory pool to amortize malloc(3) overhead.

* jm/cache-entry-from-mem-pool:
block alloc: add validations around cache_entry lifecyle
block alloc: allocate cache entries from mem_pool
mem-pool: fill out functionality
mem-pool: add life cycle management functions
mem-pool: only search head block for available space
block alloc: add lifecycle APIs for cache_entry structs
read-cache: teach make_cache_entry to take object_id
read-cache: teach refresh_cache_entry to take istate

12 files changed:
1  2 
apply.c
blame.c
builtin/checkout.c
builtin/difftool.c
builtin/reset.c
builtin/update-index.c
cache.h
git.c
merge-recursive.c
read-cache.c
tree.c
unpack-trees.c
diff --combined apply.c
index 49752cde44df6f0853051abacf8546ab92ee4d7a,ee6c406c7a9fc5c402736bd504879f35ec1925dc..2594927248b44715054d8a52faeb2cd3948c2d30
+++ b/apply.c
@@@ -9,7 -9,6 +9,7 @@@
  
  #include "cache.h"
  #include "config.h"
 +#include "object-store.h"
  #include "blob.h"
  #include "delta.h"
  #include "diff.h"
@@@ -142,8 -141,6 +142,8 @@@ int check_apply_state(struct apply_stat
                        return error(_("--cached outside a repository"));
                state->check_index = 1;
        }
 +      if (state->ita_only && (state->check_index || is_not_gitdir))
 +              state->ita_only = 0;
        if (state->check_index)
                state->unsafe_paths = 0;
  
@@@ -4056,7 -4053,7 +4056,7 @@@ static int preimage_oid_in_gitlink_patc
        return get_oid_hex(p->old_sha1_prefix, oid);
  }
  
 -/* Build an index that contains the just the files needed for a 3way merge */
 +/* Build an index that contains just the files needed for a 3way merge */
  static int build_fake_ancestor(struct apply_state *state, struct patch *list)
  {
        struct patch *patch;
                        return error(_("sha1 information is lacking or useless "
                                       "(%s)."), name);
  
-               ce = make_cache_entry(patch->old_mode, oid.hash, name, 0, 0);
+               ce = make_cache_entry(&result, patch->old_mode, &oid, name, 0, 0);
                if (!ce)
                        return error(_("make_cache_entry failed for path '%s'"),
                                     name);
                if (add_index_entry(&result, ce, ADD_CACHE_OK_TO_ADD)) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("could not add %s to temporary index"),
                                     name);
                }
@@@ -4245,7 -4242,7 +4245,7 @@@ static void patch_stats(struct apply_st
  
  static int remove_file(struct apply_state *state, struct patch *patch, int rmdir_empty)
  {
 -      if (state->update_index) {
 +      if (state->update_index && !state->ita_only) {
                if (remove_file_from_cache(patch->old_name) < 0)
                        return error(_("unable to remove %s from index"), patch->old_name);
        }
@@@ -4266,28 -4263,27 +4266,27 @@@ static int add_index_file(struct apply_
        struct stat st;
        struct cache_entry *ce;
        int namelen = strlen(path);
-       unsigned ce_size = cache_entry_size(namelen);
  
-       ce = xcalloc(1, ce_size);
 -      if (!state->update_index)
 -              return 0;
 -
+       ce = make_empty_cache_entry(&the_index, namelen);
        memcpy(ce->name, path, namelen);
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = namelen;
 -      if (S_ISGITLINK(mode)) {
 +      if (state->ita_only) {
 +              ce->ce_flags |= CE_INTENT_TO_ADD;
 +              set_object_name_for_intent_to_add_entry(ce);
 +      } else if (S_ISGITLINK(mode)) {
                const char *s;
  
                if (!skip_prefix(buf, "Subproject commit ", &s) ||
                    get_oid_hex(s, &ce->oid)) {
-                       free(ce);
-                      return error(_("corrupt patch for submodule %s"), path);
+                       discard_cache_entry(ce);
+                       return error(_("corrupt patch for submodule %s"), path);
                }
        } else {
                if (!state->cached) {
                        if (lstat(path, &st) < 0) {
-                               free(ce);
+                               discard_cache_entry(ce);
                                return error_errno(_("unable to stat newly "
                                                     "created file '%s'"),
                                                   path);
                        fill_stat_cache_info(ce, &st);
                }
                if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("unable to create backing store "
                                       "for newly created file %s"), path);
                }
        }
        if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
-               free(ce);
+               discard_cache_entry(ce);
                return error(_("unable to add cache entry for %s"), path);
        }
  
@@@ -4425,27 -4421,26 +4424,26 @@@ static int add_conflicted_stages_file(s
                                       struct patch *patch)
  {
        int stage, namelen;
-       unsigned ce_size, mode;
+       unsigned mode;
        struct cache_entry *ce;
  
        if (!state->update_index)
                return 0;
        namelen = strlen(patch->new_name);
-       ce_size = cache_entry_size(namelen);
        mode = patch->new_mode ? patch->new_mode : (S_IFREG | 0644);
  
        remove_file_from_cache(patch->new_name);
        for (stage = 1; stage < 4; stage++) {
                if (is_null_oid(&patch->threeway_stage[stage - 1]))
                        continue;
-               ce = xcalloc(1, ce_size);
+               ce = make_empty_cache_entry(&the_index, namelen);
                memcpy(ce->name, patch->new_name, namelen);
                ce->ce_mode = create_ce_mode(mode);
                ce->ce_flags = create_ce_flags(stage);
                ce->ce_namelen = namelen;
                oidcpy(&ce->oid, &patch->threeway_stage[stage - 1]);
                if (add_cache_entry(ce, ADD_CACHE_OK_TO_ADD) < 0) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error(_("unable to add cache entry for %s"),
                                     patch->new_name);
                }
@@@ -4468,9 -4463,8 +4466,9 @@@ static int create_file(struct apply_sta
  
        if (patch->conflicted_threeway)
                return add_conflicted_stages_file(state, patch);
 -      else
 +      else if (state->update_index)
                return add_index_file(state, path, mode, buf, size);
 +      return 0;
  }
  
  /* phase zero is to remove, phase one is to create */
@@@ -4690,7 -4684,7 +4688,7 @@@ static int apply_patch(struct apply_sta
        if (state->whitespace_error && (state->ws_error_action == die_on_ws_error))
                state->apply = 0;
  
 -      state->update_index = state->check_index && state->apply;
 +      state->update_index = (state->check_index || state->ita_only) && state->apply;
        if (state->update_index && !is_lock_file_locked(&state->lock_file)) {
                if (state->index_file)
                        hold_lock_file_for_update(&state->lock_file,
@@@ -4945,8 -4939,6 +4943,8 @@@ int apply_parse_options(int argc, cons
                        N_("instead of applying the patch, see if the patch is applicable")),
                OPT_BOOL(0, "index", &state->check_index,
                        N_("make sure the patch is applicable to the current index")),
 +              OPT_BOOL('N', "intent-to-add", &state->ita_only,
 +                      N_("mark new files with `git add --intent-to-add`")),
                OPT_BOOL(0, "cached", &state->cached,
                        N_("apply a patch without touching the working tree")),
                OPT_BOOL_F(0, "unsafe-paths", &state->unsafe_paths,
diff --combined blame.c
index 4229bcd384c275d584c35d9aeee7768aa79348aa,4c6668d0e16ad8f52df763f5e5f2fd849deb5b2c..58a7036847d9be574bbc3863d7ba4deb548628b7
+++ b/blame.c
@@@ -1,31 -1,11 +1,31 @@@
  #include "cache.h"
  #include "refs.h"
 +#include "object-store.h"
  #include "cache-tree.h"
  #include "mergesort.h"
  #include "diff.h"
  #include "diffcore.h"
  #include "tag.h"
  #include "blame.h"
 +#include "alloc.h"
 +#include "commit-slab.h"
 +
 +define_commit_slab(blame_suspects, struct blame_origin *);
 +static struct blame_suspects blame_suspects;
 +
 +struct blame_origin *get_blame_suspects(struct commit *commit)
 +{
 +      struct blame_origin **result;
 +
 +      result = blame_suspects_peek(&blame_suspects, commit);
 +
 +      return result ? *result : NULL;
 +}
 +
 +static void set_blame_suspects(struct commit *commit, struct blame_origin *origin)
 +{
 +      *blame_suspects_at(&blame_suspects, commit) = origin;
 +}
  
  void blame_origin_decref(struct blame_origin *o)
  {
                        blame_origin_decref(o->previous);
                free(o->file.ptr);
                /* Should be present exactly once in commit chain */
 -              for (p = o->commit->util; p; l = p, p = p->next) {
 +              for (p = get_blame_suspects(o->commit); p; l = p, p = p->next) {
                        if (p == o) {
                                if (l)
                                        l->next = p->next;
                                else
 -                                      o->commit->util = p->next;
 +                                      set_blame_suspects(o->commit, p->next);
                                free(o);
                                return;
                        }
@@@ -61,8 -41,8 +61,8 @@@ static struct blame_origin *make_origin
        FLEX_ALLOC_STR(o, path, path);
        o->commit = commit;
        o->refcnt = 1;
 -      o->next = commit->util;
 -      commit->util = o;
 +      o->next = get_blame_suspects(commit);
 +      set_blame_suspects(commit, o);
        return o;
  }
  
@@@ -74,13 -54,13 +74,13 @@@ static struct blame_origin *get_origin(
  {
        struct blame_origin *o, *l;
  
 -      for (o = commit->util, l = NULL; o; l = o, o = o->next) {
 +      for (o = get_blame_suspects(commit), l = NULL; o; l = o, o = o->next) {
                if (!strcmp(o->path, path)) {
                        /* bump to front */
                        if (l) {
                                l->next = o->next;
 -                              o->next = commit->util;
 -                              commit->util = o;
 +                              o->next = get_blame_suspects(commit);
 +                              set_blame_suspects(commit, o);
                        }
                        return blame_origin_incref(o);
                }
@@@ -119,7 -99,7 +119,7 @@@ static struct commit_list **append_pare
  {
        struct commit *parent;
  
 -      parent = lookup_commit_reference(oid);
 +      parent = lookup_commit_reference(the_repository, oid);
        if (!parent)
                die("no such commit %s", oid_to_hex(oid));
        return &commit_list_insert(parent, tail)->next;
@@@ -130,19 -110,17 +130,19 @@@ static void append_merge_parents(struc
        int merge_head;
        struct strbuf line = STRBUF_INIT;
  
 -      merge_head = open(git_path_merge_head(), O_RDONLY);
 +      merge_head = open(git_path_merge_head(the_repository), O_RDONLY);
        if (merge_head < 0) {
                if (errno == ENOENT)
                        return;
 -              die("cannot open '%s' for reading", git_path_merge_head());
 +              die("cannot open '%s' for reading",
 +                  git_path_merge_head(the_repository));
        }
  
        while (!strbuf_getwholeline_fd(&line, merge_head, '\n')) {
                struct object_id oid;
                if (line.len < GIT_SHA1_HEXSZ || get_oid_hex(line.buf, &oid))
 -                      die("unknown line in '%s': %s", git_path_merge_head(), line.buf);
 +                      die("unknown line in '%s': %s",
 +                          git_path_merge_head(the_repository), line.buf);
                tail = append_parent(tail, &oid);
        }
        close(merge_head);
@@@ -158,7 -136,7 +158,7 @@@ static void set_commit_buffer_from_strb
  {
        size_t len;
        void *buf = strbuf_detach(sb, &len);
 -      set_commit_buffer(c, buf, len);
 +      set_commit_buffer(the_repository, c, buf, len);
  }
  
  /*
@@@ -176,14 -154,14 +176,14 @@@ static struct commit *fake_working_tree
        struct strbuf buf = STRBUF_INIT;
        const char *ident;
        time_t now;
-       int size, len;
+       int len;
        struct cache_entry *ce;
        unsigned mode;
        struct strbuf msg = STRBUF_INIT;
  
        read_cache();
        time(&now);
 -      commit = alloc_commit_node();
 +      commit = alloc_commit_node(the_repository);
        commit->object.parsed = 1;
        commit->date = now;
        parent_tail = &commit->parents;
                        /* Let's not bother reading from HEAD tree */
                        mode = S_IFREG | 0644;
        }
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, len);
        oidcpy(&ce->oid, &origin->blob_oid);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(0);
@@@ -500,7 -477,7 +499,7 @@@ static void queue_blames(struct blame_s
                porigin->suspects = blame_merge(porigin->suspects, sorted);
        else {
                struct blame_origin *o;
 -              for (o = porigin->commit->util; o; o = o->next) {
 +              for (o = get_blame_suspects(porigin->commit); o; o = o->next) {
                        if (o->suspects) {
                                porigin->suspects = sorted;
                                return;
@@@ -547,7 -524,7 +546,7 @@@ static struct blame_origin *find_origin
        const char *paths[2];
  
        /* First check any existing origins */
 -      for (porigin = parent->util; porigin; porigin = porigin->next)
 +      for (porigin = get_blame_suspects(parent); porigin; porigin = porigin->next)
                if (!strcmp(porigin->path, origin->path)) {
                        /*
                         * The same path between origin and its parent
@@@ -1572,7 -1549,7 +1571,7 @@@ void assign_blame(struct blame_scoreboa
  
        while (commit) {
                struct blame_entry *ent;
 -              struct blame_origin *suspect = commit->util;
 +              struct blame_origin *suspect = get_blame_suspects(commit);
  
                /* find one suspect to break down */
                while (suspect && !suspect->suspects)
@@@ -1674,7 -1651,7 +1673,7 @@@ static struct commit *find_single_final
                struct object *obj = revs->pending.objects[i].item;
                if (obj->flags & UNINTERESTING)
                        continue;
 -              obj = deref_tag(obj, NULL, 0);
 +              obj = deref_tag(the_repository, obj, NULL, 0);
                if (obj->type != OBJ_COMMIT)
                        die("Non commit %s?", revs->pending.objects[i].name);
                if (found)
@@@ -1705,15 -1682,14 +1704,15 @@@ static struct commit *dwim_reverse_init
  
        /* Is that sole rev a committish? */
        obj = revs->pending.objects[0].item;
 -      obj = deref_tag(obj, NULL, 0);
 +      obj = deref_tag(the_repository, obj, NULL, 0);
        if (obj->type != OBJ_COMMIT)
                return NULL;
  
        /* Do we have HEAD? */
        if (!resolve_ref_unsafe("HEAD", RESOLVE_REF_READING, &head_oid, NULL))
                return NULL;
 -      head_commit = lookup_commit_reference_gently(&head_oid, 1);
 +      head_commit = lookup_commit_reference_gently(the_repository,
 +                                                   &head_oid, 1);
        if (!head_commit)
                return NULL;
  
@@@ -1741,7 -1717,7 +1740,7 @@@ static struct commit *find_single_initi
                struct object *obj = revs->pending.objects[i].item;
                if (!(obj->flags & UNINTERESTING))
                        continue;
 -              obj = deref_tag(obj, NULL, 0);
 +              obj = deref_tag(the_repository, obj, NULL, 0);
                if (obj->type != OBJ_COMMIT)
                        die("Non commit %s?", revs->pending.objects[i].name);
                if (found)
@@@ -1775,8 -1751,6 +1774,8 @@@ void setup_scoreboard(struct blame_scor
        struct commit *final_commit = NULL;
        enum object_type type;
  
 +      init_blame_suspects(&blame_suspects);
 +
        if (sb->reverse && sb->contents_from)
                die(_("--contents and --reverse do not blend well."));
  
        }
  
        if (is_null_oid(&sb->final->object.oid)) {
 -              o = sb->final->util;
 +              o = get_blame_suspects(sb->final);
                sb->final_buf = xmemdupz(o->file.ptr, o->file.size);
                sb->final_buf_size = o->file.size;
        }
diff --combined builtin/checkout.c
index 923b8cbd8240e16bad5adace670b3b63b9c02768,56d1e1a28d6ab1f8495e1b9c1898aecb027be332..516136a23a3d6962703186ca825e416cb653e677
@@@ -4,7 -4,6 +4,7 @@@
  #include "lockfile.h"
  #include "parse-options.h"
  #include "refs.h"
 +#include "object-store.h"
  #include "commit.h"
  #include "tree.h"
  #include "tree-walk.h"
@@@ -23,7 -22,6 +23,7 @@@
  #include "resolve-undo.h"
  #include "submodule-config.h"
  #include "submodule.h"
 +#include "advice.h"
  
  static const char * const checkout_usage[] = {
        N_("git checkout [<options>] <branch>"),
@@@ -79,7 -77,7 +79,7 @@@ static int update_some(const struct obj
                return READ_TREE_RECURSIVE;
  
        len = base->len + strlen(pathname);
-       ce = xcalloc(1, cache_entry_size(len));
+       ce = make_empty_cache_entry(&the_index, len);
        oidcpy(&ce->oid, oid);
        memcpy(ce->name, base->buf, base->len);
        memcpy(ce->name + base->len, pathname, len - base->len);
@@@ -98,7 -96,7 +98,7 @@@
                if (ce->ce_mode == old->ce_mode &&
                    !oidcmp(&ce->oid, &old->oid)) {
                        old->ce_flags |= CE_UPDATE;
-                       free(ce);
+                       discard_cache_entry(ce);
                        return 0;
                }
        }
@@@ -232,11 -230,11 +232,11 @@@ static int checkout_merged(int pos, con
        if (write_object_file(result_buf.ptr, result_buf.size, blob_type, &oid))
                die(_("Unable to add merge result for '%s'"), path);
        free(result_buf.ptr);
-       ce = make_cache_entry(mode, oid.hash, path, 2, 0);
+       ce = make_transient_cache_entry(mode, &oid, path, 2);
        if (!ce)
                die(_("make_cache_entry failed for path '%s'"), path);
        status = checkout_entry(ce, state, NULL);
-       free(ce);
+       discard_cache_entry(ce);
        return status;
  }
  
@@@ -380,7 -378,7 +380,7 @@@ static int checkout_paths(const struct 
                die(_("unable to write new index file"));
  
        read_ref_full("HEAD", 0, &rev, NULL);
 -      head = lookup_commit_reference_gently(&rev, 1);
 +      head = lookup_commit_reference_gently(the_repository, &rev, 1);
  
        errs |= post_checkout_hook(head, head, 0);
        return errs;
@@@ -831,7 -829,7 +831,7 @@@ static int switch_branches(const struc
        memset(&old_branch_info, 0, sizeof(old_branch_info));
        old_branch_info.path = path_to_free = resolve_refdup("HEAD", 0, &rev, &flag);
        if (old_branch_info.path)
 -              old_branch_info.commit = lookup_commit_reference_gently(&rev, 1);
 +              old_branch_info.commit = lookup_commit_reference_gently(the_repository, &rev, 1);
        if (!(flag & REF_ISSYMREF))
                old_branch_info.path = NULL;
  
@@@ -880,8 -878,7 +880,8 @@@ static int parse_branchname_arg(int arg
                                int dwim_new_local_branch_ok,
                                struct branch_info *new_branch_info,
                                struct checkout_opts *opts,
 -                              struct object_id *rev)
 +                              struct object_id *rev,
 +                              int *dwim_remotes_matched)
  {
        struct tree **source_tree = &opts->source_tree;
        const char **new_branch = &opts->new_branch;
         *   (b) If <something> is _not_ a commit, either "--" is present
         *       or <something> is not a path, no -t or -b was given, and
         *       and there is a tracking branch whose name is <something>
 -       *       in one and only one remote, then this is a short-hand to
 -       *       fork local <something> from that remote-tracking branch.
 +       *       in one and only one remote (or if the branch exists on the
 +       *       remote named in checkout.defaultRemote), then this is a
 +       *       short-hand to fork local <something> from that
 +       *       remote-tracking branch.
         *
         *   (c) Otherwise, if "--" is present, treat it like case (1).
         *
                        recover_with_dwim = 0;
  
                if (recover_with_dwim) {
 -                      const char *remote = unique_tracking_name(arg, rev);
 +                      const char *remote = unique_tracking_name(arg, rev,
 +                                                                dwim_remotes_matched);
                        if (remote) {
                                *new_branch = arg;
                                arg = remote;
        else
                new_branch_info->path = NULL; /* not an existing branch */
  
 -      new_branch_info->commit = lookup_commit_reference_gently(rev, 1);
 +      new_branch_info->commit = lookup_commit_reference_gently(the_repository, rev, 1);
        if (!new_branch_info->commit) {
                /* not a commit */
                *source_tree = parse_tree_indirect(rev);
@@@ -1115,7 -1109,6 +1115,7 @@@ int cmd_checkout(int argc, const char *
        struct branch_info new_branch_info;
        char *conflict_style = NULL;
        int dwim_new_local_branch = 1;
 +      int dwim_remotes_matched = 0;
        struct option options[] = {
                OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
                OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
                OPT_SET_INT('t', "track",  &opts.track, N_("set upstream info for new branch"),
                        BRANCH_TRACK_EXPLICIT),
                OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
 -              OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"),
 -                          2),
 -              OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
 -                          3),
 +              OPT_SET_INT_F('2', "ours", &opts.writeout_stage,
 +                            N_("checkout our version for unmerged files"),
 +                            2, PARSE_OPT_NONEG),
 +              OPT_SET_INT_F('3', "theirs", &opts.writeout_stage,
 +                            N_("checkout their version for unmerged files"),
 +                            3, PARSE_OPT_NONEG),
                OPT__FORCE(&opts.force, N_("force checkout (throw away local modifications)"),
                           PARSE_OPT_NOCOMPLETE),
                OPT_BOOL('m', "merge", &opts.merge, N_("perform a 3-way merge with the new branch")),
                        opts.track == BRANCH_TRACK_UNSPECIFIED &&
                        !opts.new_branch;
                int n = parse_branchname_arg(argc, argv, dwim_ok,
 -                                           &new_branch_info, &opts, &rev);
 +                                           &new_branch_info, &opts, &rev,
 +                                           &dwim_remotes_matched);
                argv += n;
                argc -= n;
        }
        }
  
        UNLEAK(opts);
 -      if (opts.patch_mode || opts.pathspec.nr)
 -              return checkout_paths(&opts, new_branch_info.name);
 -      else
 +      if (opts.patch_mode || opts.pathspec.nr) {
 +              int ret = checkout_paths(&opts, new_branch_info.name);
 +              if (ret && dwim_remotes_matched > 1 &&
 +                  advice_checkout_ambiguous_remote_branch_name)
 +                      advise(_("'%s' matched more than one remote tracking branch.\n"
 +                               "We found %d remotes with a reference that matched. So we fell back\n"
 +                               "on trying to resolve the argument as a path, but failed there too!\n"
 +                               "\n"
 +                               "If you meant to check out a remote tracking branch on, e.g. 'origin',\n"
 +                               "you can do so by fully qualifying the name with the --track option:\n"
 +                               "\n"
 +                               "    git checkout --track origin/<name>\n"
 +                               "\n"
 +                               "If you'd like to always have checkouts of an ambiguous <name> prefer\n"
 +                               "one remote, e.g. the 'origin' remote, consider setting\n"
 +                               "checkout.defaultRemote=origin in your config."),
 +                             argv[0],
 +                             dwim_remotes_matched);
 +              return ret;
 +      } else {
                return checkout_branch(&opts, &new_branch_info);
 +      }
  }
diff --combined builtin/difftool.c
index 51f6c9cdb460f5d35dc1abc199604ac5fa912dda,4593f0c2cd6d4546a66298996ce8001d228d01f4..3018e61d048dacd178200ce380e319ae302b5790
@@@ -20,7 -20,6 +20,7 @@@
  #include "argv-array.h"
  #include "strbuf.h"
  #include "lockfile.h"
 +#include "object-store.h"
  #include "dir.h"
  
  static char *diff_gui_tool;
@@@ -322,10 -321,10 +322,10 @@@ static int checkout_path(unsigned mode
        struct cache_entry *ce;
        int ret;
  
-       ce = make_cache_entry(mode, oid->hash, path, 0, 0);
+       ce = make_transient_cache_entry(mode, oid, path, 0);
        ret = checkout_entry(ce, state, NULL);
  
-       free(ce);
+       discard_cache_entry(ce);
        return ret;
  }
  
@@@ -489,7 -488,7 +489,7 @@@ static int run_dir_diff(const char *ext
                                 * index.
                                 */
                                struct cache_entry *ce2 =
-                                       make_cache_entry(rmode, roid.hash,
+                                       make_cache_entry(&wtindex, rmode, &roid,
                                                         dst_path, 0, 0);
  
                                add_index_entry(&wtindex, ce2,
diff --combined builtin/reset.c
index d9871e5b6c6f3f417baa7daa4d84d3b9bc9142a9,c3f0cfa1e81d02bbfd3e84c7f62ef018c835403b..11cd0dcb8cc73ac753b7ed746e194ba1458742ee
@@@ -39,7 -39,7 +39,7 @@@ static const char *reset_type_names[] 
  
  static inline int is_merge(void)
  {
 -      return !access(git_path_merge_head(), F_OK);
 +      return !access(git_path_merge_head(the_repository), F_OK);
  }
  
  static int reset_index(const struct object_id *oid, int reset_type, int quiet)
@@@ -134,7 -134,7 +134,7 @@@ static void update_index_from_diff(stru
                        continue;
                }
  
-               ce = make_cache_entry(one->mode, one->oid.hash, one->path,
+               ce = make_cache_entry(&the_index, one->mode, &one->oid, one->path,
                                      0, 0);
                if (!ce)
                        die(_("make_cache_entry failed for path '%s'"),
@@@ -319,7 -319,7 +319,7 @@@ int cmd_reset(int argc, const char **ar
                struct commit *commit;
                if (get_oid_committish(rev, &oid))
                        die(_("Failed to resolve '%s' as a valid revision."), rev);
 -              commit = lookup_commit_reference(&oid);
 +              commit = lookup_commit_reference(the_repository, &oid);
                if (!commit)
                        die(_("Could not parse object '%s'."), rev);
                oidcpy(&oid, &commit->object.oid);
                update_ref_status = reset_refs(rev, &oid);
  
                if (reset_type == HARD && !update_ref_status && !quiet)
 -                      print_new_head_line(lookup_commit_reference(&oid));
 +                      print_new_head_line(lookup_commit_reference(the_repository, &oid));
        }
        if (!pathspec.nr)
                remove_branch_state();
diff --combined builtin/update-index.c
index 3206c5ad45910643f8e75d16b6b0af08f9ac1b00,ea2f2a476c13c57a206b8ad819dbb08371c9be80..f5c0b6a1d23b203de5379cf898b70679857683ff
@@@ -268,15 -268,14 +268,14 @@@ static int process_lstat_error(const ch
  
  static int add_one_path(const struct cache_entry *old, const char *path, int len, struct stat *st)
  {
-       int option, size;
+       int option;
        struct cache_entry *ce;
  
        /* Was the old index entry already up-to-date? */
        if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
                return 0;
  
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, len);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(0);
        ce->ce_namelen = len;
  
        if (index_path(&ce->oid, path, st,
                       info_only ? 0 : HASH_WRITE_OBJECT)) {
-               free(ce);
+               discard_cache_entry(ce);
                return -1;
        }
        option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
        option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
        if (add_cache_entry(ce, option)) {
-               free(ce);
+               discard_cache_entry(ce);
                return error("%s: cannot add to the index - missing --add option?", path);
        }
        return 0;
@@@ -402,15 -401,14 +401,14 @@@ static int process_path(const char *pat
  static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
                         const char *path, int stage)
  {
-       int size, len, option;
+       int len, option;
        struct cache_entry *ce;
  
        if (!verify_path(path, mode))
                return error("Invalid path '%s'", path);
  
        len = strlen(path);
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, len);
  
        oidcpy(&ce->oid, oid);
        memcpy(ce->name, path, len);
@@@ -492,7 -490,6 +490,7 @@@ static void update_one(const char *path
  
  static void read_index_info(int nul_term_line)
  {
 +      const int hexsz = the_hash_algo->hexsz;
        struct strbuf buf = STRBUF_INIT;
        struct strbuf uq = STRBUF_INIT;
        strbuf_getline_fn getline_fn;
                mode = ul;
  
                tab = strchr(ptr, '\t');
 -              if (!tab || tab - ptr < GIT_SHA1_HEXSZ + 1)
 +              if (!tab || tab - ptr < hexsz + 1)
                        goto bad_line;
  
                if (tab[-2] == ' ' && '0' <= tab[-1] && tab[-1] <= '3') {
                        ptr = tab + 1; /* point at the head of path */
                }
  
 -              if (get_oid_hex(tab - GIT_SHA1_HEXSZ, &oid) ||
 -                      tab[-(GIT_SHA1_HEXSZ + 1)] != ' ')
 +              if (get_oid_hex(tab - hexsz, &oid) ||
 +                      tab[-(hexsz + 1)] != ' ')
                        goto bad_line;
  
                path_name = ptr;
                         * ptr[-1] points at tab,
                         * ptr[-41] is at the beginning of sha1
                         */
 -                      ptr[-(GIT_SHA1_HEXSZ + 2)] = ptr[-1] = 0;
 +                      ptr[-(hexsz + 2)] = ptr[-1] = 0;
                        if (add_cacheinfo(mode, &oid, path_name, stage))
                                die("git update-index: unable to update %s",
                                    path_name);
@@@ -600,7 -597,6 +598,6 @@@ static struct cache_entry *read_one_ent
  {
        unsigned mode;
        struct object_id oid;
-       int size;
        struct cache_entry *ce;
  
        if (get_tree_entry(ent, path, &oid, &mode)) {
                        error("%s: not a blob in %s branch.", path, which);
                return NULL;
        }
-       size = cache_entry_size(namelen);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(&the_index, namelen);
  
        oidcpy(&ce->oid, &oid);
        memcpy(ce->name, path, namelen);
@@@ -691,8 -686,8 +687,8 @@@ static int unresolve_one(const char *pa
        error("%s: cannot add their version to the index.", path);
        ret = -1;
   free_return:
-       free(ce_2);
-       free(ce_3);
+       discard_cache_entry(ce_2);
+       discard_cache_entry(ce_3);
        return ret;
  }
  
@@@ -759,7 -754,7 +755,7 @@@ static int do_reupdate(int ac, const ch
                                           ce->name, ce_namelen(ce), 0);
                if (old && ce->ce_mode == old->ce_mode &&
                    !oidcmp(&ce->oid, &old->oid)) {
-                       free(old);
+                       discard_cache_entry(old);
                        continue; /* unchanged */
                }
                /* Be careful.  The working tree may not have the
                path = xstrdup(ce->name);
                update_one(path);
                free(path);
-               free(old);
+               discard_cache_entry(old);
                if (save_nr != active_nr)
                        goto redo;
        }
@@@ -827,7 -822,6 +823,7 @@@ static int parse_new_style_cacheinfo(co
  {
        unsigned long ul;
        char *endp;
 +      const char *p;
  
        if (!arg)
                return -1;
                return -1; /* not a new-style cacheinfo */
        *mode = ul;
        endp++;
 -      if (get_oid_hex(endp, oid) || endp[GIT_SHA1_HEXSZ] != ',')
 +      if (parse_oid_hex(endp, oid, &p) || *p != ',')
                return -1;
 -      *path = endp + GIT_SHA1_HEXSZ + 1;
 +      *path = p + 1;
        return 0;
  }
  
diff --combined cache.h
index ebfe59d01c8ef0e41f9ec228dde124ea9b9015f2,a3334a71cafa519e2e6f2edf915d78d7e23d6377..05388e597b22632fb557603e1b173ce5bab69f4e
+++ b/cache.h
@@@ -15,6 -15,7 +15,7 @@@
  #include "path.h"
  #include "sha1-array.h"
  #include "repository.h"
+ #include "mem-pool.h"
  
  #include <zlib.h>
  typedef struct git_zstream {
@@@ -156,6 -157,7 +157,7 @@@ struct cache_entry 
        struct stat_data ce_stat_data;
        unsigned int ce_mode;
        unsigned int ce_flags;
+       unsigned int mem_pool_allocated;
        unsigned int ce_namelen;
        unsigned int index;     /* for link extension */
        struct object_id oid;
@@@ -227,6 -229,7 +229,7 @@@ static inline void copy_cache_entry(str
                                    const struct cache_entry *src)
  {
        unsigned int state = dst->ce_flags & CE_HASHED;
+       int mem_pool_allocated = dst->mem_pool_allocated;
  
        /* Don't copy hash chain and name */
        memcpy(&dst->ce_stat_data, &src->ce_stat_data,
  
        /* Restore the hash state */
        dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
+       /* Restore the mem_pool_allocated flag */
+       dst->mem_pool_allocated = mem_pool_allocated;
  }
  
  static inline unsigned create_ce_flags(unsigned stage)
@@@ -328,6 -334,7 +334,7 @@@ struct index_state 
        struct untracked_cache *untracked;
        uint64_t fsmonitor_last_update;
        struct ewah_bitmap *fsmonitor_dirty;
+       struct mem_pool *ce_mem_pool;
  };
  
  extern struct index_state the_index;
@@@ -339,6 -346,60 +346,60 @@@ extern void remove_name_hash(struct ind
  extern void free_name_hash(struct index_state *istate);
  
  
+ /* Cache entry creation and cleanup */
+ /*
+  * Create cache_entry intended for use in the specified index. Caller
+  * is responsible for discarding the cache_entry with
+  * `discard_cache_entry`.
+  */
+ struct cache_entry *make_cache_entry(struct index_state *istate,
+                                    unsigned int mode,
+                                    const struct object_id *oid,
+                                    const char *path,
+                                    int stage,
+                                    unsigned int refresh_options);
+ struct cache_entry *make_empty_cache_entry(struct index_state *istate,
+                                          size_t name_len);
+ /*
+  * Create a cache_entry that is not intended to be added to an index.
+  * Caller is responsible for discarding the cache_entry
+  * with `discard_cache_entry`.
+  */
+ struct cache_entry *make_transient_cache_entry(unsigned int mode,
+                                              const struct object_id *oid,
+                                              const char *path,
+                                              int stage);
+ struct cache_entry *make_empty_transient_cache_entry(size_t name_len);
+ /*
+  * Discard cache entry.
+  */
+ void discard_cache_entry(struct cache_entry *ce);
+ /*
+  * Check configuration if we should perform extra validation on cache
+  * entries.
+  */
+ int should_validate_cache_entries(void);
+ /*
+  * Duplicate a cache_entry. Allocate memory for the new entry from a
+  * memory_pool. Takes into account cache_entry fields that are meant
+  * for managing the underlying memory allocation of the cache_entry.
+  */
+ struct cache_entry *dup_cache_entry(const struct cache_entry *ce, struct index_state *istate);
+ /*
+  * Validate the cache entries in the index.  This is an internal
+  * consistency check that the cache_entry structs are allocated from
+  * the expected memory pool.
+  */
+ void validate_cache_entries(const struct index_state *istate);
  #ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
  #define active_cache (the_index.cache)
  #define active_nr (the_index.cache_nr)
@@@ -484,7 -545,7 +545,7 @@@ extern const char *get_git_dir(void)
  extern const char *get_git_common_dir(void);
  extern char *get_object_directory(void);
  extern char *get_index_file(void);
 -extern char *get_graft_file(void);
 +extern char *get_graft_file(struct repository *r);
  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);
@@@ -698,7 -759,6 +759,6 @@@ extern int remove_file_from_index(struc
  extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
  extern int add_file_to_index(struct index_state *, const char *path, int flags);
  
- extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
  extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
  extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
  extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
@@@ -751,7 -811,7 +811,7 @@@ extern void fill_stat_cache_info(struc
  #define REFRESH_IGNORE_SUBMODULES     0x0010  /* ignore submodules */
  #define REFRESH_IN_PORCELAIN  0x0020  /* user friendly output, not "needs update" */
  extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
- extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
+ extern struct cache_entry *refresh_cache_entry(struct index_state *, struct cache_entry *, unsigned int);
  
  /*
   * Opportunistically update the index but do not complain if we can't.
@@@ -972,7 -1032,7 +1032,7 @@@ extern const struct object_id null_oid
  
  static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
 -      return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
 +      return memcmp(sha1, sha2, the_hash_algo->rawsz);
  }
  
  static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
@@@ -992,7 -1052,7 +1052,7 @@@ static inline int is_null_oid(const str
  
  static inline void hashcpy(unsigned char *sha_dst, const unsigned char *sha_src)
  {
 -      memcpy(sha_dst, sha_src, GIT_SHA1_RAWSZ);
 +      memcpy(sha_dst, sha_src, the_hash_algo->rawsz);
  }
  
  static inline void oidcpy(struct object_id *dst, const struct object_id *src)
@@@ -1009,7 -1069,7 +1069,7 @@@ static inline struct object_id *oiddup(
  
  static inline void hashclr(unsigned char *hash)
  {
 -      memset(hash, 0, GIT_SHA1_RAWSZ);
 +      memset(hash, 0, the_hash_algo->rawsz);
  }
  
  static inline void oidclr(struct object_id *oid)
@@@ -1192,6 -1252,32 +1252,6 @@@ extern char *xdg_config_home(const cha
   */
  extern char *xdg_cache_home(const char *filename);
  
 -extern void *read_object_file_extended(const struct object_id *oid,
 -                                     enum object_type *type,
 -                                     unsigned long *size, int lookup_replace);
 -static inline void *read_object_file(const struct object_id *oid, enum object_type *type, unsigned long *size)
 -{
 -      return read_object_file_extended(oid, type, size, 1);
 -}
 -
 -/* Read and unpack an object file into memory, write memory to an object file */
 -int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);
 -
 -extern int hash_object_file(const void *buf, unsigned long len,
 -                          const char *type, struct object_id *oid);
 -
 -extern int write_object_file(const void *buf, unsigned long len,
 -                           const char *type, struct object_id *oid);
 -
 -extern int hash_object_file_literally(const void *buf, unsigned long len,
 -                                    const char *type, struct object_id *oid,
 -                                    unsigned flags);
 -
 -extern int pretend_object_file(void *, unsigned long, enum object_type,
 -                             struct object_id *oid);
 -
 -extern int force_object_loose(const struct object_id *oid, time_t mtime);
 -
  extern int git_open_cloexec(const char *name, int flags);
  #define git_open(name) git_open_cloexec(name, O_RDONLY)
  extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
@@@ -1201,6 -1287,43 +1261,6 @@@ extern int check_object_signature(cons
  
  extern int finalize_object_file(const char *tmpfile, const char *filename);
  
 -/*
 - * Open the loose object at path, check its hash, and return the contents,
 - * type, and size. If the object is a blob, then "contents" may return NULL,
 - * to allow streaming of large blobs.
 - *
 - * Returns 0 on success, negative on error (details may be written to stderr).
 - */
 -int read_loose_object(const char *path,
 -                    const struct object_id *expected_oid,
 -                    enum object_type *type,
 -                    unsigned long *size,
 -                    void **contents);
 -
 -/*
 - * Convenience for sha1_object_info_extended() with a NULL struct
 - * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass
 - * nonzero flags to also set other flags.
 - */
 -extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
 -static inline int has_sha1_file(const unsigned char *sha1)
 -{
 -      return has_sha1_file_with_flags(sha1, 0);
 -}
 -
 -/* Same as the above, except for struct object_id. */
 -extern int has_object_file(const struct object_id *oid);
 -extern int has_object_file_with_flags(const struct object_id *oid, int flags);
 -
 -/*
 - * Return true iff an alternate object database has a loose object
 - * with the specified name.  This function does not respect replace
 - * references.
 - */
 -extern int has_loose_object_nonlocal(const struct object_id *oid);
 -
 -extern void assert_oid_type(const struct object_id *oid, enum object_type expect);
 -
  /* Helper to check and "touch" a file */
  extern int check_and_freshen_file(const char *fn, int freshen);
  
@@@ -1568,6 -1691,60 +1628,6 @@@ int for_each_loose_file_in_objdir_buf(s
  #define FOR_EACH_OBJECT_LOCAL_ONLY 0x1
  extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags);
  
 -struct object_info {
 -      /* Request */
 -      enum object_type *typep;
 -      unsigned long *sizep;
 -      off_t *disk_sizep;
 -      unsigned char *delta_base_sha1;
 -      struct strbuf *type_name;
 -      void **contentp;
 -
 -      /* Response */
 -      enum {
 -              OI_CACHED,
 -              OI_LOOSE,
 -              OI_PACKED,
 -              OI_DBCACHED
 -      } whence;
 -      union {
 -              /*
 -               * struct {
 -               *      ... Nothing to expose in this case
 -               * } cached;
 -               * struct {
 -               *      ... Nothing to expose in this case
 -               * } loose;
 -               */
 -              struct {
 -                      struct packed_git *pack;
 -                      off_t offset;
 -                      unsigned int is_delta;
 -              } packed;
 -      } u;
 -};
 -
 -/*
 - * Initializer for a "struct object_info" that wants no items. You may
 - * also memset() the memory to all-zeroes.
 - */
 -#define OBJECT_INFO_INIT {NULL}
 -
 -/* Invoke lookup_replace_object() on the given hash */
 -#define OBJECT_INFO_LOOKUP_REPLACE 1
 -/* Allow reading from a loose object file of unknown/bogus type */
 -#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
 -/* Do not check cached storage */
 -#define OBJECT_INFO_SKIP_CACHED 4
 -/* Do not retry packed storage after checking packed and loose storage */
 -#define OBJECT_INFO_QUICK 8
 -/* Do not check loose object */
 -#define OBJECT_INFO_IGNORE_LOOSE 16
 -
 -int oid_object_info_extended(struct repository *r,
 -                           const struct object_id *,
 -                           struct object_info *, unsigned flags);
 -
  /*
   * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
   * blobs. This has a difference only if extensions.partialClone is set.
@@@ -1653,6 -1830,15 +1713,6 @@@ extern const char *excludes_file
  int decode_85(char *dst, const char *line, int linelen);
  void encode_85(char *buf, const unsigned char *data, int bytes);
  
 -/* alloc.c */
 -extern void *alloc_blob_node(void);
 -extern void *alloc_tree_node(void);
 -extern void *alloc_commit_node(void);
 -extern void *alloc_tag_node(void);
 -extern void *alloc_object_node(void);
 -extern void alloc_report(void);
 -extern unsigned int alloc_commit_index(void);
 -
  /* pkt-line.c */
  void packet_trace_identity(const char *prog);
  
diff --combined git.c
index 3fded745195a603d15da399823e060bb75fb26ef,010898ba6d15e5ed051288ee6c46bf1ed2132bd8..fc7d15d549e49113fba73ee98161fafd3fd10a56
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -267,7 -267,7 +267,7 @@@ static int handle_options(const char **
                } else if (!strcmp(cmd, "--shallow-file")) {
                        (*argv)++;
                        (*argc)--;
 -                      set_alternate_shallow_file((*argv)[0], 1);
 +                      set_alternate_shallow_file(the_repository, (*argv)[0], 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "-C")) {
@@@ -414,7 -414,10 +414,10 @@@ static int run_builtin(struct cmd_struc
  
        trace_argv_printf(argv, "trace: built-in: git");
  
+       validate_cache_entries(&the_index);
        status = p->fn(argc, argv, prefix);
+       validate_cache_entries(&the_index);
        if (status)
                return status;
  
@@@ -537,7 -540,6 +540,7 @@@ static struct cmd_struct commands[] = 
        { "shortlog", cmd_shortlog, RUN_SETUP_GENTLY | USE_PAGER },
        { "show", cmd_show, RUN_SETUP },
        { "show-branch", cmd_show_branch, RUN_SETUP },
 +      { "show-index", cmd_show_index },
        { "show-ref", cmd_show_ref, RUN_SETUP },
        { "stage", cmd_add, RUN_SETUP | NEED_WORK_TREE },
        { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
diff --combined merge-recursive.c
index 3d6b34b4f7438d2408780d73095e9a1bd0cd4338,a580cff886d5d0a30dbffeae167cfd999ce6dfee..07d792fd10c6bcee9ca12367fc2ad708fb26f9c4
@@@ -8,8 -8,6 +8,8 @@@
  #include "advice.h"
  #include "lockfile.h"
  #include "cache-tree.h"
 +#include "object-store.h"
 +#include "repository.h"
  #include "commit.h"
  #include "blob.h"
  #include "builtin.h"
@@@ -17,7 -15,6 +17,7 @@@
  #include "diff.h"
  #include "diffcore.h"
  #include "tag.h"
 +#include "alloc.h"
  #include "unpack-trees.h"
  #include "string-list.h"
  #include "xdiff-interface.h"
@@@ -158,12 -155,12 +158,12 @@@ static struct tree *shift_tree_object(s
        }
        if (!oidcmp(&two->object.oid, &shifted))
                return two;
 -      return lookup_tree(&shifted);
 +      return lookup_tree(the_repository, &shifted);
  }
  
  static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
  {
 -      struct commit *commit = alloc_commit_node();
 +      struct commit *commit = alloc_commit_node(the_repository);
  
        set_merge_remote_desc(commit, comment, (struct object *)commit);
        commit->maybe_tree = tree;
@@@ -184,7 -181,7 +184,7 @@@ static int oid_eq(const struct object_i
  
  enum rename_type {
        RENAME_NORMAL = 0,
 -      RENAME_DIR,
 +      RENAME_VIA_DIR,
        RENAME_DELETE,
        RENAME_ONE_FILE_TO_ONE,
        RENAME_ONE_FILE_TO_TWO,
@@@ -289,12 -286,10 +289,12 @@@ static void output(struct merge_option
  
  static void output_commit_title(struct merge_options *o, struct commit *commit)
  {
 +      struct merge_remote_desc *desc;
 +
        strbuf_addchars(&o->obuf, ' ', o->call_depth * 2);
 -      if (commit->util)
 -              strbuf_addf(&o->obuf, "virtual %s\n",
 -                      merge_remote_util(commit)->name);
 +      desc = merge_remote_util(commit);
 +      if (desc)
 +              strbuf_addf(&o->obuf, "virtual %s\n", desc->name);
        else {
                strbuf_add_unique_abbrev(&o->obuf, &commit->object.oid,
                                         DEFAULT_ABBREV);
  }
  
  static int add_cacheinfo(struct merge_options *o,
 -              unsigned int mode, const struct object_id *oid,
 -              const char *path, int stage, int refresh, int options)
 +                       unsigned int mode, const struct object_id *oid,
 +                       const char *path, int stage, int refresh, int options)
  {
        struct cache_entry *ce;
        int ret;
  
-       ce = make_cache_entry(mode, oid ? oid->hash : null_sha1, path, stage, 0);
+       ce = make_cache_entry(&the_index, mode, oid ? oid : &null_oid, path, stage, 0);
        if (!ce)
                return err(o, _("add_cacheinfo failed for path '%s'; merge aborting."), path);
  
        if (refresh) {
                struct cache_entry *nce;
  
-               nce = refresh_cache_entry(ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
+               nce = refresh_cache_entry(&the_index, ce, CE_MATCH_REFRESH | CE_MATCH_IGNORE_MISSING);
                if (!nce)
                        return err(o, _("add_cacheinfo failed to refresh for path '%s'; merge aborting."), path);
                if (nce != ce)
@@@ -416,14 -411,14 +416,14 @@@ struct tree *write_tree_from_memory(str
                return NULL;
        }
  
 -      result = lookup_tree(&active_cache_tree->oid);
 +      result = lookup_tree(the_repository, &active_cache_tree->oid);
  
        return result;
  }
  
  static int save_files_dirs(const struct object_id *oid,
 -              struct strbuf *base, const char *path,
 -              unsigned int mode, int stage, void *context)
 +                         struct strbuf *base, const char *path,
 +                         unsigned int mode, int stage, void *context)
  {
        struct path_hashmap_entry *entry;
        int baselen = base->len;
@@@ -544,7 -539,7 +544,7 @@@ static void record_df_conflict_files(st
                                     struct string_list *entries)
  {
        /* If there is a D/F conflict and the file for such a conflict
 -       * currently exist in the working tree, we want to allow it to be
 +       * currently exists in the working tree, we want to allow it to be
         * removed to make room for the corresponding directory if needed.
         * The files underneath the directories of such D/F conflicts will
         * be processed before the corresponding file involved in the D/F
@@@ -918,7 -913,7 +918,7 @@@ static int make_room_for_path(struct me
         */
        if (would_lose_untracked(path))
                return err(o, _("refusing to lose untracked file at '%s'"),
 -                           path);
 +                         path);
  
        /* Successful unlink is good.. */
        if (!unlink(path))
@@@ -997,16 -992,16 +997,16 @@@ static int update_file_flags(struct mer
                        unlink(path);
                        if (symlink(lnk, path))
                                ret = err(o, _("failed to symlink '%s': %s"),
 -                                      path, strerror(errno));
 +                                        path, strerror(errno));
                        free(lnk);
                } else
                        ret = err(o,
                                  _("do not know what to do with %06o %s '%s'"),
                                  mode, oid_to_hex(oid), path);
 - free_buf:
 +      free_buf:
                free(buf);
        }
 - update_index:
 +update_index:
        if (!ret && update_cache)
                if (add_cacheinfo(o, mode, oid, path, 0, update_wd,
                                  ADD_CACHE_OK_TO_ADD))
@@@ -1095,7 -1090,7 +1095,7 @@@ static int merge_3way(struct merge_opti
  }
  
  static int find_first_merges(struct object_array *result, const char *path,
 -              struct commit *a, struct commit *b)
 +                           struct commit *a, struct commit *b)
  {
        int i, j;
        struct object_array merges = OBJECT_ARRAY_INIT;
  
        /* get all revisions that merge commit a */
        xsnprintf(merged_revision, sizeof(merged_revision), "^%s",
 -                      oid_to_hex(&a->object.oid));
 +                oid_to_hex(&a->object.oid));
        init_revisions(&revs, NULL);
        rev_opts.submodule = path;
        /* FIXME: can't handle linked worktrees in submodules yet */
@@@ -1192,9 -1187,9 +1192,9 @@@ static int merge_submodule(struct merge
                return 0;
        }
  
 -      if (!(commit_base = lookup_commit_reference(base)) ||
 -          !(commit_a = lookup_commit_reference(a)) ||
 -          !(commit_b = lookup_commit_reference(b))) {
 +      if (!(commit_base = lookup_commit_reference(the_repository, base)) ||
 +          !(commit_a = lookup_commit_reference(the_repository, a)) ||
 +          !(commit_b = lookup_commit_reference(the_repository, b))) {
                output(o, 1, _("Failed to merge submodule %s (commits not present)"), path);
                return 0;
        }
                output(o, 2, _("Found a possible merge resolution for the submodule:\n"));
                print_commit((struct commit *) merges.objects[0].item);
                output(o, 2, _(
 -                      "If this is correct simply add it to the index "
 -                      "for example\n"
 -                      "by using:\n\n"
 -                      "  git update-index --cacheinfo 160000 %s \"%s\"\n\n"
 -                      "which will accept this suggestion.\n"),
 -                      oid_to_hex(&merges.objects[0].item->oid), path);
 +                     "If this is correct simply add it to the index "
 +                     "for example\n"
 +                     "by using:\n\n"
 +                     "  git update-index --cacheinfo 160000 %s \"%s\"\n\n"
 +                     "which will accept this suggestion.\n"),
 +                     oid_to_hex(&merges.objects[0].item->oid), path);
                break;
  
        default:
@@@ -1337,10 -1332,10 +1337,10 @@@ static int merge_file_1(struct merge_op
                        result->clean = (merge_status == 0);
                } else if (S_ISGITLINK(a->mode)) {
                        result->clean = merge_submodule(o, &result->oid,
 -                                                     one->path,
 -                                                     &one->oid,
 -                                                     &a->oid,
 -                                                     &b->oid);
 +                                                      one->path,
 +                                                      &one->oid,
 +                                                      &a->oid,
 +                                                      &b->oid);
                } else if (S_ISLNK(a->mode)) {
                        switch (o->recursive_variant) {
                        case MERGE_RECURSIVE_NORMAL:
@@@ -1415,17 -1410,11 +1415,17 @@@ static int merge_file_one(struct merge_
        return merge_file_1(o, &one, &a, &b, path, branch1, branch2, mfi);
  }
  
 -static int conflict_rename_dir(struct merge_options *o,
 -                             struct diff_filepair *pair,
 -                             const char *rename_branch,
 -                             const char *other_branch)
 +static int handle_rename_via_dir(struct merge_options *o,
 +                               struct diff_filepair *pair,
 +                               const char *rename_branch,
 +                               const char *other_branch)
  {
 +      /*
 +       * Handle file adds that need to be renamed due to directory rename
 +       * detection.  This differs from handle_rename_normal, because
 +       * there is no content merge to do; just move the file into the
 +       * desired final location.
 +       */
        const struct diff_filespec *dest = pair->two;
  
        if (!o->call_depth && would_lose_untracked(dest->path)) {
  }
  
  static int handle_change_delete(struct merge_options *o,
 -                               const char *path, const char *old_path,
 -                               const struct object_id *o_oid, int o_mode,
 -                               const struct object_id *changed_oid,
 -                               int changed_mode,
 -                               const char *change_branch,
 -                               const char *delete_branch,
 -                               const char *change, const char *change_past)
 +                              const char *path, const char *old_path,
 +                              const struct object_id *o_oid, int o_mode,
 +                              const struct object_id *changed_oid,
 +                              int changed_mode,
 +                              const char *change_branch,
 +                              const char *delete_branch,
 +                              const char *change, const char *change_past)
  {
        char *alt_path = NULL;
        const char *update_path = path;
                if (!ret)
                        ret = update_file(o, 0, o_oid, o_mode, update_path);
        } else {
 +              /*
 +               * Despite the four nearly duplicate messages and argument
 +               * lists below and the ugliness of the nested if-statements,
 +               * having complete messages makes the job easier for
 +               * translators.
 +               *
 +               * The slight variance among the cases is due to the fact
 +               * that:
 +               *   1) directory/file conflicts (in effect if
 +               *      !alt_path) could cause us to need to write the
 +               *      file to a different path.
 +               *   2) renames (in effect if !old_path) could mean that
 +               *      there are two names for the path that the user
 +               *      may know the file by.
 +               */
                if (!alt_path) {
                        if (!old_path) {
                                output(o, 1, _("CONFLICT (%s/delete): %s deleted in %s "
        return ret;
  }
  
 -static int conflict_rename_delete(struct merge_options *o,
 -                                 struct diff_filepair *pair,
 -                                 const char *rename_branch,
 -                                 const char *delete_branch)
 +static int handle_rename_delete(struct merge_options *o,
 +                              struct diff_filepair *pair,
 +                              const char *rename_branch,
 +                              const char *delete_branch)
  {
        const struct diff_filespec *orig = pair->one;
        const struct diff_filespec *dest = pair->two;
@@@ -1640,8 -1614,8 +1640,8 @@@ static int handle_file(struct merge_opt
        return ret;
  }
  
 -static int conflict_rename_rename_1to2(struct merge_options *o,
 -                                      struct rename_conflict_info *ci)
 +static int handle_rename_rename_1to2(struct merge_options *o,
 +                                   struct rename_conflict_info *ci)
  {
        /* One file was renamed in both branches, but to different names. */
        struct diff_filespec *one = ci->pair1->one;
        return 0;
  }
  
 -static int conflict_rename_rename_2to1(struct merge_options *o,
 -                                      struct rename_conflict_info *ci)
 +static int handle_rename_rename_2to1(struct merge_options *o,
 +                                   struct rename_conflict_info *ci)
  {
        /* Two files, a & b, were renamed to the same thing, c. */
        struct diff_filespec *a = ci->pair1->one;
@@@ -2445,7 -2419,7 +2445,7 @@@ static void apply_directory_rename_modi
         * "NOTE" in update_stages(), doing so will modify the current
         * in-memory index which will break calls to would_lose_untracked()
         * that we need to make.  Instead, we need to just make sure that
 -       * the various conflict_rename_*() functions update the index
 +       * the various handle_rename_*() functions update the index
         * explicitly rather than relying on unpack_trees() to have done it.
         */
        get_tree_entry(&tree->object.oid,
@@@ -2718,7 -2692,7 +2718,7 @@@ static int process_renames(struct merge
  
                        if (oid_eq(&src_other.oid, &null_oid) &&
                            ren1->add_turned_into_rename) {
 -                              setup_rename_conflict_info(RENAME_DIR,
 +                              setup_rename_conflict_info(RENAME_VIA_DIR,
                                                           ren1->pair,
                                                           NULL,
                                                           branch1,
@@@ -2849,12 -2823,12 +2849,12 @@@ static void initial_cleanup_rename(stru
        free(pairs);
  }
  
 -static int handle_renames(struct merge_options *o,
 -                        struct tree *common,
 -                        struct tree *head,
 -                        struct tree *merge,
 -                        struct string_list *entries,
 -                        struct rename_info *ri)
 +static int detect_and_process_renames(struct merge_options *o,
 +                                    struct tree *common,
 +                                    struct tree *head,
 +                                    struct tree *merge,
 +                                    struct string_list *entries,
 +                                    struct rename_info *ri)
  {
        struct diff_queue_struct *head_pairs, *merge_pairs;
        struct hashmap *dir_re_head, *dir_re_merge;
@@@ -2930,8 -2904,7 +2930,8 @@@ static struct object_id *stage_oid(cons
  }
  
  static int read_oid_strbuf(struct merge_options *o,
 -      const struct object_id *oid, struct strbuf *dst)
 +                         const struct object_id *oid,
 +                         struct strbuf *dst)
  {
        void *buf;
        enum object_type type;
@@@ -2984,10 -2957,10 +2984,10 @@@ error_return
  }
  
  static int handle_modify_delete(struct merge_options *o,
 -                               const char *path,
 -                               struct object_id *o_oid, int o_mode,
 -                               struct object_id *a_oid, int a_mode,
 -                               struct object_id *b_oid, int b_mode)
 +                              const char *path,
 +                              struct object_id *o_oid, int o_mode,
 +                              struct object_id *a_oid, int a_mode,
 +                              struct object_id *b_oid, int b_mode)
  {
        const char *modify_branch, *delete_branch;
        struct object_id *changed_oid;
@@@ -3125,12 -3098,12 +3125,12 @@@ static int merge_content(struct merge_o
        return !is_dirty && mfi.clean;
  }
  
 -static int conflict_rename_normal(struct merge_options *o,
 -                                const char *path,
 -                                struct object_id *o_oid, unsigned int o_mode,
 -                                struct object_id *a_oid, unsigned int a_mode,
 -                                struct object_id *b_oid, unsigned int b_mode,
 -                                struct rename_conflict_info *ci)
 +static int handle_rename_normal(struct merge_options *o,
 +                              const char *path,
 +                              struct object_id *o_oid, unsigned int o_mode,
 +                              struct object_id *a_oid, unsigned int a_mode,
 +                              struct object_id *b_oid, unsigned int b_mode,
 +                              struct rename_conflict_info *ci)
  {
        /* Merge the content and write it out */
        return merge_content(o, path, was_dirty(o, path),
@@@ -3157,37 -3130,37 +3157,37 @@@ static int process_entry(struct merge_o
                switch (conflict_info->rename_type) {
                case RENAME_NORMAL:
                case RENAME_ONE_FILE_TO_ONE:
 -                      clean_merge = conflict_rename_normal(o,
 -                                                           path,
 -                                                           o_oid, o_mode,
 -                                                           a_oid, a_mode,
 -                                                           b_oid, b_mode,
 -                                                           conflict_info);
 +                      clean_merge = handle_rename_normal(o,
 +                                                         path,
 +                                                         o_oid, o_mode,
 +                                                         a_oid, a_mode,
 +                                                         b_oid, b_mode,
 +                                                         conflict_info);
                        break;
 -              case RENAME_DIR:
 +              case RENAME_VIA_DIR:
                        clean_merge = 1;
 -                      if (conflict_rename_dir(o,
 -                                              conflict_info->pair1,
 -                                              conflict_info->branch1,
 -                                              conflict_info->branch2))
 +                      if (handle_rename_via_dir(o,
 +                                                conflict_info->pair1,
 +                                                conflict_info->branch1,
 +                                                conflict_info->branch2))
                                clean_merge = -1;
                        break;
                case RENAME_DELETE:
                        clean_merge = 0;
 -                      if (conflict_rename_delete(o,
 -                                                 conflict_info->pair1,
 -                                                 conflict_info->branch1,
 -                                                 conflict_info->branch2))
 +                      if (handle_rename_delete(o,
 +                                               conflict_info->pair1,
 +                                               conflict_info->branch1,
 +                                               conflict_info->branch2))
                                clean_merge = -1;
                        break;
                case RENAME_ONE_FILE_TO_TWO:
                        clean_merge = 0;
 -                      if (conflict_rename_rename_1to2(o, conflict_info))
 +                      if (handle_rename_rename_1to2(o, conflict_info))
                                clean_merge = -1;
                        break;
                case RENAME_TWO_FILES_TO_ONE:
                        clean_merge = 0;
 -                      if (conflict_rename_rename_2to1(o, conflict_info))
 +                      if (handle_rename_rename_2to1(o, conflict_info))
                                clean_merge = -1;
                        break;
                default:
@@@ -3327,8 -3300,8 +3327,8 @@@ int merge_trees(struct merge_options *o
                get_files_dirs(o, merge);
  
                entries = get_unmerged();
 -              clean = handle_renames(o, common, head, merge, entries,
 -                                     &re_info);
 +              clean = detect_and_process_renames(o, common, head, merge,
 +                                                 entries, &re_info);
                record_df_conflict_files(o, entries);
                if (clean < 0)
                        goto cleanup;
                                    entries->items[i].string);
                }
  
 -cleanup:
 +      cleanup:
                final_cleanup_renames(&re_info);
  
                string_list_clear(entries, 1);
@@@ -3427,7 -3400,7 +3427,7 @@@ int merge_recursive(struct merge_option
                /* if there is no common ancestor, use an empty tree */
                struct tree *tree;
  
 -              tree = lookup_tree(the_hash_algo->empty_tree);
 +              tree = lookup_tree(the_repository, the_repository->hash_algo->empty_tree);
                merged_common_ancestors = make_virtual_commit(tree, "ancestor");
        }
  
@@@ -3489,9 -3462,7 +3489,9 @@@ static struct commit *get_ref(const str
  {
        struct object *object;
  
 -      object = deref_tag(parse_object(oid), name, strlen(name));
 +      object = deref_tag(the_repository, parse_object(the_repository, oid),
 +                         name,
 +                         strlen(name));
        if (!object)
                return NULL;
        if (object->type == OBJ_TREE)
@@@ -3522,14 -3493,14 +3522,14 @@@ int merge_recursive_generic(struct merg
                        struct commit *base;
                        if (!(base = get_ref(base_list[i], oid_to_hex(base_list[i]))))
                                return err(o, _("Could not parse object '%s'"),
 -                                      oid_to_hex(base_list[i]));
 +                                         oid_to_hex(base_list[i]));
                        commit_list_insert(base, &ca);
                }
        }
  
        hold_locked_index(&lock, LOCK_DIE_ON_ERROR);
        clean = merge_recursive(o, head_commit, next_commit, ca,
 -                      result);
 +                              result);
        if (clean < 0) {
                rollback_lock_file(&lock);
                return clean;
diff --combined read-cache.c
index e865254bea028485e1731d316727b66753a8fc5e,fd67e2e8a48b4f28d923b4ba7354b02f203d8d7f..56eac508362f272e5d777c98b7f31c0f043c1d89
@@@ -11,7 -11,6 +11,7 @@@
  #include "cache-tree.h"
  #include "refs.h"
  #include "dir.h"
 +#include "object-store.h"
  #include "tree.h"
  #include "commit.h"
  #include "blob.h"
                 CE_ENTRY_ADDED | CE_ENTRY_REMOVED | CE_ENTRY_CHANGED | \
                 SPLIT_INDEX_ORDERED | UNTRACKED_CHANGED | FSMONITOR_CHANGED)
  
+ /*
+  * This is an estimate of the pathname length in the index.  We use
+  * this for V4 index files to guess the un-deltafied size of the index
+  * in memory because of pathname deltafication.  This is not required
+  * for V2/V3 index formats because their pathnames are not compressed.
+  * If the initial amount of memory set aside is not sufficient, the
+  * mem pool will allocate extra memory.
+  */
+ #define CACHE_ENTRY_PATH_LENGTH 80
+ static inline struct cache_entry *mem_pool__ce_alloc(struct mem_pool *mem_pool, size_t len)
+ {
+       struct cache_entry *ce;
+       ce = mem_pool_alloc(mem_pool, cache_entry_size(len));
+       ce->mem_pool_allocated = 1;
+       return ce;
+ }
+ static inline struct cache_entry *mem_pool__ce_calloc(struct mem_pool *mem_pool, size_t len)
+ {
+       struct cache_entry * ce;
+       ce = mem_pool_calloc(mem_pool, 1, cache_entry_size(len));
+       ce->mem_pool_allocated = 1;
+       return ce;
+ }
+ static struct mem_pool *find_mem_pool(struct index_state *istate)
+ {
+       struct mem_pool **pool_ptr;
+       if (istate->split_index && istate->split_index->base)
+               pool_ptr = &istate->split_index->base->ce_mem_pool;
+       else
+               pool_ptr = &istate->ce_mem_pool;
+       if (!*pool_ptr)
+               mem_pool_init(pool_ptr, 0);
+       return *pool_ptr;
+ }
  struct index_state the_index;
  static const char *alternate_index_output;
  
@@@ -62,7 -103,7 +104,7 @@@ static void replace_index_entry(struct 
  
        replace_index_entry_in_base(istate, old, ce);
        remove_name_hash(istate, old);
-       free(old);
+       discard_cache_entry(old);
        ce->ce_flags &= ~CE_HASHED;
        set_index_entry(istate, nr, ce);
        ce->ce_flags |= CE_UPDATE_IN_BASE;
@@@ -75,7 -116,7 +117,7 @@@ void rename_index_entry_at(struct index
        struct cache_entry *old_entry = istate->cache[nr], *new_entry;
        int namelen = strlen(new_name);
  
-       new_entry = xmalloc(cache_entry_size(namelen));
+       new_entry = make_empty_cache_entry(istate, namelen);
        copy_cache_entry(new_entry, old_entry);
        new_entry->ce_flags &= ~CE_HASHED;
        new_entry->ce_namelen = namelen;
@@@ -624,7 -665,7 +666,7 @@@ static struct cache_entry *create_alias
  
        /* Ok, create the new entry using the name of the existing alias */
        len = ce_namelen(alias);
-       new_entry = xcalloc(1, cache_entry_size(len));
+       new_entry = make_empty_cache_entry(istate, len);
        memcpy(new_entry->name, alias->name, len);
        copy_cache_entry(new_entry, ce);
        save_or_free_index_entry(istate, ce);
@@@ -641,7 -682,7 +683,7 @@@ void set_object_name_for_intent_to_add_
  
  int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
  {
-       int size, namelen, was_same;
+       int namelen, was_same;
        mode_t st_mode = st->st_mode;
        struct cache_entry *ce, *alias = NULL;
        unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY;
                while (namelen && path[namelen-1] == '/')
                        namelen--;
        }
-       size = cache_entry_size(namelen);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(istate, namelen);
        memcpy(ce->name, path, namelen);
        ce->ce_namelen = namelen;
        if (!intent_only)
                                ce_mark_uptodate(alias);
                        alias->ce_flags |= CE_ADDED;
  
-                       free(ce);
+                       discard_cache_entry(ce);
                        return 0;
                }
        }
        if (!intent_only) {
                if (index_path(&ce->oid, path, st, newflags)) {
-                       free(ce);
+                       discard_cache_entry(ce);
                        return error("unable to index file %s", path);
                }
        } else
                    ce->ce_mode == alias->ce_mode);
  
        if (pretend)
-               free(ce);
+               discard_cache_entry(ce);
        else if (add_index_entry(istate, ce, add_option)) {
-               free(ce);
+               discard_cache_entry(ce);
                return error("unable to add %s to index", path);
        }
        if (verbose && !was_same)
@@@ -746,12 -786,25 +787,25 @@@ int add_file_to_index(struct index_stat
        return add_to_index(istate, path, &st, flags);
  }
  
- struct cache_entry *make_cache_entry(unsigned int mode,
-               const unsigned char *sha1, const char *path, int stage,
-               unsigned int refresh_options)
+ struct cache_entry *make_empty_cache_entry(struct index_state *istate, size_t len)
+ {
+       return mem_pool__ce_calloc(find_mem_pool(istate), len);
+ }
+ struct cache_entry *make_empty_transient_cache_entry(size_t len)
+ {
+       return xcalloc(1, cache_entry_size(len));
+ }
+ struct cache_entry *make_cache_entry(struct index_state *istate,
+                                    unsigned int mode,
+                                    const struct object_id *oid,
+                                    const char *path,
+                                    int stage,
+                                    unsigned int refresh_options)
  {
-       int size, len;
        struct cache_entry *ce, *ret;
+       int len;
  
        if (!verify_path(path, mode)) {
                error("Invalid path '%s'", path);
        }
  
        len = strlen(path);
-       size = cache_entry_size(len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(istate, len);
  
-       hashcpy(ce->oid.hash, sha1);
+       oidcpy(&ce->oid, oid);
        memcpy(ce->name, path, len);
        ce->ce_flags = create_ce_flags(stage);
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
  
-       ret = refresh_cache_entry(ce, refresh_options);
+       ret = refresh_cache_entry(&the_index, ce, refresh_options);
        if (ret != ce)
-               free(ce);
+               discard_cache_entry(ce);
        return ret;
  }
  
+ struct cache_entry *make_transient_cache_entry(unsigned int mode, const struct object_id *oid,
+                                              const char *path, int stage)
+ {
+       struct cache_entry *ce;
+       int len;
+       if (!verify_path(path, mode)) {
+               error("Invalid path '%s'", path);
+               return NULL;
+       }
+       len = strlen(path);
+       ce = make_empty_transient_cache_entry(len);
+       oidcpy(&ce->oid, oid);
+       memcpy(ce->name, path, len);
+       ce->ce_flags = create_ce_flags(stage);
+       ce->ce_namelen = len;
+       ce->ce_mode = create_ce_mode(mode);
+       return ce;
+ }
  /*
   * Chmod an index entry with either +x or -x.
   *
@@@ -1269,7 -1344,7 +1345,7 @@@ static struct cache_entry *refresh_cach
  {
        struct stat st;
        struct cache_entry *updated;
-       int changed, size;
+       int changed;
        int refresh = options & CE_MATCH_REFRESH;
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
        int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
                return NULL;
        }
  
-       size = ce_size(ce);
-       updated = xmalloc(size);
+       updated = make_empty_cache_entry(istate, ce_namelen(ce));
        copy_cache_entry(updated, ce);
        memcpy(updated->name, ce->name, ce->ce_namelen + 1);
        fill_stat_cache_info(updated, &st);
@@@ -1474,10 -1548,11 +1549,11 @@@ int refresh_index(struct index_state *i
        return has_errors;
  }
  
- struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
-                                              unsigned int options)
+ struct cache_entry *refresh_cache_entry(struct index_state *istate,
+                                       struct cache_entry *ce,
+                                       unsigned int options)
  {
-       return refresh_cache_ent(&the_index, ce, options, NULL, NULL);
+       return refresh_cache_ent(istate, ce, options, NULL, NULL);
  }
  
  
@@@ -1635,12 -1710,13 +1711,13 @@@ int read_index(struct index_state *ista
        return read_index_from(istate, get_index_file(), get_git_dir());
  }
  
- static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
+ static struct cache_entry *cache_entry_from_ondisk(struct mem_pool *mem_pool,
+                                                  struct ondisk_cache_entry *ondisk,
                                                   unsigned int flags,
                                                   const char *name,
                                                   size_t len)
  {
-       struct cache_entry *ce = xmalloc(cache_entry_size(len));
+       struct cache_entry *ce = mem_pool__ce_alloc(mem_pool, len);
  
        ce->ce_stat_data.sd_ctime.sec = get_be32(&ondisk->ctime.sec);
        ce->ce_stat_data.sd_mtime.sec = get_be32(&ondisk->mtime.sec);
@@@ -1682,7 -1758,8 +1759,8 @@@ static unsigned long expand_name_field(
        return (const char *)ep + 1 - cp_;
  }
  
- static struct cache_entry *create_from_disk(struct ondisk_cache_entry *ondisk,
+ static struct cache_entry *create_from_disk(struct mem_pool *mem_pool,
+                                           struct ondisk_cache_entry *ondisk,
                                            unsigned long *ent_size,
                                            struct strbuf *previous_name)
  {
                /* v3 and earlier */
                if (len == CE_NAMEMASK)
                        len = strlen(name);
-               ce = cache_entry_from_ondisk(ondisk, flags, name, len);
+               ce = cache_entry_from_ondisk(mem_pool, ondisk, flags, name, len);
  
                *ent_size = ondisk_ce_size(ce);
        } else {
                unsigned long consumed;
                consumed = expand_name_field(previous_name, name);
-               ce = cache_entry_from_ondisk(ondisk, flags,
+               ce = cache_entry_from_ondisk(mem_pool, ondisk, flags,
                                             previous_name->buf,
                                             previous_name->len);
  
@@@ -1793,6 -1870,22 +1871,22 @@@ static void post_read_index_from(struc
        tweak_fsmonitor(istate);
  }
  
+ static size_t estimate_cache_size_from_compressed(unsigned int entries)
+ {
+       return entries * (sizeof(struct cache_entry) + CACHE_ENTRY_PATH_LENGTH);
+ }
+ static size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
+ {
+       long per_entry = sizeof(struct cache_entry) - sizeof(struct ondisk_cache_entry);
+       /*
+        * Account for potential alignment differences.
+        */
+       per_entry += align_padding_size(sizeof(struct cache_entry), -sizeof(struct ondisk_cache_entry));
+       return ondisk_size + entries * per_entry;
+ }
  /* remember to discard_cache() before reading a different cache! */
  int do_read_index(struct index_state *istate, const char *path, int must_exist)
  {
        istate->cache = xcalloc(istate->cache_alloc, sizeof(*istate->cache));
        istate->initialized = 1;
  
-       if (istate->version == 4)
+       if (istate->version == 4) {
                previous_name = &previous_name_buf;
-       else
+               mem_pool_init(&istate->ce_mem_pool,
+                             estimate_cache_size_from_compressed(istate->cache_nr));
+       } else {
                previous_name = NULL;
+               mem_pool_init(&istate->ce_mem_pool,
+                             estimate_cache_size(mmap_size, istate->cache_nr));
+       }
  
        src_offset = sizeof(*hdr);
        for (i = 0; i < istate->cache_nr; i++) {
                unsigned long consumed;
  
                disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset);
-               ce = create_from_disk(disk_ce, &consumed, previous_name);
+               ce = create_from_disk(istate->ce_mem_pool, disk_ce, &consumed, previous_name);
                set_index_entry(istate, i, ce);
  
                src_offset += consumed;
@@@ -1948,17 -2046,15 +2047,15 @@@ int is_index_unborn(struct index_state 
  
  int discard_index(struct index_state *istate)
  {
-       int i;
+       /*
+        * Cache entries in istate->cache[] should have been allocated
+        * from the memory pool associated with this index, or from an
+        * associated split_index. There is no need to free individual
+        * cache entries. validate_cache_entries can detect when this
+        * assertion does not hold.
+        */
+       validate_cache_entries(istate);
  
-       for (i = 0; i < istate->cache_nr; i++) {
-               if (istate->cache[i]->index &&
-                   istate->split_index &&
-                   istate->split_index->base &&
-                   istate->cache[i]->index <= istate->split_index->base->cache_nr &&
-                   istate->cache[i] == istate->split_index->base->cache[istate->cache[i]->index - 1])
-                       continue;
-               free(istate->cache[i]);
-       }
        resolve_undo_clear_index(istate);
        istate->cache_nr = 0;
        istate->cache_changed = 0;
        discard_split_index(istate);
        free_untracked_cache(istate->untracked);
        istate->untracked = NULL;
+       if (istate->ce_mem_pool) {
+               mem_pool_discard(istate->ce_mem_pool, should_validate_cache_entries());
+               istate->ce_mem_pool = NULL;
+       }
        return 0;
  }
  
+ /*
+  * Validate the cache entries of this index.
+  * All cache entries associated with this index
+  * should have been allocated by the memory pool
+  * associated with this index, or by a referenced
+  * split index.
+  */
+ void validate_cache_entries(const struct index_state *istate)
+ {
+       int i;
+       if (!should_validate_cache_entries() ||!istate || !istate->initialized)
+               return;
+       for (i = 0; i < istate->cache_nr; i++) {
+               if (!istate) {
+                       die("internal error: cache entry is not allocated from expected memory pool");
+               } else if (!istate->ce_mem_pool ||
+                       !mem_pool_contains(istate->ce_mem_pool, istate->cache[i])) {
+                       if (!istate->split_index ||
+                               !istate->split_index->base ||
+                               !istate->split_index->base->ce_mem_pool ||
+                               !mem_pool_contains(istate->split_index->base->ce_mem_pool, istate->cache[i])) {
+                               die("internal error: cache entry is not allocated from expected memory pool");
+                       }
+               }
+       }
+       if (istate->split_index)
+               validate_cache_entries(istate->split_index->base);
+ }
  int unmerged_index(const struct index_state *istate)
  {
        int i;
@@@ -2647,14 -2781,13 +2782,13 @@@ int read_index_unmerged(struct index_st
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i];
                struct cache_entry *new_ce;
-               int size, len;
+               int len;
  
                if (!ce_stage(ce))
                        continue;
                unmerged = 1;
                len = ce_namelen(ce);
-               size = cache_entry_size(len);
-               new_ce = xcalloc(1, size);
+               new_ce = make_empty_cache_entry(istate, len);
                memcpy(new_ce->name, ce->name, len);
                new_ce->ce_flags = create_ce_flags(0) | CE_CONFLICTED;
                new_ce->ce_namelen = len;
@@@ -2763,3 -2896,41 +2897,41 @@@ void move_index_extensions(struct index
        dst->untracked = src->untracked;
        src->untracked = NULL;
  }
+ struct cache_entry *dup_cache_entry(const struct cache_entry *ce,
+                                   struct index_state *istate)
+ {
+       unsigned int size = ce_size(ce);
+       int mem_pool_allocated;
+       struct cache_entry *new_entry = make_empty_cache_entry(istate, ce_namelen(ce));
+       mem_pool_allocated = new_entry->mem_pool_allocated;
+       memcpy(new_entry, ce, size);
+       new_entry->mem_pool_allocated = mem_pool_allocated;
+       return new_entry;
+ }
+ void discard_cache_entry(struct cache_entry *ce)
+ {
+       if (ce && should_validate_cache_entries())
+               memset(ce, 0xCD, cache_entry_size(ce->ce_namelen));
+       if (ce && ce->mem_pool_allocated)
+               return;
+       free(ce);
+ }
+ int should_validate_cache_entries(void)
+ {
+       static int validate_index_cache_entries = -1;
+       if (validate_index_cache_entries < 0) {
+               if (getenv("GIT_TEST_VALIDATE_INDEX_CACHE_ENTRIES"))
+                       validate_index_cache_entries = 1;
+               else
+                       validate_index_cache_entries = 0;
+       }
+       return validate_index_cache_entries;
+ }
diff --combined tree.c
index 78d440a9c8f9367d65f074cfca98055bb9b30e95,5111ce8376c54f4cb323bc527185e209f0a6739d..215d3fdc7c4af2ef2faca1cf5d5d0b5de52b84a8
--- 1/tree.c
--- 2/tree.c
+++ b/tree.c
@@@ -2,13 -2,10 +2,13 @@@
  #include "cache.h"
  #include "cache-tree.h"
  #include "tree.h"
 +#include "object-store.h"
  #include "blob.h"
  #include "commit.h"
  #include "tag.h"
 +#include "alloc.h"
  #include "tree-walk.h"
 +#include "repository.h"
  
  const char *tree_type = "tree";
  
@@@ -19,15 -16,13 +19,13 @@@ static int read_one_entry_opt(struct in
                              unsigned mode, int stage, int opt)
  {
        int len;
-       unsigned int size;
        struct cache_entry *ce;
  
        if (S_ISDIR(mode))
                return READ_TREE_RECURSIVE;
  
        len = strlen(pathname);
-       size = cache_entry_size(baselen + len);
-       ce = xcalloc(1, size);
+       ce = make_empty_cache_entry(istate, baselen + len);
  
        ce->ce_mode = create_ce_mode(mode);
        ce->ce_flags = create_ce_flags(stage);
@@@ -101,7 -96,7 +99,7 @@@ static int read_tree_1(struct tree *tre
                else if (S_ISGITLINK(entry.mode)) {
                        struct commit *commit;
  
 -                      commit = lookup_commit(entry.oid);
 +                      commit = lookup_commit(the_repository, entry.oid);
                        if (!commit)
                                die("Commit %s in submodule path %s%s not found",
                                    oid_to_hex(entry.oid),
                len = tree_entry_len(&entry);
                strbuf_add(base, entry.path, len);
                strbuf_addch(base, '/');
 -              retval = read_tree_1(lookup_tree(&oid),
 +              retval = read_tree_1(lookup_tree(the_repository, &oid),
                                     base, stage, pathspec,
                                     fn, context);
                strbuf_setlen(base, oldlen);
@@@ -195,13 -190,12 +193,13 @@@ int read_tree(struct tree *tree, int st
        return 0;
  }
  
 -struct tree *lookup_tree(const struct object_id *oid)
 +struct tree *lookup_tree(struct repository *r, const struct object_id *oid)
  {
 -      struct object *obj = lookup_object(oid->hash);
 +      struct object *obj = lookup_object(r, oid->hash);
        if (!obj)
 -              return create_object(oid->hash, alloc_tree_node());
 -      return object_as_type(obj, OBJ_TREE, 0);
 +              return create_object(r, oid->hash,
 +                                   alloc_tree_node(r));
 +      return object_as_type(r, obj, OBJ_TREE, 0);
  }
  
  int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
@@@ -245,7 -239,7 +243,7 @@@ void free_tree_buffer(struct tree *tree
  
  struct tree *parse_tree_indirect(const struct object_id *oid)
  {
 -      struct object *obj = parse_object(oid);
 +      struct object *obj = parse_object(the_repository, oid);
        do {
                if (!obj)
                        return NULL;
                else
                        return NULL;
                if (!obj->parsed)
 -                      parse_object(&obj->oid);
 +                      parse_object(the_repository, &obj->oid);
        } while (1);
  }
diff --combined unpack-trees.c
index cd0680f11e3580ef24e9140dd00a1e38f02557d8,a3b513173218ae53d11961dfc25fc9f62f1643ee..f9efee0836a20e7072477ae0f3de7c9e1a29ff78
@@@ -16,7 -16,6 +16,7 @@@
  #include "submodule.h"
  #include "submodule-config.h"
  #include "fsmonitor.h"
 +#include "object-store.h"
  #include "fetch-object.h"
  
  /*
@@@ -204,20 -203,11 +204,11 @@@ static int do_add_entry(struct unpack_t
                               ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
  }
  
- static struct cache_entry *dup_entry(const struct cache_entry *ce)
- {
-       unsigned int size = ce_size(ce);
-       struct cache_entry *new_entry = xmalloc(size);
-       memcpy(new_entry, ce, size);
-       return new_entry;
- }
  static void add_entry(struct unpack_trees_options *o,
                      const struct cache_entry *ce,
                      unsigned int set, unsigned int clear)
  {
-       do_add_entry(o, dup_entry(ce), set, clear);
+       do_add_entry(o, dup_cache_entry(ce, &o->result), set, clear);
  }
  
  /*
@@@ -798,10 -788,17 +789,17 @@@ static int ce_in_traverse_path(const st
        return (info->pathlen < ce_namelen(ce));
  }
  
- static struct cache_entry *create_ce_entry(const struct traverse_info *info, const struct name_entry *n, int stage)
+ static struct cache_entry *create_ce_entry(const struct traverse_info *info,
+       const struct name_entry *n,
+       int stage,
+       struct index_state *istate,
+       int is_transient)
  {
        int len = traverse_path_len(info, n);
-       struct cache_entry *ce = xcalloc(1, cache_entry_size(len));
+       struct cache_entry *ce =
+               is_transient ?
+               make_empty_transient_cache_entry(len) :
+               make_empty_cache_entry(istate, len);
  
        ce->ce_mode = create_ce_mode(n->mode);
        ce->ce_flags = create_ce_flags(stage);
@@@ -847,7 -844,15 +845,15 @@@ static int unpack_nondirectories(int n
                        stage = 3;
                else
                        stage = 2;
-               src[i + o->merge] = create_ce_entry(info, names + i, stage);
+               /*
+                * If the merge bit is set, then the cache entries are
+                * discarded in the following block.  In this case,
+                * construct "transient" cache_entries, as they are
+                * not stored in the index.  otherwise construct the
+                * cache entry from the index aware logic.
+                */
+               src[i + o->merge] = create_ce_entry(info, names + i, stage, &o->result, o->merge);
        }
  
        if (o->merge) {
                for (i = 0; i < n; i++) {
                        struct cache_entry *ce = src[i + o->merge];
                        if (ce != o->df_conflict_entry)
-                               free(ce);
+                               discard_cache_entry(ce);
                }
                return rc;
        }
@@@ -1247,7 -1252,7 +1253,7 @@@ static void mark_new_skip_worktree(stru
                if (select_flag && !(ce->ce_flags & select_flag))
                        continue;
  
 -              if (!ce_stage(ce))
 +              if (!ce_stage(ce) && !(ce->ce_flags & CE_CONFLICTED))
                        ce->ce_flags |= skip_wt_flag;
                else
                        ce->ce_flags &= ~skip_wt_flag;
@@@ -1788,7 -1793,7 +1794,7 @@@ static int merged_entry(const struct ca
                        struct unpack_trees_options *o)
  {
        int update = CE_UPDATE;
-       struct cache_entry *merge = dup_entry(ce);
+       struct cache_entry *merge = dup_cache_entry(ce, &o->result);
  
        if (!old) {
                /*
  
                if (verify_absent(merge,
                                  ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) {
-                       free(merge);
+                       discard_cache_entry(merge);
                        return -1;
                }
                invalidate_ce_path(merge, o);
                        update = 0;
                } else {
                        if (verify_uptodate(old, o)) {
-                               free(merge);
+                               discard_cache_entry(merge);
                                return -1;
                        }
                        /* Migrate old flags over */