split-index: don't write cache tree with null oid entries
authorThomas Gummerer <t.gummerer@gmail.com>
Sun, 7 Jan 2018 22:30:14 +0000 (22:30 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 19 Jan 2018 18:36:39 +0000 (10:36 -0800)
In a96d3cc3f6 ("cache-tree: reject entries with null sha1", 2017-04-21)
we made sure that broken cache entries do not get propagated to new
trees. Part of that was making sure not to re-use an existing cache
tree that includes a null oid.

It did so by dropping the cache tree in 'do_write_index()' if one of
the entries contains a null oid. In split index mode however, there
are two invocations to 'do_write_index()', one for the shared index
and one for the split index. The cache tree is only written once, to
the split index.

As we only loop through the elements that are effectively being
written by the current invocation, that may not include the entry with
a null oid in the split index (when it is already written to the
shared index), where we write the cache tree. Therefore in split
index mode we may still end up writing the cache tree, even though
there is an entry with a null oid in the index.

Fix this by checking for null oids in prepare_to_write_split_index,
where we loop the entries of the shared index as well as the entries for
the split index.

This fixes t7009 with GIT_TEST_SPLIT_INDEX. Also add a new test that's
more specifically showing the problem.

Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
cache.h
read-cache.c
split-index.c
t/t1700-split-index.sh
diff --git a/cache.h b/cache.h
index bcf0fc55fd1560ded71710e7582420eaf678d3a2..add5f9f50ac75828221b42392441d086b1df1e9d 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -340,7 +340,8 @@ struct index_state {
        struct split_index *split_index;
        struct cache_time timestamp;
        unsigned name_hash_initialized : 1,
-                initialized : 1;
+                initialized : 1,
+                drop_cache_tree : 1;
        struct hashmap name_hash;
        struct hashmap dir_hash;
        unsigned char sha1[20];
index 1248a09de4212747aa01f477ee090708731e33fe..5cd14e2f726489f331425ff762068bb1c184a665 100644 (file)
@@ -2199,7 +2199,7 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
        struct stat st;
        struct ondisk_cache_entry_extended ondisk;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
-       int drop_cache_tree = 0;
+       int drop_cache_tree = istate->drop_cache_tree;
 
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
index 83e39ec8d7739816188ba909a4cb9da302d48f73..284d04d67f885d8905130e138c45cc4ff4fbdc30 100644 (file)
@@ -238,6 +238,8 @@ void prepare_to_write_split_index(struct index_state *istate)
                                ALLOC_GROW(entries, nr_entries+1, nr_alloc);
                                entries[nr_entries++] = ce;
                        }
+                       if (is_null_oid(&ce->oid))
+                               istate->drop_cache_tree = 1;
                }
        }
 
index 22f69a410ba8194bbdff70471f5b3e746af116da..322721dd646b408fdb4c63d9a91427769a44608a 100755 (executable)
@@ -400,4 +400,23 @@ done <<\EOF
 0642 -rw-r---w-
 EOF
 
+test_expect_success 'writing split index with null sha1 does not write cache tree' '
+       git config core.splitIndex true &&
+       git config splitIndex.maxPercentChange 0 &&
+       git commit -m "commit" &&
+       {
+               git ls-tree HEAD &&
+               printf "160000 commit $_z40\\tbroken\\n"
+       } >broken-tree &&
+       echo "add broken entry" >msg &&
+
+       tree=$(git mktree <broken-tree) &&
+       test_tick &&
+       commit=$(git commit-tree $tree -p HEAD <msg) &&
+       git update-ref HEAD "$commit" &&
+       GIT_ALLOW_NULL_SHA1=1 git reset --hard &&
+       (test-dump-cache-tree >cache-tree.out || true) &&
+       test_line_count = 0 cache-tree.out
+'
+
 test_done