read-cache: fix reading the shared index for other repos
authorThomas Gummerer <t.gummerer@gmail.com>
Sun, 7 Jan 2018 22:30:13 +0000 (22:30 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Jan 2018 18:36:34 +0000 (10:36 -0800)
read_index_from() takes a path argument for the location of the index
file. For reading the shared index in split index mode however it just
ignores that path argument, and reads it from the gitdir of the current
repository.

This works as long as an index in the_repository is read. Once that
changes, such as when we read the index of a submodule, or of a
different working tree than the current one, the gitdir of
the_repository will no longer contain the appropriate shared index,
and git will fail to read it.

For example t3007-ls-files-recurse-submodules.sh was broken with
GIT_TEST_SPLIT_INDEX set in 188dce131f ("ls-files: use repository
object", 2017-06-22), and t7814-grep-recurse-submodules.sh was also
broken in a similar manner, probably by introducing struct repository
there, although I didn't track down the exact commit for that.

be489d02d2 ("revision.c: --indexed-objects add objects from all
worktrees", 2017-08-23) breaks with split index mode in a similar
manner, not erroring out when it can't read the index, but instead
carrying on with pruning, without taking the index of the worktree into
account.

Fix this by passing an additional gitdir parameter to read_index_from,
to indicate where it should look for and read the shared index from.

read_cache_from() defaults to using the gitdir of the_repository. As it
is mostly a convenience macro, having to pass get_git_dir() for every
call seems overkill, and if necessary users can have more control by
using read_index_from().

Helped-by: Brandon Williams <bmwill@google.com>
Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
cache-tree.c
cache.h
read-cache.c
repository.c
revision.c
index d3f7401278bd5130558dde18da1235c188bb7303..e006215edc3a593fdbe31a169ed42c097430100b 100644 (file)
@@ -608,7 +608,7 @@ int write_index_as_tree(unsigned char *sha1, struct index_state *index_state, co
 
        newfd = hold_lock_file_for_update(&lock_file, index_path, LOCK_DIE_ON_ERROR);
 
-       entries = read_index_from(index_state, index_path);
+       entries = read_index_from(index_state, index_path, get_git_dir());
        if (entries < 0) {
                ret = WRITE_TREE_UNREADABLE_INDEX;
                goto out;
diff --git a/cache.h b/cache.h
index 6440e2bf21f5800db98f82fcedff46478188674e..bcf0fc55fd1560ded71710e7582420eaf678d3a2 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -364,7 +364,7 @@ extern void free_name_hash(struct index_state *istate);
 #define active_cache_tree (the_index.cache_tree)
 
 #define read_cache() read_index(&the_index)
-#define read_cache_from(path) read_index_from(&the_index, (path))
+#define read_cache_from(path) read_index_from(&the_index, (path), (get_git_dir()))
 #define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec))
 #define is_cache_unborn() is_index_unborn(&the_index)
 #define read_cache_unmerged() read_index_unmerged(&the_index)
@@ -599,7 +599,8 @@ extern int read_index(struct index_state *);
 extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
 extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
-extern int read_index_from(struct index_state *, const char *path);
+extern int read_index_from(struct index_state *, const char *path,
+                          const char *gitdir);
 extern int is_index_unborn(struct index_state *);
 extern int read_index_unmerged(struct index_state *);
 #define COMMIT_LOCK            (1 << 0)
index 65f4fe8375d59234d5e58f87a8593fc50e6336a2..1248a09de4212747aa01f477ee090708731e33fe 100644 (file)
@@ -1568,7 +1568,7 @@ int hold_locked_index(struct lock_file *lk, int lock_flags)
 
 int read_index(struct index_state *istate)
 {
-       return read_index_from(istate, get_index_file());
+       return read_index_from(istate, get_index_file(), get_git_dir());
 }
 
 static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
@@ -1824,20 +1824,19 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
  * This way, shared index can be removed if they have not been used
  * for some time.
  */
-static void freshen_shared_index(char *base_sha1_hex, int warn)
+static void freshen_shared_index(const char *shared_index, int warn)
 {
-       char *shared_index = git_pathdup("sharedindex.%s", base_sha1_hex);
        if (!check_and_freshen_file(shared_index, 1) && warn)
                warning("could not freshen shared index '%s'", shared_index);
-       free(shared_index);
 }
 
-int read_index_from(struct index_state *istate, const char *path)
+int read_index_from(struct index_state *istate, const char *path,
+                   const char *gitdir)
 {
        struct split_index *split_index;
        int ret;
        char *base_sha1_hex;
-       const char *base_path;
+       char *base_path;
 
        /* istate->initialized covers both .git/index and .git/sharedindex.xxx */
        if (istate->initialized)
@@ -1857,16 +1856,17 @@ int read_index_from(struct index_state *istate, const char *path)
                split_index->base = xcalloc(1, sizeof(*split_index->base));
 
        base_sha1_hex = sha1_to_hex(split_index->base_sha1);
-       base_path = git_path("sharedindex.%s", base_sha1_hex);
+       base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_sha1_hex);
        ret = do_read_index(split_index->base, base_path, 1);
        if (hashcmp(split_index->base_sha1, split_index->base->sha1))
                die("broken index, expect %s in %s, got %s",
                    base_sha1_hex, base_path,
                    sha1_to_hex(split_index->base->sha1));
 
-       freshen_shared_index(base_sha1_hex, 0);
+       freshen_shared_index(base_path, 0);
        merge_base_index(istate);
        post_read_index_from(istate);
+       free(base_path);
        return ret;
 }
 
@@ -2521,8 +2521,11 @@ 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)
-               freshen_shared_index(sha1_to_hex(si->base_sha1), 1);
+       if (!ret && !new_shared_index) {
+               const char *shared_index = git_path("sharedindex.%s",
+                                                   sha1_to_hex(si->base_sha1));
+               freshen_shared_index(shared_index, 1);
+       }
 
        return ret;
 }
index bb2fae5446b7ea8d2bfac87faa30c165f714d121..161e2d712aa29625bc6f8d616c5827258922d54a 100644 (file)
@@ -229,5 +229,5 @@ int repo_read_index(struct repository *repo)
        if (!repo->index)
                repo->index = xcalloc(1, sizeof(*repo->index));
 
-       return read_index_from(repo->index, repo->index_file);
+       return read_index_from(repo->index, repo->index_file, repo->gitdir);
 }
index d167223e694e54626786740954454d4973e28752..d6a89c5af1a05ea169b9b0afab36dbadf3915b00 100644 (file)
@@ -1343,7 +1343,8 @@ void add_index_objects_to_pending(struct rev_info *revs, unsigned int flags)
                        continue; /* current index already taken care of */
 
                if (read_index_from(&istate,
-                                   worktree_git_path(wt, "index")) > 0)
+                                   worktree_git_path(wt, "index"),
+                                   get_worktree_git_dir(wt)) > 0)
                        do_add_index_objects_to_pending(revs, &istate);
                discard_index(&istate);
        }