]> git.ipfire.org Git - thirdparty/git.git/blobdiff - read-cache.c
Merge branch 'jt/t5500-unflake'
[thirdparty/git.git] / read-cache.c
index a07bd95eb8df771bbb4ecc26fa41ac0e8eb606dd..aa427c5c170f02c0c2300f4de5e16a03c83dd975 100644 (file)
@@ -3,7 +3,6 @@
  *
  * Copyright (C) Linus Torvalds, 2005
  */
-#define NO_THE_INDEX_COMPATIBILITY_MACROS
 #include "cache.h"
 #include "config.h"
 #include "diff.h"
 #include "commit.h"
 #include "blob.h"
 #include "resolve-undo.h"
+#include "run-command.h"
 #include "strbuf.h"
 #include "varint.h"
 #include "split-index.h"
 #include "utf8.h"
 #include "fsmonitor.h"
+#include "thread-utils.h"
+#include "progress.h"
 
 /* Mask for the name length in ce_flags in the on-disk index */
 
@@ -43,6 +45,8 @@
 #define CACHE_EXT_LINK 0x6c696e6b        /* "link" */
 #define CACHE_EXT_UNTRACKED 0x554E5452   /* "UNTR" */
 #define CACHE_EXT_FSMONITOR 0x46534D4E   /* "FSMN" */
+#define CACHE_EXT_ENDOFINDEXENTRIES 0x454F4945 /* "EOIE" */
+#define CACHE_EXT_INDEXENTRYOFFSETTABLE 0x49454F54 /* "IEOT" */
 
 /* changes that can be kept in $GIT_DIR/index (basically all extensions) */
 #define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
@@ -91,7 +95,6 @@ static struct mem_pool *find_mem_pool(struct index_state *istate)
        return *pool_ptr;
 }
 
-struct index_state the_index;
 static const char *alternate_index_output;
 
 static void set_index_entry(struct index_state *istate, int nr, struct cache_entry *ce)
@@ -192,7 +195,7 @@ int match_stat_data(const struct stat_data *sd, struct stat *st)
  * cache, ie the parts that aren't tracked by GIT, and only used
  * to validate the cache.
  */
-void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
+void fill_stat_cache_info(struct index_state *istate, struct cache_entry *ce, struct stat *st)
 {
        fill_stat_data(&ce->ce_stat_data, st);
 
@@ -201,19 +204,21 @@ void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
 
        if (S_ISREG(st->st_mode)) {
                ce_mark_uptodate(ce);
-               mark_fsmonitor_valid(ce);
+               mark_fsmonitor_valid(istate, ce);
        }
 }
 
-static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
+static int ce_compare_data(struct index_state *istate,
+                          const struct cache_entry *ce,
+                          struct stat *st)
 {
        int match = -1;
        int fd = git_open_cloexec(ce->name, O_RDONLY);
 
        if (fd >= 0) {
                struct object_id oid;
-               if (!index_fd(&oid, fd, st, OBJ_BLOB, ce->name, 0))
-                       match = oidcmp(&oid, &ce->oid);
+               if (!index_fd(istate, &oid, fd, st, OBJ_BLOB, ce->name, 0))
+                       match = !oideq(&oid, &ce->oid);
                /* index_fd() closed the file descriptor already */
        }
        return match;
@@ -254,14 +259,16 @@ static int ce_compare_gitlink(const struct cache_entry *ce)
         */
        if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0)
                return 0;
-       return oidcmp(&oid, &ce->oid);
+       return !oideq(&oid, &ce->oid);
 }
 
-static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st)
+static int ce_modified_check_fs(struct index_state *istate,
+                               const struct cache_entry *ce,
+                               struct stat *st)
 {
        switch (st->st_mode & S_IFMT) {
        case S_IFREG:
-               if (ce_compare_data(ce, st))
+               if (ce_compare_data(istate, ce, st))
                        return DATA_CHANGED;
                break;
        case S_IFLNK:
@@ -308,7 +315,7 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st)
                        changed |= DATA_CHANGED;
                return changed;
        default:
-               die("internal error: ce_mode is %o", ce->ce_mode);
+               BUG("unsupported ce_mode: %o", ce->ce_mode);
        }
 
        changed |= match_stat_data(&ce->ce_stat_data, st);
@@ -407,7 +414,7 @@ int ie_match_stat(struct index_state *istate,
                if (assume_racy_is_modified)
                        changed |= DATA_CHANGED;
                else
-                       changed |= ce_modified_check_fs(ce, st);
+                       changed |= ce_modified_check_fs(istate, ce, st);
        }
 
        return changed;
@@ -447,7 +454,7 @@ int ie_modified(struct index_state *istate,
            (S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0))
                return changed;
 
-       changed_fs = ce_modified_check_fs(ce, st);
+       changed_fs = ce_modified_check_fs(istate, ce, st);
        if (changed_fs)
                return changed | changed_fs;
        return 0;
