From 8cc21ce78c2f3781024117047c0650861f890213 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 20 Apr 2009 03:58:17 -0700 Subject: read-tree A B: do not corrupt cache-tree An earlier commit aab3b9a (read-tree A B C: do not create a bogus index and do not segfault, 2009-03-12) resurrected the support for an obscure (but useful) feature to read and overlay more than one tree into the index without the -m (merge) option. But the fix was not enough. Exercising this feature exposes a longstanding bug in the code that primes the cache-tree in the index from the tree that was read. The intention was that when we know that the index must exactly match the tree we just read, we prime the entire cache-tree with it. However, the logic to detect that case incorrectly triggered if you read two trees without -m. This resulted in a corrupted cache-tree, and write-tree would have produced an incorrect tree object out of such an index. Signed-off-by: Junio C Hamano --- builtin-read-tree.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'builtin-read-tree.c') diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 38fef34d3f..e4e0e710c8 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -211,7 +211,6 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) case 3: default: opts.fn = threeway_merge; - cache_tree_free(&active_cache_tree); break; } @@ -221,6 +220,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) opts.head_idx = 1; } + cache_tree_free(&active_cache_tree); for (i = 0; i < nr_trees; i++) { struct tree *tree = trees[i]; parse_tree(tree); @@ -235,10 +235,8 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) * valid cache-tree because the index must match exactly * what came from the tree. */ - if (nr_trees && !opts.prefix && (!opts.merge || (stage == 2))) { - cache_tree_free(&active_cache_tree); + if (nr_trees == 1 && !opts.prefix) prime_cache_tree(); - } if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) -- cgit v1.2.1 From b9d37a5420446d0db2dc0dc5458a5e50656a4852 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 20 Apr 2009 03:58:18 -0700 Subject: Move prime_cache_tree() to cache-tree.c The interface to build cache-tree belongs there. Signed-off-by: Junio C Hamano --- builtin-read-tree.c | 37 +------------------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) (limited to 'builtin-read-tree.c') diff --git a/builtin-read-tree.c b/builtin-read-tree.c index e4e0e710c8..9cd7d0738e 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -29,41 +29,6 @@ static int list_tree(unsigned char *sha1) return 0; } -static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) -{ - struct tree_desc desc; - struct name_entry entry; - int cnt; - - hashcpy(it->sha1, tree->object.sha1); - init_tree_desc(&desc, tree->buffer, tree->size); - cnt = 0; - while (tree_entry(&desc, &entry)) { - if (!S_ISDIR(entry.mode)) - cnt++; - else { - struct cache_tree_sub *sub; - struct tree *subtree = lookup_tree(entry.sha1); - if (!subtree->object.parsed) - parse_tree(subtree); - sub = cache_tree_sub(it, entry.path); - sub->cache_tree = cache_tree(); - prime_cache_tree_rec(sub->cache_tree, subtree); - cnt += sub->cache_tree->entry_count; - } - } - it->entry_count = cnt; -} - -static void prime_cache_tree(void) -{ - if (!nr_trees) - return; - active_cache_tree = cache_tree(); - prime_cache_tree_rec(active_cache_tree, trees[0]); - -} - static const char read_tree_usage[] = "git read-tree ( | [[-m [--trivial] [--aggressive] | --reset | --prefix=] [-u | -i]] [--exclude-per-directory=] [--index-output=] [ []])"; static struct lock_file lock_file; @@ -236,7 +201,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) * what came from the tree. */ if (nr_trees == 1 && !opts.prefix) - prime_cache_tree(); + prime_cache_tree(&active_cache_tree, trees[0]); if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) -- cgit v1.2.1 From 456156dc068b7664c08e35157e17a6440ec68f32 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Mon, 20 Apr 2009 03:58:19 -0700 Subject: read-tree -m A B: prime cache-tree from the switched-to tree When switching to a new branch with "read-tree -m A B", the resulting index must match tree B and we can prime the cache tree with it. Signed-off-by: Junio C Hamano --- builtin-read-tree.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'builtin-read-tree.c') diff --git a/builtin-read-tree.c b/builtin-read-tree.c index 9cd7d0738e..391d709704 100644 --- a/builtin-read-tree.c +++ b/builtin-read-tree.c @@ -199,9 +199,14 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix) * "-m ent" or "--reset ent" form), we can obtain a fully * valid cache-tree because the index must match exactly * what came from the tree. + * + * The same holds true if we are switching between two trees + * using read-tree -m A B. The index must match B after that. */ if (nr_trees == 1 && !opts.prefix) prime_cache_tree(&active_cache_tree, trees[0]); + else if (nr_trees == 2 && opts.merge) + prime_cache_tree(&active_cache_tree, trees[1]); if (write_cache(newfd, active_cache, active_nr) || commit_locked_index(&lock_file)) -- cgit v1.2.1