@@ -542,7 +549,7 @@ static int index_name_stage_pos(const struct index_state *istate, const char *na
        first = 0;
        last = istate->cache_nr;
        while (last > first) {
-               int next = (last + first) >> 1;
+               int next = first + ((last - first) >> 1);
                struct cache_entry *ce = istate->cache[next];
                int cmp = cache_name_stage_compare(name, namelen, stage, ce->name, ce_namelen(ce), ce_stage(ce));
                if (!cmp)
@@ -582,13 +589,19 @@ int remove_index_entry_at(struct index_state *istate, int pos)
  * CE_REMOVE is set in ce_flags.  This is much more effective than
  * calling remove_index_entry_at() for each entry to be removed.
  */
-void remove_marked_cache_entries(struct index_state *istate)
+void remove_marked_cache_entries(struct index_state *istate, int invalidate)
 {
        struct cache_entry **ce_array = istate->cache;
        unsigned int i, j;
 
        for (i = j = 0; i < istate->cache_nr; i++) {
                if (ce_array[i]->ce_flags & CE_REMOVE) {
+                       if (invalidate) {
+                               cache_tree_invalidate_path(istate,
+                                                          ce_array[i]->name);
+                               untracked_cache_remove_from_index(istate,
+                                                                 ce_array[i]->name);
+                       }
                        remove_name_hash(istate, ce_array[i]);
                        save_or_free_index_entry(istate, ce_array[i]);
                }
@@ -664,7 +677,8 @@ static struct cache_entry *create_alias_ce(struct index_state *istate,
        struct cache_entry *new_entry;
 
        if (alias->ce_flags & CE_ADDED)
-               die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name);
+               die(_("will not add file alias '%s' ('%s' already exists in index)"),
+                   ce->name, alias->name);
 
        /* Ok, create the new entry using the name of the existing alias */
        len = ce_namelen(alias);
@@ -679,7 +693,7 @@ void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
 {
        struct object_id oid;
        if (write_object_file("", 0, blob_type, &oid))
-               die("cannot create an empty blob in the object database");
+               die(_("cannot create an empty blob in the object database"));
        oidcpy(&ce->oid, &oid);
 }
 
@@ -694,16 +708,19 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        int intent_only = flags & ADD_CACHE_INTENT;
        int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
                          (intent_only ? ADD_CACHE_NEW_ONLY : 0));
-       int newflags = HASH_WRITE_OBJECT;
+       int hash_flags = HASH_WRITE_OBJECT;
+       struct object_id oid;
 
-       if (flags & HASH_RENORMALIZE)
-               newflags |= HASH_RENORMALIZE;
+       if (flags & ADD_CACHE_RENORMALIZE)
+               hash_flags |= HASH_RENORMALIZE;
 
        if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
-               return error("%s: can only add regular files, symbolic links or git-directories", path);
+               return error(_("%s: can only add regular files, symbolic links or git-directories"), path);
 
        namelen = strlen(path);
        if (S_ISDIR(st_mode)) {
+               if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
+                       return error(_("'%s' does not have a commit checked out"), path);
                while (namelen && path[namelen-1] == '/')
                        namelen--;
        }
@@ -711,7 +728,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        memcpy(ce->name, path, namelen);
        ce->ce_namelen = namelen;
        if (!intent_only)
-               fill_stat_cache_info(ce, st);
+               fill_stat_cache_info(istate, ce, st);
        else
                ce->ce_flags |= CE_INTENT_TO_ADD;
 
@@ -737,7 +754,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        if (ignore_case) {
                adjust_dirname_case(istate, ce->name);
        }
-       if (!(flags & HASH_RENORMALIZE)) {
+       if (!(flags & ADD_CACHE_RENORMALIZE)) {
                alias = index_file_exists(istate, ce->name,
                                          ce_namelen(ce), ignore_case);
                if (alias &&
@@ -753,9 +770,9 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
                }
        }
        if (!intent_only) {
-               if (index_path(&ce->oid, path, st, newflags)) {
+               if (index_path(istate, &ce->oid, path, st, hash_flags)) {
                        discard_cache_entry(ce);
-                       return error("unable to index file %s", path);
+                       return error(_("unable to index file '%s'"), path);
                }
        } else
                set_object_name_for_intent_to_add_entry(ce);
@@ -767,14 +784,14 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        /* It was suspected to be racily clean, but it turns out to be Ok */
        was_same = (alias &&
                    !ce_stage(alias) &&
-                   !oidcmp(&alias->oid, &ce->oid) &&
+                   oideq(&alias->oid, &ce->oid) &&
                    ce->ce_mode == alias->ce_mode);
 
        if (pretend)
                discard_cache_entry(ce);
        else if (add_index_entry(istate, ce, add_option)) {
                discard_cache_entry(ce);
-               return error("unable to add %s to index", path);
+               return error(_("unable to add '%s' to index"), path);
        }
        if (verbose && !was_same)
                printf("add '%s'\n", path);
@@ -785,7 +802,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)
 {
        struct stat st;
        if (lstat(path, &st))
-               die_errno("unable to stat '%s'", path);
+               die_errno(_("unable to stat '%s'"), path);
        return add_to_index(istate, path, &st, flags);
 }
 
@@ -810,7 +827,7 @@ struct cache_entry *make_cache_entry(struct index_state *istate,
        int len;
 
        if (!verify_path(path, mode)) {
-               error("Invalid path '%s'", path);
+               error(_("invalid path '%s'"), path);
                return NULL;
        }
 
@@ -823,7 +840,7 @@ struct cache_entry *make_cache_entry(struct index_state *istate,
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
 
-       ret = refresh_cache_entry(&the_index, ce, refresh_options);
+       ret = refresh_cache_entry(istate, ce, refresh_options);
        if (ret != ce)
                discard_cache_entry(ce);
        return ret;
@@ -836,7 +853,7 @@ struct cache_entry *make_transient_cache_entry(unsigned int mode, const struct o
        int len;
 
        if (!verify_path(path, mode)) {
-               error("Invalid path '%s'", path);
+               error(_("invalid path '%s'"), path);
                return NULL;
        }
 
@@ -942,7 +959,7 @@ static int verify_dotfile(const char *rest, unsigned mode)
 
 int verify_path(const char *path, unsigned mode)
 {
-       char c;
+       char c = 0;
 
        if (has_dos_drive_prefix(path))
                return 0;
@@ -957,6 +974,7 @@ int verify_path(const char *path, unsigned mode)
                if (is_dir_sep(c)) {
 inside:
                        if (protect_hfs) {
+
                                if (is_hfs_dotgit(path))
                                        return 0;
                                if (S_ISLNK(mode)) {
@@ -965,6 +983,10 @@ inside:
                                }
                        }
                        if (protect_ntfs) {
+#ifdef GIT_WINDOWS_NATIVE
+                               if (c == '\\')
+                                       return 0;
+#endif
                                if (is_ntfs_dotgit(path))
                                        return 0;
                                if (S_ISLNK(mode)) {
@@ -1270,7 +1292,7 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
         */
        if (istate->cache_nr > 0 &&
                strcmp(ce->name, istate->cache[istate->cache_nr - 1]->name) > 0)
-               pos = -istate->cache_nr - 1;
+               pos = index_pos_to_insert_pos(istate->cache_nr);
        else
                pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
 
@@ -1300,12 +1322,12 @@ static int add_index_entry_with_check(struct index_state *istate, struct cache_e
        if (!ok_to_add)
                return -1;
        if (!verify_path(ce->name, ce->ce_mode))
-               return error("Invalid path '%s'", ce->name);
+               return error(_("invalid path '%s'"), ce->name);
 
        if (!skip_df_check &&
            check_file_directory_conflict(istate, ce, pos, ok_to_replace)) {
                if (!ok_to_replace)
-                       return error("'%s' appears as both a file and as a directory",
+                       return error(_("'%s' appears as both a file and as a directory"),
                                     ce->name);
                pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
                pos = -pos-1;
@@ -1426,7 +1448,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
                         */
                        if (!S_ISGITLINK(ce->ce_mode)) {
                                ce_mark_uptodate(ce);
-                               mark_fsmonitor_valid(ce);
+                               mark_fsmonitor_valid(istate, ce);
                        }
                        return ce;
                }
@@ -1441,7 +1463,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        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);
+       fill_stat_cache_info(istate, updated, &st);
        /*
         * If ignore_valid is not set, we should leave CE_VALID bit
         * alone.  Otherwise, paths marked with --no-assume-unchanged
@@ -1466,6 +1488,27 @@ static void show_file(const char * fmt, const char * name, int in_porcelain,
        printf(fmt, name);
 }
 
+int repo_refresh_and_write_index(struct repository *repo,
+                                unsigned int refresh_flags,
+                                unsigned int write_flags,
+                                int gentle,
+                                const struct pathspec *pathspec,
+                                char *seen, const char *header_msg)
+{
+       struct lock_file lock_file = LOCK_INIT;
+       int fd, ret = 0;
+
+       fd = repo_hold_locked_index(repo, &lock_file, 0);
+       if (!gentle && fd < 0)
+               return -1;
+       if (refresh_index(repo->index, refresh_flags, pathspec, seen, header_msg))
+               ret = 1;
+       if (0 <= fd && write_locked_index(repo->index, &lock_file, COMMIT_LOCK | write_flags))
+               ret = -1;
+       return ret;
+}
+
+
 int refresh_index(struct index_state *istate, unsigned int flags,
                  const struct pathspec *pathspec,
                  char *seen, const char *header_msg)
@@ -1487,13 +1530,24 @@ int refresh_index(struct index_state *istate, unsigned int flags,
        const char *typechange_fmt;
        const char *added_fmt;
        const char *unmerged_fmt;
-       uint64_t start = getnanotime();
-
-       modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
-       deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n");
-       typechange_fmt = (in_porcelain ? "T\t%s\n" : "%s needs update\n");
-       added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n");
-       unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
+       struct progress *progress = NULL;
+
+       if (flags & REFRESH_PROGRESS && isatty(2))
+               progress = start_delayed_progress(_("Refresh index"),
+                                                 istate->cache_nr);
+
+       trace_performance_enter();
+       modified_fmt   = in_porcelain ? "M\t%s\n" : "%s: needs update\n";
+       deleted_fmt    = in_porcelain ? "D\t%s\n" : "%s: needs update\n";
+       typechange_fmt = in_porcelain ? "T\t%s\n" : "%s: needs update\n";
+       added_fmt      = in_porcelain ? "A\t%s\n" : "%s: needs update\n";
+       unmerged_fmt   = in_porcelain ? "U\t%s\n" : "%s: needs merge\n";
+       /*
+        * Use the multi-threaded preload_index() to refresh most of the
+        * cache entries quickly then in the single threaded loop below,
+        * we only have to do the special cases that are left.
+        */
+       preload_index(istate, pathspec, 0);
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce, *new_entry;
                int cache_errno = 0;
@@ -1504,7 +1558,7 @@ int refresh_index(struct index_state *istate, unsigned int flags,
                if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
                        continue;
 
-               if (pathspec && !ce_path_match(&the_index, ce, pathspec, seen))
+               if (pathspec && !ce_path_match(istate, ce, pathspec, seen))
                        filtered = 1;
 
                if (ce_stage(ce)) {
@@ -1527,6 +1581,8 @@ int refresh_index(struct index_state *istate, unsigned int flags,
                new_entry = refresh_cache_ent(istate, ce, options, &cache_errno, &changed);
                if (new_entry == ce)
                        continue;
+               if (progress)
+                       display_progress(progress, i);
                if (!new_entry) {
                        const char *fmt;
 
@@ -1558,7 +1614,11 @@ int refresh_index(struct index_state *istate, unsigned int flags,
 
                replace_index_entry(istate, i, new_entry);
        }
-       trace_performance_since(start, "refresh index");
+       if (progress) {
+               display_progress(progress, istate->cache_nr);
+               stop_progress(&progress);
+       }
+       trace_performance_leave("refresh index");
        return has_errors;
 }
 
@@ -1576,16 +1636,17 @@ struct cache_entry *refresh_cache_entry(struct index_state *istate,
 
 #define INDEX_FORMAT_DEFAULT 3
 
-static unsigned int get_index_format_default(void)
+static unsigned int get_index_format_default(struct repository *r)
 {
        char *envversion = getenv("GIT_INDEX_VERSION");
        char *endp;
-       int value;
        unsigned int version = INDEX_FORMAT_DEFAULT;
 
        if (!envversion) {
-               if (!git_config_get_int("index.version", &value))
-                       version = value;
+               prepare_repo_settings(r);
+
+               if (r->settings.index_version >= 0)
+                       version = r->settings.index_version;
                if (version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < version) {
                        warning(_("index.version set, but the value is invalid.\n"
                                  "Using version %i"), INDEX_FORMAT_DEFAULT);
@@ -1621,39 +1682,24 @@ struct ondisk_cache_entry {
        uint32_t uid;
        uint32_t gid;
        uint32_t size;
-       unsigned char sha1[20];
-       uint16_t flags;
-       char name[FLEX_ARRAY]; /* more */
-};
-
-/*
- * This struct is used when CE_EXTENDED bit is 1
- * The struct must match ondisk_cache_entry exactly from
- * ctime till flags
- */
-struct ondisk_cache_entry_extended {
-       struct cache_time ctime;
-       struct cache_time mtime;
-       uint32_t dev;
-       uint32_t ino;
-       uint32_t mode;
-       uint32_t uid;
-       uint32_t gid;
-       uint32_t size;
-       unsigned char sha1[20];
-       uint16_t flags;
-       uint16_t flags2;
-       char name[FLEX_ARRAY]; /* more */
+       /*
+        * unsigned char hash[hashsz];
+        * uint16_t flags;
+        * if (flags & CE_EXTENDED)
+        *      uint16_t flags2;
+        */
+       unsigned char data[GIT_MAX_RAWSZ + 2 * sizeof(uint16_t)];
+       char name[FLEX_ARRAY];
 };
 
 /* These are only used for v3 or lower */
 #define align_padding_size(size, len) ((size + (len) + 8) & ~7) - (size + len)
-#define align_flex_name(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
+#define align_flex_name(STRUCT,len) ((offsetof(struct STRUCT,data) + (len) + 8) & ~7)
 #define ondisk_cache_entry_size(len) align_flex_name(ondisk_cache_entry,len)
-#define ondisk_cache_entry_extended_size(len) align_flex_name(ondisk_cache_entry_extended,len)
-#define ondisk_ce_size(ce) (((ce)->ce_flags & CE_EXTENDED) ? \
-                           ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
-                           ondisk_cache_entry_size(ce_namelen(ce)))
+#define ondisk_data_size(flags, len) (the_hash_algo->rawsz + \
+                                    ((flags & CE_EXTENDED) ? 2 : 1) * sizeof(uint16_t) + len)
+#define ondisk_data_size_max(len) (ondisk_data_size(CE_EXTENDED, len))
+#define ondisk_ce_size(ce) (ondisk_cache_entry_size(ondisk_data_size((ce)->ce_flags, ce_namelen(ce))))
 
 /* Allow fsck to force verification of the index checksum. */
 int verify_index_checksum;
@@ -1661,17 +1707,17 @@ int verify_index_checksum;
 /* Allow fsck to force verification of the cache entry order. */
 int verify_ce_order;
 
-static int verify_hdr(struct cache_header *hdr, unsigned long size)
+static int verify_hdr(const struct cache_header *hdr, unsigned long size)
 {
        git_hash_ctx c;
        unsigned char hash[GIT_MAX_RAWSZ];
        int hdr_version;
 
        if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
-               return error("bad signature");
+               return error(_("bad signature 0x%08x"), hdr->hdr_signature);
        hdr_version = ntohl(hdr->hdr_version);
        if (hdr_version < INDEX_FORMAT_LB || INDEX_FORMAT_UB < hdr_version)
-               return error("bad index version %d", hdr_version);
+               return error(_("bad index version %d"), hdr_version);
 
        if (!verify_index_checksum)
                return 0;
@@ -1679,13 +1725,13 @@ static int verify_hdr(struct cache_header *hdr, unsigned long size)
        the_hash_algo->init_fn(&c);
        the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
        the_hash_algo->final_fn(hash, &c);
-       if (hashcmp(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
-               return error("bad index file sha1 signature");
+       if (!hasheq(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
+               return error(_("bad index file sha1 signature"));
        return 0;
 }
 
 static int read_index_extension(struct index_state *istate,
-                               const char *ext, void *data, unsigned long sz)
+                               const char *ext, const char *data, unsigned long sz)
 {
        switch (CACHE_EXT(ext)) {
        case CACHE_EXT_TREE:
@@ -1704,117 +1750,107 @@ static int read_index_extension(struct index_state *istate,
        case CACHE_EXT_FSMONITOR:
                read_fsmonitor_extension(istate, data, sz);
                break;
+       case CACHE_EXT_ENDOFINDEXENTRIES:
+       case CACHE_EXT_INDEXENTRYOFFSETTABLE:
+               /* already handled in do_read_index() */
+               break;
        default:
                if (*ext < 'A' || 'Z' < *ext)
-                       return error("index uses %.4s extension, which we do not understand",
+                       return error(_("index uses %.4s extension, which we do not understand"),
                                     ext);
-               fprintf(stderr, "ignoring %.4s extension\n", ext);
+               fprintf_ln(stderr, _("ignoring %.4s extension"), ext);
                break;
        }
        return 0;
 }
 
-int hold_locked_index(struct lock_file *lk, int lock_flags)
-{
-       return hold_lock_file_for_update(lk, get_index_file(), lock_flags);
-}
-
-int read_index(struct index_state *istate)
-{
-       return read_index_from(istate, get_index_file(), get_git_dir());
-}
-
-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 = 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);
-       ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
-       ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
-       ce->ce_stat_data.sd_dev   = get_be32(&ondisk->dev);
-       ce->ce_stat_data.sd_ino   = get_be32(&ondisk->ino);
-       ce->ce_mode  = get_be32(&ondisk->mode);
-       ce->ce_stat_data.sd_uid   = get_be32(&ondisk->uid);
-       ce->ce_stat_data.sd_gid   = get_be32(&ondisk->gid);
-       ce->ce_stat_data.sd_size  = get_be32(&ondisk->size);
-       ce->ce_flags = flags & ~CE_NAMEMASK;
-       ce->ce_namelen = len;
-       ce->index = 0;
-       hashcpy(ce->oid.hash, ondisk->sha1);
-       memcpy(ce->name, name, len);
-       ce->name[len] = '\0';
-       return ce;
-}
-
-/*
- * Adjacent cache entries tend to share the leading paths, so it makes
- * sense to only store the differences in later entries.  In the v4
- * on-disk format of the index, each on-disk cache entry stores the
- * number of bytes to be stripped from the end of the previous name,
- * and the bytes to append to the result, to come up with its name.
- */
-static unsigned long expand_name_field(struct strbuf *name, const char *cp_)
-{
-       const unsigned char *ep, *cp = (const unsigned char *)cp_;
-       size_t len = decode_varint(&cp);
-
-       if (name->len < len)
-               die("malformed name field in the index");
-       strbuf_remove(name, name->len - len, len);
-       for (ep = cp; *ep; ep++)
-               ; /* find the end */
-       strbuf_add(name, cp, ep - cp);
-       return (const char *)ep + 1 - cp_;
-}
-
-static struct cache_entry *create_from_disk(struct mem_pool *mem_pool,
+static struct cache_entry *create_from_disk(struct mem_pool *ce_mem_pool,
+                                           unsigned int version,
                                            struct ondisk_cache_entry *ondisk,
                                            unsigned long *ent_size,
-                                           struct strbuf *previous_name)
+                                           const struct cache_entry *previous_ce)
 {
        struct cache_entry *ce;
        size_t len;
        const char *name;
+       const unsigned hashsz = the_hash_algo->rawsz;
+       const uint16_t *flagsp = (const uint16_t *)(ondisk->data + hashsz);
        unsigned int flags;
+       size_t copy_len = 0;
+       /*
+        * Adjacent cache entries tend to share the leading paths, so it makes
+        * sense to only store the differences in later entries.  In the v4
+        * on-disk format of the index, each on-disk cache entry stores the
+        * number of bytes to be stripped from the end of the previous name,
+        * and the bytes to append to the result, to come up with its name.
+        */
+       int expand_name_field = version == 4;
 
        /* On-disk flags are just 16 bits */
-       flags = get_be16(&ondisk->flags);
+       flags = get_be16(flagsp);
        len = flags & CE_NAMEMASK;
 
        if (flags & CE_EXTENDED) {
-               struct ondisk_cache_entry_extended *ondisk2;
                int extended_flags;
-               ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
-               extended_flags = get_be16(&ondisk2->flags2) << 16;
+               extended_flags = get_be16(flagsp + 1) << 16;
                /* We do not yet understand any bit out of CE_EXTENDED_FLAGS */
                if (extended_flags & ~CE_EXTENDED_FLAGS)
-                       die("Unknown index entry format %08x", extended_flags);
+                       die(_("unknown index entry format 0x%08x"), extended_flags);
                flags |= extended_flags;
-               name = ondisk2->name;
+               name = (const char *)(flagsp + 2);
        }
        else
-               name = ondisk->name;
+               name = (const char *)(flagsp + 1);
+
+       if (expand_name_field) {
+               const unsigned char *cp = (const unsigned char *)name;
+               size_t strip_len, previous_len;
+
+               /* If we're at the beginning of a block, ignore the previous name */
+               strip_len = decode_varint(&cp);
+               if (previous_ce) {
+                       previous_len = previous_ce->ce_namelen;
+                       if (previous_len < strip_len)
+                               die(_("malformed name field in the index, near path '%s'"),
+                                       previous_ce->name);
+                       copy_len = previous_len - strip_len;
+               }
+               name = (const char *)cp;
+       }
 
-       if (!previous_name) {
-               /* v3 and earlier */
-               if (len == CE_NAMEMASK)
-                       len = strlen(name);
-               ce = cache_entry_from_ondisk(mem_pool, ondisk, flags, name, len);
+       if (len == CE_NAMEMASK) {
+               len = strlen(name);
+               if (expand_name_field)
+                       len += copy_len;
+       }
 
-               *ent_size = ondisk_ce_size(ce);
-       } else {
-               unsigned long consumed;
-               consumed = expand_name_field(previous_name, name);
-               ce = cache_entry_from_ondisk(mem_pool, ondisk, flags,
-                                            previous_name->buf,
-                                            previous_name->len);
+       ce = mem_pool__ce_alloc(ce_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);
+       ce->ce_stat_data.sd_ctime.nsec = get_be32(&ondisk->ctime.nsec);
+       ce->ce_stat_data.sd_mtime.nsec = get_be32(&ondisk->mtime.nsec);
+       ce->ce_stat_data.sd_dev   = get_be32(&ondisk->dev);
+       ce->ce_stat_data.sd_ino   = get_be32(&ondisk->ino);
+       ce->ce_mode  = get_be32(&ondisk->mode);
+       ce->ce_stat_data.sd_uid   = get_be32(&ondisk->uid);
+       ce->ce_stat_data.sd_gid   = get_be32(&ondisk->gid);
+       ce->ce_stat_data.sd_size  = get_be32(&ondisk->size);
+       ce->ce_flags = flags & ~CE_NAMEMASK;
+       ce->ce_namelen = len;
+       ce->index = 0;
+       hashcpy(ce->oid.hash, ondisk->data);
+       memcpy(ce->name, name, len);
+       ce->name[len] = '\0';
 
-               *ent_size = (name - ((char *)ondisk)) + consumed;
+       if (expand_name_field) {
+               if (copy_len)
+                       memcpy(ce->name, previous_ce->name, copy_len);
+               memcpy(ce->name + copy_len, name, len + 1 - copy_len);
+               *ent_size = (name - ((char *)ondisk)) + len + 1 - copy_len;
+       } else {
+               memcpy(ce->name, name, len + 1);
+               *ent_size = ondisk_ce_size(ce);
        }
        return ce;
 }
@@ -1832,13 +1868,13 @@ static void check_ce_order(struct index_state *istate)
                int name_compare = strcmp(ce->name, next_ce->name);
 
                if (0 < name_compare)
-                       die("unordered stage entries in index");
+                       die(_("unordered stage entries in index"));
                if (!name_compare) {
                        if (!ce_stage(ce))
-                               die("multiple stage entries for merged file '%s'",
+                               die(_("multiple stage entries for merged file '%s'"),
                                    ce->name);
                        if (ce_stage(ce) > ce_stage(next_ce))
-                               die("unordered stage entries for '%s'",
+                               die(_("unordered stage entries for '%s'"),
                                    ce->name);
                }
        }
@@ -1846,18 +1882,17 @@ static void check_ce_order(struct index_state *istate)
 
 static void tweak_untracked_cache(struct index_state *istate)
 {
-       switch (git_config_get_untracked_cache()) {
-       case -1: /* keep: do nothing */
-               break;
-       case 0: /* false */
+       struct repository *r = the_repository;
+
+       prepare_repo_settings(r);
+
+       if (r->settings.core_untracked_cache  == UNTRACKED_CACHE_REMOVE) {
                remove_untracked_cache(istate);
-               break;
-       case 1: /* true */
-               add_untracked_cache(istate);
-               break;
-       default: /* unknown value: do nothing */
-               break;
+               return;
        }
+
+       if (r->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE)
+               add_untracked_cache(istate);
 }
 
 static void tweak_split_index(struct index_state *istate)
@@ -1896,20 +1931,232 @@ static size_t estimate_cache_size(size_t ondisk_size, unsigned int entries)
        /*
         * Account for potential alignment differences.
         */
-       per_entry += align_padding_size(sizeof(struct cache_entry), -sizeof(struct ondisk_cache_entry));
+       per_entry += align_padding_size(per_entry, 0);
        return ondisk_size + entries * per_entry;
 }
 
+struct index_entry_offset
+{
+       /* starting byte offset into index file, count of index entries in this block */
+       int offset, nr;
+};
+
+struct index_entry_offset_table
+{
+       int nr;
+       struct index_entry_offset entries[FLEX_ARRAY];
+};
+
+static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset);
+static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot);
+
+static size_t read_eoie_extension(const char *mmap, size_t mmap_size);
+static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset);
+
+struct load_index_extensions
+{
+       pthread_t pthread;
+       struct index_state *istate;
+       const char *mmap;
+       size_t mmap_size;
+       unsigned long src_offset;
+};
+
+static void *load_index_extensions(void *_data)
+{
+       struct load_index_extensions *p = _data;
+       unsigned long src_offset = p->src_offset;
+
+       while (src_offset <= p->mmap_size - the_hash_algo->rawsz - 8) {
+               /* After an array of active_nr index entries,
+                * there can be arbitrary number of extended
+                * sections, each of which is prefixed with
+                * extension name (4-byte) and section length
+                * in 4-byte network byte order.
+                */
+               uint32_t extsize = get_be32(p->mmap + src_offset + 4);
+               if (read_index_extension(p->istate,
+                                        p->mmap + src_offset,
+                                        p->mmap + src_offset + 8,
+                                        extsize) < 0) {
+                       munmap((void *)p->mmap, p->mmap_size);
+                       die(_("index file corrupt"));
+               }
+               src_offset += 8;
+               src_offset += extsize;
+       }
+
+       return NULL;
+}
+
+/*
+ * A helper function that will load the specified range of cache entries
+ * from the memory mapped file and add them to the given index.
+ */
+static unsigned long load_cache_entry_block(struct index_state *istate,
+                       struct mem_pool *ce_mem_pool, int offset, int nr, const char *mmap,
+                       unsigned long start_offset, const struct cache_entry *previous_ce)
+{
+       int i;
+       unsigned long src_offset = start_offset;
+
+       for (i = offset; i < offset + nr; i++) {
+               struct ondisk_cache_entry *disk_ce;
+               struct cache_entry *ce;
+               unsigned long consumed;
+
+               disk_ce = (struct ondisk_cache_entry *)(mmap + src_offset);
+               ce = create_from_disk(ce_mem_pool, istate->version, disk_ce, &consumed, previous_ce);
+               set_index_entry(istate, i, ce);
+
+               src_offset += consumed;
+               previous_ce = ce;
+       }
+       return src_offset - start_offset;
+}
+
+static unsigned long load_all_cache_entries(struct index_state *istate,
+                       const char *mmap, size_t mmap_size, unsigned long src_offset)
+{
+       unsigned long consumed;
+
+       if (istate->version == 4) {
+               mem_pool_init(&istate->ce_mem_pool,
+                               estimate_cache_size_from_compressed(istate->cache_nr));
+       } else {
+               mem_pool_init(&istate->ce_mem_pool,
+                               estimate_cache_size(mmap_size, istate->cache_nr));
+       }
+
+       consumed = load_cache_entry_block(istate, istate->ce_mem_pool,
+                                       0, istate->cache_nr, mmap, src_offset, NULL);
+       return consumed;
+}
+
+/*
+ * Mostly randomly chosen maximum thread counts: we
+ * cap the parallelism to online_cpus() threads, and we want
+ * to have at least 10000 cache entries per thread for it to
+ * be worth starting a thread.
+ */
+
+#define THREAD_COST            (10000)
+
+struct load_cache_entries_thread_data
+{
+       pthread_t pthread;
+       struct index_state *istate;
+       struct mem_pool *ce_mem_pool;
+       int offset;
+       const char *mmap;
+       struct index_entry_offset_table *ieot;
+       int ieot_start;         /* starting index into the ieot array */
+       int ieot_blocks;        /* count of ieot entries to process */
+       unsigned long consumed; /* return # of bytes in index file processed */
+};
+
+/*
+ * A thread proc to run the load_cache_entries() computation
+ * across multiple background threads.
+ */
+static void *load_cache_entries_thread(void *_data)
+{
+       struct load_cache_entries_thread_data *p = _data;
+       int i;
+
+       /* iterate across all ieot blocks assigned to this thread */
+       for (i = p->ieot_start; i < p->ieot_start + p->ieot_blocks; i++) {
+               p->consumed += load_cache_entry_block(p->istate, p->ce_mem_pool,
+                       p->offset, p->ieot->entries[i].nr, p->mmap, p->ieot->entries[i].offset, NULL);
+               p->offset += p->ieot->entries[i].nr;
+       }
+       return NULL;
+}
+
+static unsigned long load_cache_entries_threaded(struct index_state *istate, const char *mmap, size_t mmap_size,
+                                                int nr_threads, struct index_entry_offset_table *ieot)
+{
+       int i, offset, ieot_blocks, ieot_start, err;
+       struct load_cache_entries_thread_data *data;
+       unsigned long consumed = 0;
+
+       /* a little sanity checking */
+       if (istate->name_hash_initialized)
+               BUG("the name hash isn't thread safe");
+
+       mem_pool_init(&istate->ce_mem_pool, 0);
+
+       /* ensure we have no more threads than we have blocks to process */
+       if (nr_threads > ieot->nr)
+               nr_threads = ieot->nr;
+       data = xcalloc(nr_threads, sizeof(*data));
+
+       offset = ieot_start = 0;
+       ieot_blocks = DIV_ROUND_UP(ieot->nr, nr_threads);
+       for (i = 0; i < nr_threads; i++) {
+               struct load_cache_entries_thread_data *p = &data[i];
+               int nr, j;
+
+               if (ieot_start + ieot_blocks > ieot->nr)
+                       ieot_blocks = ieot->nr - ieot_start;
+
+               p->istate = istate;
+               p->offset = offset;
+               p->mmap = mmap;
+               p->ieot = ieot;
+               p->ieot_start = ieot_start;
+               p->ieot_blocks = ieot_blocks;
+
+               /* create a mem_pool for each thread */
+               nr = 0;
+               for (j = p->ieot_start; j < p->ieot_start + p->ieot_blocks; j++)
+                       nr += p->ieot->entries[j].nr;
+               if (istate->version == 4) {
+                       mem_pool_init(&p->ce_mem_pool,
+                               estimate_cache_size_from_compressed(nr));
+               } else {
+                       mem_pool_init(&p->ce_mem_pool,
+                               estimate_cache_size(mmap_size, nr));
+               }
+
+               err = pthread_create(&p->pthread, NULL, load_cache_entries_thread, p);
+               if (err)
+                       die(_("unable to create load_cache_entries thread: %s"), strerror(err));
+
+               /* increment by the number of cache entries in the ieot block being processed */
+               for (j = 0; j < ieot_blocks; j++)
+                       offset += ieot->entries[ieot_start + j].nr;
+               ieot_start += ieot_blocks;
+       }
+
+       for (i = 0; i < nr_threads; i++) {
+               struct load_cache_entries_thread_data *p = &data[i];
+
+               err = pthread_join(p->pthread, NULL);
+               if (err)
+                       die(_("unable to join load_cache_entries thread: %s"), strerror(err));
+               mem_pool_combine(istate->ce_mem_pool, p->ce_mem_pool);
+               consumed += p->consumed;
+       }
+
+       free(data);
+
+       return consumed;
+}
+
 /* remember to discard_cache() before reading a different cache! */
 int do_read_index(struct index_state *istate, const char *path, int must_exist)
 {
-       int fd, i;
+       int fd;
        struct stat st;
        unsigned long src_offset;
-       struct cache_header *hdr;
-       void *mmap;
+       const struct cache_header *hdr;
+       const char *mmap;
        size_t mmap_size;
-       struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
+       struct load_index_extensions p;
+       size_t extension_offset = 0;
+       int nr_threads, cpus;
+       struct index_entry_offset_table *ieot = NULL;
 
        if (istate->initialized)
                return istate->cache_nr;
@@ -1920,22 +2167,22 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
        if (fd < 0) {
                if (!must_exist && errno == ENOENT)
                        return 0;
-               die_errno("%s: index file open failed", path);
+               die_errno(_("%s: index file open failed"), path);
        }
 
        if (fstat(fd, &st))
-               die_errno("cannot stat the open index");
+               die_errno(_("%s: cannot stat the open index"), path);
 
        mmap_size = xsize_t(st.st_size);
        if (mmap_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
-               die("index file smaller than expected");
+               die(_("%s: index file smaller than expected"), path);
 
-       mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
+       mmap = xmmap_gently(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
        if (mmap == MAP_FAILED)
-               die_errno("unable to map index file");
+               die_errno(_("%s: unable to map index file"), path);
        close(fd);
 
-       hdr = mmap;
+       hdr = (const struct cache_header *)mmap;
        if (verify_hdr(hdr, mmap_size) < 0)
                goto unmap;
 
@@ -1946,56 +2193,82 @@ 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) {
-               previous_name = &previous_name_buf;
-               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));
-       }
+       p.istate = istate;
+       p.mmap = mmap;
+       p.mmap_size = mmap_size;
 
        src_offset = sizeof(*hdr);
-       for (i = 0; i < istate->cache_nr; i++) {
-               struct ondisk_cache_entry *disk_ce;
-               struct cache_entry *ce;
-               unsigned long consumed;
 
-               disk_ce = (struct ondisk_cache_entry *)((char *)mmap + src_offset);
-               ce = create_from_disk(istate->ce_mem_pool, disk_ce, &consumed, previous_name);
-               set_index_entry(istate, i, ce);
+       if (git_config_get_index_threads(&nr_threads))
+               nr_threads = 1;
 
-               src_offset += consumed;
+       /* TODO: does creating more threads than cores help? */
+       if (!nr_threads) {
+               nr_threads = istate->cache_nr / THREAD_COST;
+               cpus = online_cpus();
+               if (nr_threads > cpus)
+                       nr_threads = cpus;
        }
-       strbuf_release(&previous_name_buf);
+
+       if (!HAVE_THREADS)
+               nr_threads = 1;
+
+       if (nr_threads > 1) {
+               extension_offset = read_eoie_extension(mmap, mmap_size);
+               if (extension_offset) {
+                       int err;
+
+                       p.src_offset = extension_offset;
+                       err = pthread_create(&p.pthread, NULL, load_index_extensions, &p);
+                       if (err)
+                               die(_("unable to create load_index_extensions thread: %s"), strerror(err));
+
+                       nr_threads--;
+               }
+       }
+
+       /*
+        * Locate and read the index entry offset table so that we can use it
+        * to multi-thread the reading of the cache entries.
+        */
+       if (extension_offset && nr_threads > 1)
+               ieot = read_ieot_extension(mmap, mmap_size, extension_offset);
+
+       if (ieot) {
+               src_offset += load_cache_entries_threaded(istate, mmap, mmap_size, nr_threads, ieot);
+               free(ieot);
+       } else {
+               src_offset += load_all_cache_entries(istate, mmap, mmap_size, src_offset);
+       }
+
        istate->timestamp.sec = st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
 
-       while (src_offset <= mmap_size - the_hash_algo->rawsz - 8) {
-               /* After an array of active_nr index entries,
-                * there can be arbitrary number of extended
-                * sections, each of which is prefixed with
-                * extension name (4-byte) and section length
-                * in 4-byte network byte order.
-                */
-               uint32_t extsize;
-               memcpy(&extsize, (char *)mmap + src_offset + 4, 4);
-               extsize = ntohl(extsize);
-               if (read_index_extension(istate,
-                                        (const char *) mmap + src_offset,
-                                        (char *) mmap + src_offset + 8,
-                                        extsize) < 0)
-                       goto unmap;
-               src_offset += 8;
-               src_offset += extsize;
+       /* if we created a thread, join it otherwise load the extensions on the primary thread */
+       if (extension_offset) {
+               int ret = pthread_join(p.pthread, NULL);
+               if (ret)
+                       die(_("unable to join load_index_extensions thread: %s"), strerror(ret));
+       } else {
+               p.src_offset = src_offset;
+               load_index_extensions(&p);
        }
-       munmap(mmap, mmap_size);
+       munmap((void *)mmap, mmap_size);
+
+       /*
+        * TODO trace2: replace "the_repository" with the actual repo instance
+        * that is associated with the given "istate".
+        */
+       trace2_data_intmax("index", the_repository, "read/version",
+                          istate->version);
+       trace2_data_intmax("index", the_repository, "read/cache_nr",
+                          istate->cache_nr);
+
        return istate->cache_nr;
 
 unmap:
-       munmap(mmap, mmap_size);
-       die("index file corrupt");
+       munmap((void *)mmap, mmap_size);
+       die(_("index file corrupt"));
 }
 
 /*
@@ -2007,13 +2280,12 @@ unmap:
 static void freshen_shared_index(const char *shared_index, int warn)
 {
        if (!check_and_freshen_file(shared_index, 1) && warn)
-               warning("could not freshen shared index '%s'", shared_index);
+               warning(_("could not freshen shared index '%s'"), shared_index);
 }
 
 int read_index_from(struct index_state *istate, const char *path,
                    const char *gitdir)
 {
-       uint64_t start = getnanotime();
        struct split_index *split_index;
        int ret;
        char *base_oid_hex;
@@ -2023,8 +2295,17 @@ int read_index_from(struct index_state *istate, const char *path,
        if (istate->initialized)
                return istate->cache_nr;
 
+       /*
+        * TODO trace2: replace "the_repository" with the actual repo instance
+        * that is associated with the given "istate".
+        */
+       trace2_region_enter_printf("index", "do_read_index", the_repository,
+                                  "%s", path);
+       trace_performance_enter();
        ret = do_read_index(istate, path, 0);
-       trace_performance_since(start, "read cache %s", path);
+       trace_performance_leave("read cache %s", path);
+       trace2_region_leave_printf("index", "do_read_index", the_repository,
+                                  "%s", path);
 
        split_index = istate->split_index;
        if (!split_index || is_null_oid(&split_index->base_oid)) {
@@ -2032,6 +2313,7 @@ int read_index_from(struct index_state *istate, const char *path,
                return ret;
        }
 
+       trace_performance_enter();
        if (split_index->base)
                discard_index(split_index->base);
        else
@@ -2039,16 +2321,20 @@ int read_index_from(struct index_state *istate, const char *path,
 
        base_oid_hex = oid_to_hex(&split_index->base_oid);
        base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_oid_hex);
+       trace2_region_enter_printf("index", "shared/do_read_index",
+                                  the_repository, "%s", base_path);
        ret = do_read_index(split_index->base, base_path, 1);
-       if (oidcmp(&split_index->base_oid, &split_index->base->oid))
-               die("broken index, expect %s in %s, got %s",
+       trace2_region_leave_printf("index", "shared/do_read_index",
+                                  the_repository, "%s", base_path);
+       if (!oideq(&split_index->base_oid, &split_index->base->oid))
+               die(_("broken index, expect %s in %s, got %s"),
                    base_oid_hex, base_path,
                    oid_to_hex(&split_index->base->oid));
 
        freshen_shared_index(base_path, 0);
        merge_base_index(istate);
        post_read_index_from(istate);
-       trace_performance_since(start, "read cache %s", base_path);
+       trace_performance_leave("read cache %s", base_path);
        free(base_path);
        return ret;
 }
@@ -2077,6 +2363,7 @@ int discard_index(struct index_state *istate)
        free_name_hash(istate);
        cache_tree_free(&(istate->cache_tree));
        istate->initialized = 0;
+       istate->fsmonitor_has_run_once = 0;
        FREE_AND_NULL(istate->cache);
        istate->cache_alloc = 0;
        discard_split_index(istate);
@@ -2107,14 +2394,14 @@ void validate_cache_entries(const struct index_state *istate)
 
        for (i = 0; i < istate->cache_nr; i++) {
                if (!istate) {
-                       die("internal error: cache entry is not allocated from expected memory pool");
+                       BUG("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");
+                               BUG("cache entry is not allocated from expected memory pool");
                        }
                }
        }
@@ -2133,22 +2420,20 @@ int unmerged_index(const struct index_state *istate)
        return 0;
 }
 
-int index_has_changes(const struct index_state *istate,
-                     struct tree *tree,
-                     struct strbuf *sb)
+int repo_index_has_changes(struct repository *repo,
+                          struct tree *tree,
+                          struct strbuf *sb)
 {
+       struct index_state *istate = repo->index;
        struct object_id cmp;
        int i;
 
-       if (istate != &the_index) {
-               BUG("index_has_changes cannot yet accept istate != &the_index; do_diff_cache needs updating first.");
-       }
        if (tree)
                cmp = tree->object.oid;
        if (tree || !get_oid_tree("HEAD", &cmp)) {
                struct diff_options opt;
 
-               diff_setup(&opt);
+               repo_diff_setup(repo, &opt);
                opt.flags.exit_with_status = 1;
                if (!sb)
                        opt.flags.quick = 1;
@@ -2209,11 +2494,15 @@ static int ce_write(git_hash_ctx *context, int fd, void *data, unsigned int len)
        return 0;
 }
 
-static int write_index_ext_header(git_hash_ctx *context, int fd,
-                                 unsigned int ext, unsigned int sz)
+static int write_index_ext_header(git_hash_ctx *context, git_hash_ctx *eoie_context,
+                                 int fd, unsigned int ext, unsigned int sz)
 {
        ext = htonl(ext);
        sz = htonl(sz);
+       if (eoie_context) {
+               the_hash_algo->update_fn(eoie_context, &ext, 4);
+               the_hash_algo->update_fn(eoie_context, &sz, 4);
+       }
        return ((ce_write(context, fd, &ext, 4) < 0) ||
                (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
 }
@@ -2241,7 +2530,8 @@ static int ce_flush(git_hash_ctx *context, int fd, unsigned char *hash)
        return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
 }
 
-static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
+static void ce_smudge_racily_clean_entry(struct index_state *istate,
+                                        struct cache_entry *ce)
 {
        /*
         * The only thing we care about in this function is to smudge the
@@ -2260,7 +2550,7 @@ static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
                return;
        if (ce_match_stat_basic(ce, &st))
                return;
-       if (ce_modified_check_fs(ce, &st)) {
+       if (ce_modified_check_fs(istate, ce, &st)) {
                /* This is "racily clean"; smudge it.  Note that this
                 * is a tricky code.  At first glance, it may appear
                 * that it can break with this sequence:
@@ -2295,6 +2585,8 @@ static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
                                       struct cache_entry *ce)
 {
        short flags;
+       const unsigned hashsz = the_hash_algo->rawsz;
+       uint16_t *flagsp = (uint16_t *)(ondisk->data + hashsz);
 
        ondisk->ctime.sec = htonl(ce->ce_stat_data.sd_ctime.sec);
        ondisk->mtime.sec = htonl(ce->ce_stat_data.sd_mtime.sec);
@@ -2306,15 +2598,13 @@ static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
        ondisk->uid  = htonl(ce->ce_stat_data.sd_uid);
        ondisk->gid  = htonl(ce->ce_stat_data.sd_gid);
        ondisk->size = htonl(ce->ce_stat_data.sd_size);
-       hashcpy(ondisk->sha1, ce->oid.hash);
+       hashcpy(ondisk->data, ce->oid.hash);
 
        flags = ce->ce_flags & ~CE_NAMEMASK;
        flags |= (ce_namelen(ce) >= CE_NAMEMASK ? CE_NAMEMASK : ce_namelen(ce));
-       ondisk->flags = htons(flags);
+       flagsp[0] = htons(flags);
        if (ce->ce_flags & CE_EXTENDED) {
-               struct ondisk_cache_entry_extended *ondisk2;
-               ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
-               ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);
+               flagsp[1] = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);
        }
 }
 
@@ -2333,10 +2623,7 @@ static int ce_write_entry(git_hash_ctx *c, int fd, struct cache_entry *ce,
                stripped_name = 1;
        }
 
-       if (ce->ce_flags & CE_EXTENDED)
-               size = offsetof(struct ondisk_cache_entry_extended, name);
-       else
-               size = offsetof(struct ondisk_cache_entry, name);
+       size = offsetof(struct ondisk_cache_entry,data) + ondisk_data_size(ce->ce_flags, 0);
 
        if (!previous_name) {
                int len = ce_namelen(ce);
@@ -2406,7 +2693,7 @@ static int verify_index_from(const struct index_state *istate, const char *path)
        if (n != the_hash_algo->rawsz)
                goto out;
 
-       if (hashcmp(istate->oid.hash, hash))
+       if (!hasheq(istate->oid.hash, hash))
                goto out;
 
        close(fd);
@@ -2417,9 +2704,9 @@ out:
        return 0;
 }
 
-static int verify_index(const struct index_state *istate)
+static int repo_verify_index(struct repository *repo)
 {
-       return verify_index_from(istate, get_index_file());
+       return verify_index_from(repo->index, repo->index_file);
 }
 
 static int has_racy_timestamp(struct index_state *istate)
@@ -2435,15 +2722,47 @@ static int has_racy_timestamp(struct index_state *istate)
        return 0;
 }
 
-void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
+void repo_update_index_if_able(struct repository *repo,
+                              struct lock_file *lockfile)
 {
-       if ((istate->cache_changed || has_racy_timestamp(istate)) &&
-           verify_index(istate))
-               write_locked_index(istate, lockfile, COMMIT_LOCK);
+       if ((repo->index->cache_changed ||
+            has_racy_timestamp(repo->index)) &&
+           repo_verify_index(repo))
+               write_locked_index(repo->index, lockfile, COMMIT_LOCK);
        else
                rollback_lock_file(lockfile);
 }
 
+static int record_eoie(void)
+{
+       int val;
+
+       if (!git_config_get_bool("index.recordendofindexentries", &val))
+               return val;
+
+       /*
+        * As a convenience, the end of index entries extension
+        * used for threading is written by default if the user
+        * explicitly requested threaded index reads.
+        */
+       return !git_config_get_index_threads(&val) && val != 1;
+}
+
+static int record_ieot(void)
+{
+       int val;
+
+       if (!git_config_get_bool("index.recordoffsettable", &val))
+               return val;
+
+       /*
+        * As a convenience, the offset table used for threading is
+        * written by default if the user explicitly requested
+        * threaded index reads.
+        */
+       return !git_config_get_index_threads(&val) && val != 1;
+}
+
 /*
  * On success, `tempfile` is closed. If it is the temporary file
  * of a `struct lock_file`, we will therefore effectively perform
@@ -2456,15 +2775,19 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 {
        uint64_t start = getnanotime();
        int newfd = tempfile->fd;
-       git_hash_ctx c;
+       git_hash_ctx c, eoie_c;
        struct cache_header hdr;
        int i, err = 0, removed, extended, hdr_version;
        struct cache_entry **cache = istate->cache;
        int entries = istate->cache_nr;
        struct stat st;
-       struct ondisk_cache_entry_extended ondisk;
+       struct ondisk_cache_entry ondisk;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
        int drop_cache_tree = istate->drop_cache_tree;
+       off_t offset;
+       int ieot_entries = 1;
+       struct index_entry_offset_table *ieot = NULL;
+       int nr, nr_threads;
 
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
@@ -2479,7 +2802,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        }
 
        if (!istate->version) {
-               istate->version = get_index_format_default();
+               istate->version = get_index_format_default(the_repository);
                if (git_env_bool("GIT_TEST_SPLIT_INDEX", 0))
                        init_split_index(istate);
        }
@@ -2498,6 +2821,46 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
                return -1;
 
+       if (!HAVE_THREADS || git_config_get_index_threads(&nr_threads))
+               nr_threads = 1;
+
+       if (nr_threads != 1 && record_ieot()) {
+               int ieot_blocks, cpus;
+
+               /*
+                * ensure default number of ieot blocks maps evenly to the
+                * default number of threads that will process them leaving
+                * room for the thread to load the index extensions.
+                */
+               if (!nr_threads) {
+                       ieot_blocks = istate->cache_nr / THREAD_COST;
+                       cpus = online_cpus();
+                       if (ieot_blocks > cpus - 1)
+                               ieot_blocks = cpus - 1;
+               } else {
+                       ieot_blocks = nr_threads;
+                       if (ieot_blocks > istate->cache_nr)
+                               ieot_blocks = istate->cache_nr;
+               }
+
+               /*
+                * no reason to write out the IEOT extension if we don't
+                * have enough blocks to utilize multi-threading
+                */
+               if (ieot_blocks > 1) {
+                       ieot = xcalloc(1, sizeof(struct index_entry_offset_table)
+                               + (ieot_blocks * sizeof(struct index_entry_offset)));
+                       ieot_entries = DIV_ROUND_UP(entries, ieot_blocks);
+               }
+       }
+
+       offset = lseek(newfd, 0, SEEK_CUR);
+       if (offset < 0) {
+               free(ieot);
+               return -1;
+       }
+       offset += write_buffer_len;
+       nr = 0;
        previous_name = (hdr_version == 4) ? &previous_name_buf : NULL;
 
        for (i = 0; i < entries; i++) {
@@ -2505,7 +2868,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                if (ce->ce_flags & CE_REMOVE)
                        continue;
                if (!ce_uptodate(ce) && is_racy_timestamp(istate, ce))
-                       ce_smudge_racily_clean_entry(ce);
+                       ce_smudge_racily_clean_entry(istate, ce);
                if (is_null_oid(&ce->oid)) {
                        static const char msg[] = "cache entry has null sha1: %s";
                        static int allow = -1;
@@ -2519,23 +2882,78 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
 
                        drop_cache_tree = 1;
                }
+               if (ieot && i && (i % ieot_entries == 0)) {
+                       ieot->entries[ieot->nr].nr = nr;
+                       ieot->entries[ieot->nr].offset = offset;
+                       ieot->nr++;
+                       /*
+                        * If we have a V4 index, set the first byte to an invalid
+                        * character to ensure there is nothing common with the previous
+                        * entry
+                        */
+                       if (previous_name)
+                               previous_name->buf[0] = 0;
+                       nr = 0;
+                       offset = lseek(newfd, 0, SEEK_CUR);
+                       if (offset < 0) {
+                               free(ieot);
+                               return -1;
+                       }
+                       offset += write_buffer_len;
+               }
                if (ce_write_entry(&c, newfd, ce, previous_name, (struct ondisk_cache_entry *)&ondisk) < 0)
                        err = -1;
 
                if (err)
                        break;
+               nr++;
+       }
+       if (ieot && nr) {
+               ieot->entries[ieot->nr].nr = nr;
+               ieot->entries[ieot->nr].offset = offset;
+               ieot->nr++;
        }
        strbuf_release(&previous_name_buf);
 
-       if (err)
+       if (err) {
+               free(ieot);
                return err;
+       }
 
        /* Write extension data here */
-       if (!strip_extensions && istate->split_index) {
+       offset = lseek(newfd, 0, SEEK_CUR);
+       if (offset < 0) {
+               free(ieot);
+               return -1;
+       }
+       offset += write_buffer_len;
+       the_hash_algo->init_fn(&eoie_c);
+
+       /*
+        * Lets write out CACHE_EXT_INDEXENTRYOFFSETTABLE first so that we
+        * can minimize the number of extensions we have to scan through to
+        * find it during load.  Write it out regardless of the
+        * strip_extensions parameter as we need it when loading the shared
+        * index.
+        */
+       if (ieot) {
+               struct strbuf sb = STRBUF_INIT;
+
+               write_ieot_extension(&sb, ieot);
+               err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_INDEXENTRYOFFSETTABLE, sb.len) < 0
+                       || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+               strbuf_release(&sb);
+               free(ieot);
+               if (err)
+                       return -1;
+       }
+
+       if (!strip_extensions && istate->split_index &&
+           !is_null_oid(&istate->split_index->base_oid)) {
                struct strbuf sb = STRBUF_INIT;
 
                err = write_link_extension(&sb, istate) < 0 ||
-                       write_index_ext_header(&c, newfd, CACHE_EXT_LINK,
+                       write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_LINK,
                                               sb.len) < 0 ||
                        ce_write(&c, newfd, sb.buf, sb.len) < 0;
                strbuf_release(&sb);
@@ -2546,7 +2964,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                struct strbuf sb = STRBUF_INIT;
 
                cache_tree_write(&sb, istate->cache_tree);
-               err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0
+               err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_TREE, sb.len) < 0
                        || ce_write(&c, newfd, sb.buf, sb.len) < 0;
                strbuf_release(&sb);
                if (err)
@@ -2556,7 +2974,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                struct strbuf sb = STRBUF_INIT;
 
                resolve_undo_write(&sb, istate->resolve_undo);
-               err = write_index_ext_header(&c, newfd, CACHE_EXT_RESOLVE_UNDO,
+               err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_RESOLVE_UNDO,
                                             sb.len) < 0
                        || ce_write(&c, newfd, sb.buf, sb.len) < 0;
                strbuf_release(&sb);
@@ -2567,7 +2985,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                struct strbuf sb = STRBUF_INIT;
 
                write_untracked_extension(&sb, istate->untracked);
-               err = write_index_ext_header(&c, newfd, CACHE_EXT_UNTRACKED,
+               err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_UNTRACKED,
                                             sb.len) < 0 ||
                        ce_write(&c, newfd, sb.buf, sb.len) < 0;
                strbuf_release(&sb);
@@ -2578,7 +2996,24 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                struct strbuf sb = STRBUF_INIT;
 
                write_fsmonitor_extension(&sb, istate);
-               err = write_index_ext_header(&c, newfd, CACHE_EXT_FSMONITOR, sb.len) < 0
+               err = write_index_ext_header(&c, &eoie_c, newfd, CACHE_EXT_FSMONITOR, sb.len) < 0
+                       || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+               strbuf_release(&sb);
+               if (err)
+                       return -1;
+       }
+
+       /*
+        * CACHE_EXT_ENDOFINDEXENTRIES must be written as the last entry before the SHA1
+        * so that it can be found and processed before all the index entries are
+        * read.  Write it out regardless of the strip_extensions parameter as we need it
+        * when loading the shared index.
+        */
+       if (offset && record_eoie()) {
+               struct strbuf sb = STRBUF_INIT;
+
+               write_eoie_extension(&sb, &eoie_c, offset);
+               err = write_index_ext_header(&c, NULL, newfd, CACHE_EXT_ENDOFINDEXENTRIES, sb.len) < 0
                        || ce_write(&c, newfd, sb.buf, sb.len) < 0;
                strbuf_release(&sb);
                if (err)
@@ -2596,6 +3031,16 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        istate->timestamp.sec = (unsigned int)st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
        trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
+
+       /*
+        * TODO trace2: replace "the_repository" with the actual repo instance
+        * that is associated with the given "istate".
+        */
+       trace2_data_intmax("index", the_repository, "write/version",
+                          istate->version);
+       trace2_data_intmax("index", the_repository, "write/cache_nr",
+                          istate->cache_nr);
+
        return 0;
 }
 
@@ -2615,12 +3060,32 @@ static int commit_locked_index(struct lock_file *lk)
 static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
                                 unsigned flags)
 {
-       int ret = do_write_index(istate, lock->tempfile, 0);
+       int ret;
+
+       /*
+        * TODO trace2: replace "the_repository" with the actual repo instance
+        * that is associated with the given "istate".
+        */
+       trace2_region_enter_printf("index", "do_write_index", the_repository,
+                                  "%s", lock->tempfile->filename.buf);
+       ret = do_write_index(istate, lock->tempfile, 0);
+       trace2_region_leave_printf("index", "do_write_index", the_repository,
+                                  "%s", lock->tempfile->filename.buf);
+
        if (ret)
                return ret;
        if (flags & COMMIT_LOCK)
-               return commit_locked_index(lock);
-       return close_lock_file_gently(lock);
+               ret = commit_locked_index(lock);
+       else
+               ret = close_lock_file_gently(lock);
+
+       run_hook_le(NULL, "post-index-change",
+                       istate->updated_workdir ? "1" : "0",
+                       istate->updated_skipworktree ? "1" : "0", NULL);
+       istate->updated_workdir = 0;
+       istate->updated_skipworktree = 0;
+
+       return ret;
 }
 
 static int write_split_index(struct index_state *istate,
@@ -2700,12 +3165,18 @@ static int write_shared_index(struct index_state *istate,
        int ret;
 
        move_cache_to_base_index(istate);
+
+       trace2_region_enter_printf("index", "shared/do_write_index",
+                                  the_repository, "%s", (*temp)->filename.buf);
        ret = do_write_index(si->base, *temp, 1);
+       trace2_region_leave_printf("index", "shared/do_write_index",
+                                  the_repository, "%s", (*temp)->filename.buf);
+
        if (ret)
                return ret;
        ret = adjust_shared_perm(get_tempfile_path(*temp));
        if (ret) {
-               error("cannot fix permission bits on %s", get_tempfile_path(*temp));
+               error(_("cannot fix permission bits on '%s'"), get_tempfile_path(*temp));
                return ret;
        }
        ret = rename_tempfile(temp,
@@ -2754,6 +3225,9 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
        int new_shared_index, ret;
        struct split_index *si = istate->split_index;
 
+       if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
+               cache_tree_verify(the_repository, istate);
+
        if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
                if (flags & COMMIT_LOCK)
                        rollback_lock_file(lock);
@@ -2785,7 +3259,8 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
                struct tempfile *temp;
                int saved_errno;
 
-               temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
+               /* Same initial permissions as the main .git/index file */
+               temp = mks_tempfile_sm(git_path("sharedindex_XXXXXX"), 0, 0666);
                if (!temp) {
                        oidclr(&si->base_oid);
                        ret = do_write_locked_index(istate, lock, flags);
@@ -2805,7 +3280,7 @@ int write_locked_index(struct index_state *istate, struct lock_file *lock,
        ret = write_split_index(istate, lock, flags);
 
        /* Freshen the shared index only if the split-index was written */
-       if (!ret && !new_shared_index) {
+       if (!ret && !new_shared_index && !is_null_oid(&si->base_oid)) {
                const char *shared_index = git_path("sharedindex.%s",
                                                    oid_to_hex(&si->base_oid));
                freshen_shared_index(shared_index, 1);
@@ -2827,12 +3302,14 @@ out:
  * state can call this and check its return value, instead of calling
  * read_cache().
  */
-int read_index_unmerged(struct index_state *istate)
+int repo_read_index_unmerged(struct repository *repo)
 {
+       struct index_state *istate;
        int i;
        int unmerged = 0;
 
-       read_index(istate);
+       repo_read_index(repo);
+       istate = repo->index;
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i];
                struct cache_entry *new_ce;
@@ -2848,7 +3325,7 @@ int read_index_unmerged(struct index_state *istate)
                new_ce->ce_namelen = len;
                new_ce->ce_mode = ce->ce_mode;
                if (add_index_entry(istate, new_ce, ADD_CACHE_SKIP_DFCHECK))
-                       return error("%s: cannot drop to stage #0",
+                       return error(_("%s: cannot drop to stage #0"),
                                     new_ce->name);
        }
        return unmerged;
@@ -2950,6 +3427,8 @@ void move_index_extensions(struct index_state *dst, struct index_state *src)
 {
        dst->untracked = src->untracked;
        src->untracked = NULL;
+       dst->cache_tree = src->cache_tree;
+       src->cache_tree = NULL;
 }
 
 struct cache_entry *dup_cache_entry(const struct cache_entry *ce,
@@ -2989,3 +3468,179 @@ int should_validate_cache_entries(void)
 
        return validate_index_cache_entries;
 }
+
+#define EOIE_SIZE (4 + GIT_SHA1_RAWSZ) /* <4-byte offset> + <20-byte hash> */
+#define EOIE_SIZE_WITH_HEADER (4 + 4 + EOIE_SIZE) /* <4-byte signature> + <4-byte length> + EOIE_SIZE */
+
+static size_t read_eoie_extension(const char *mmap, size_t mmap_size)
+{
+       /*
+        * The end of index entries (EOIE) extension is guaranteed to be last
+        * so that it can be found by scanning backwards from the EOF.
+        *
+        * "EOIE"
+        * <4-byte length>
+        * <4-byte offset>
+        * <20-byte hash>
+        */
+       const char *index, *eoie;
+       uint32_t extsize;
+       size_t offset, src_offset;
+       unsigned char hash[GIT_MAX_RAWSZ];
+       git_hash_ctx c;
+
+       /* ensure we have an index big enough to contain an EOIE extension */
+       if (mmap_size < sizeof(struct cache_header) + EOIE_SIZE_WITH_HEADER + the_hash_algo->rawsz)
+               return 0;
+
+       /* validate the extension signature */
+       index = eoie = mmap + mmap_size - EOIE_SIZE_WITH_HEADER - the_hash_algo->rawsz;
+       if (CACHE_EXT(index) != CACHE_EXT_ENDOFINDEXENTRIES)
+               return 0;
+       index += sizeof(uint32_t);
+
+       /* validate the extension size */
+       extsize = get_be32(index);
+       if (extsize != EOIE_SIZE)
+               return 0;
+       index += sizeof(uint32_t);
+
+       /*
+        * Validate the offset we're going to look for the first extension
+        * signature is after the index header and before the eoie extension.
+        */
+       offset = get_be32(index);
+       if (mmap + offset < mmap + sizeof(struct cache_header))
+               return 0;
+       if (mmap + offset >= eoie)
+               return 0;
+       index += sizeof(uint32_t);
+
+       /*
+        * The hash is computed over extension types and their sizes (but not
+        * their contents).  E.g. if we have "TREE" extension that is N-bytes
+        * long, "REUC" extension that is M-bytes long, followed by "EOIE",
+        * then the hash would be:
+        *
+        * SHA-1("TREE" + <binary representation of N> +
+        *       "REUC" + <binary representation of M>)
+        */
+       src_offset = offset;
+       the_hash_algo->init_fn(&c);
+       while (src_offset < mmap_size - the_hash_algo->rawsz - EOIE_SIZE_WITH_HEADER) {
+               /* After an array of active_nr index entries,
+                * there can be arbitrary number of extended
+                * sections, each of which is prefixed with
+                * extension name (4-byte) and section length
+                * in 4-byte network byte order.
+                */
+               uint32_t extsize;
+               memcpy(&extsize, mmap + src_offset + 4, 4);
+               extsize = ntohl(extsize);
+
+               /* verify the extension size isn't so large it will wrap around */
+               if (src_offset + 8 + extsize < src_offset)
+                       return 0;
+
+               the_hash_algo->update_fn(&c, mmap + src_offset, 8);
+
+               src_offset += 8;
+               src_offset += extsize;
+       }
+       the_hash_algo->final_fn(hash, &c);
+       if (!hasheq(hash, (const unsigned char *)index))
+               return 0;
+
+       /* Validate that the extension offsets returned us back to the eoie extension. */
+       if (src_offset != mmap_size - the_hash_algo->rawsz - EOIE_SIZE_WITH_HEADER)
+               return 0;
+
+       return offset;
+}
+
+static void write_eoie_extension(struct strbuf *sb, git_hash_ctx *eoie_context, size_t offset)
+{
+       uint32_t buffer;
+       unsigned char hash[GIT_MAX_RAWSZ];
+
+       /* offset */
+       put_be32(&buffer, offset);
+       strbuf_add(sb, &buffer, sizeof(uint32_t));
+
+       /* hash */
+       the_hash_algo->final_fn(hash, eoie_context);
+       strbuf_add(sb, hash, the_hash_algo->rawsz);
+}
+
+#define IEOT_VERSION   (1)
+
+static struct index_entry_offset_table *read_ieot_extension(const char *mmap, size_t mmap_size, size_t offset)
+{
+       const char *index = NULL;
+       uint32_t extsize, ext_version;
+       struct index_entry_offset_table *ieot;
+       int i, nr;
+
+       /* find the IEOT extension */
+       if (!offset)
+               return NULL;
+       while (offset <= mmap_size - the_hash_algo->rawsz - 8) {
+               extsize = get_be32(mmap + offset + 4);
+               if (CACHE_EXT((mmap + offset)) == CACHE_EXT_INDEXENTRYOFFSETTABLE) {
+                       index = mmap + offset + 4 + 4;
+                       break;
+               }
+               offset += 8;
+               offset += extsize;
+       }
+       if (!index)
+               return NULL;
+
+       /* validate the version is IEOT_VERSION */
+       ext_version = get_be32(index);
+       if (ext_version != IEOT_VERSION) {
+               error("invalid IEOT version %d", ext_version);
+               return NULL;
+       }
+       index += sizeof(uint32_t);
+
+       /* extension size - version bytes / bytes per entry */
+       nr = (extsize - sizeof(uint32_t)) / (sizeof(uint32_t) + sizeof(uint32_t));
+       if (!nr) {
+               error("invalid number of IEOT entries %d", nr);
+               return NULL;
+       }
+       ieot = xmalloc(sizeof(struct index_entry_offset_table)
+                      + (nr * sizeof(struct index_entry_offset)));
+       ieot->nr = nr;
+       for (i = 0; i < nr; i++) {
+               ieot->entries[i].offset = get_be32(index);
+               index += sizeof(uint32_t);
+               ieot->entries[i].nr = get_be32(index);
+               index += sizeof(uint32_t);
+       }
+
+       return ieot;
+}
+
+static void write_ieot_extension(struct strbuf *sb, struct index_entry_offset_table *ieot)
+{
+       uint32_t buffer;
+       int i;
+
+       /* version */
+       put_be32(&buffer, IEOT_VERSION);
+       strbuf_add(sb, &buffer, sizeof(uint32_t));
+
+       /* ieot */
+       for (i = 0; i < ieot->nr; i++) {
+
+               /* offset */
+               put_be32(&buffer, ieot->entries[i].offset);
+               strbuf_add(sb, &buffer, sizeof(uint32_t));
+
+               /* count */
+               put_be32(&buffer, ieot->entries[i].nr);
+               strbuf_add(sb, &buffer, sizeof(uint32_t));
+       }
+}