X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=read-tree.c;h=aa6172b52eeadb4f118e5145c182270342a70bf0;hb=aedb8995f841949ce29e05ea7e5c03c2d5466089;hp=ab516824ef92cd66146ca3d453f3461119e41155;hpb=b34c39cf31e370dad3bcfba29ee8cd023c40fd6b;p=git.git diff --git a/read-tree.c b/read-tree.c index ab516824e..aa6172b52 100644 --- a/read-tree.c +++ b/read-tree.c @@ -13,6 +13,7 @@ #include #include +static int reset = 0; static int merge = 0; static int update = 0; static int index_only = 0; @@ -21,6 +22,7 @@ static int trivial_merges_only = 0; static int aggressive = 0; static int verbose_update = 0; static volatile int progress_update = 0; +static const char *prefix = NULL; static int head_idx = -1; static int merge_size = 0; @@ -369,7 +371,8 @@ static int unpack_trees(merge_fn_t fn) posns[i] = ((struct tree *) posn->item)->entries; posn = posn->next; } - if (unpack_trees_rec(posns, len, "", fn, &indpos)) + if (unpack_trees_rec(posns, len, prefix ? prefix : "", + fn, &indpos)) return -1; } @@ -417,6 +420,10 @@ static void verify_uptodate(struct cache_entry *ce) return; errno = 0; } + if (reset) { + ce->ce_flags |= htons(CE_UPDATE); + return; + } if (errno == ENOENT) return; die("Entry '%s' not uptodate. Cannot merge.", ce->name); @@ -446,6 +453,8 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old) invalidate_ce_path(old); } } + else + invalidate_ce_path(merge); merge->ce_flags &= ~htons(CE_STAGEMASK); add_cache_entry(merge, ADD_CACHE_OK_TO_ADD); return 1; @@ -677,6 +686,28 @@ static int twoway_merge(struct cache_entry **src) return deleted_entry(oldtree, current); } +/* + * Bind merge. + * + * Keep the index entries at stage0, collapse stage1 but make sure + * stage0 does not have anything in prefix. + */ +static int bind_merge(struct cache_entry **src) +{ + struct cache_entry *old = src[0]; + struct cache_entry *a = src[1]; + + if (merge_size != 1) + return error("Cannot do a bind merge of %d trees\n", + merge_size); + if (!a) + return merged_entry(old, NULL); + if (old) + die("Entry '%s' overlaps. Cannot bind.", a->name); + + return merged_entry(a, NULL); +} + /* * One-way merge. * @@ -694,9 +725,15 @@ static int oneway_merge(struct cache_entry **src) if (!a) { invalidate_ce_path(old); - return 0; + return deleted_entry(old, NULL); } if (old && same(old, a)) { + if (reset) { + struct stat st; + if (lstat(old->name, &st) || + ce_match_stat(old, &st, 1)) + old->ce_flags |= htons(CE_UPDATE); + } return keep_entry(old); } return merged_entry(a, NULL); @@ -725,13 +762,46 @@ static int read_cache_unmerged(void) return deleted; } -static const char read_tree_usage[] = "git-read-tree ( | -m [--aggressive] [-u | -i] [ []])"; +static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree) +{ + struct tree_entry_list *ent; + int cnt; + + memcpy(it->sha1, tree->object.sha1, 20); + for (cnt = 0, ent = tree->entries; ent; ent = ent->next) { + if (!ent->directory) + cnt++; + else { + struct cache_tree_sub *sub; + struct tree *subtree = (struct tree *)ent->item.tree; + if (!subtree->object.parsed) + parse_tree(subtree); + sub = cache_tree_sub(it, ent->name); + 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) +{ + struct tree *tree = (struct tree *)trees->item; + if (!tree) + return; + active_cache_tree = cache_tree(); + prime_cache_tree_rec(active_cache_tree, tree); + +} + +static const char read_tree_usage[] = "git-read-tree ( | [[-m [--aggressive] | --reset | --prefix=] [-u | -i]] [ []])"; static struct cache_file cache_file; int main(int argc, char **argv) { - int i, newfd, reset, stage = 0; + int i, newfd, stage = 0; unsigned char sha1[20]; merge_fn_t fn = NULL; @@ -770,9 +840,24 @@ int main(int argc, char **argv) continue; } + /* "--prefix=/" means keep the current index + * entries and put the entries from the tree under the + * given subdirectory. + */ + if (!strncmp(arg, "--prefix=", 9)) { + if (stage || merge || prefix) + usage(read_tree_usage); + prefix = arg + 9; + merge = 1; + stage = 1; + if (read_cache_unmerged()) + die("you need to resolve your current index first"); + continue; + } + /* This differs from "-m" in that we'll silently ignore unmerged entries */ if (!strcmp(arg, "--reset")) { - if (stage || merge) + if (stage || merge || prefix) usage(read_tree_usage); reset = 1; merge = 1; @@ -793,7 +878,7 @@ int main(int argc, char **argv) /* "-m" stands for "merge", meaning we start in stage 1 */ if (!strcmp(arg, "-m")) { - if (stage || merge) + if (stage || merge || prefix) usage(read_tree_usage); if (read_cache_unmerged()) die("you need to resolve your current index first"); @@ -806,8 +891,8 @@ int main(int argc, char **argv) if (1 < index_only + update) usage(read_tree_usage); - if (get_sha1(arg, sha1) < 0) - usage(read_tree_usage); + if (get_sha1(arg, sha1)) + die("Not a valid object name %s", arg); if (list_tree(sha1) < 0) die("failed to unpack tree object %s", arg); stage++; @@ -815,12 +900,31 @@ int main(int argc, char **argv) if ((update||index_only) && !merge) usage(read_tree_usage); + if (prefix) { + int pfxlen = strlen(prefix); + int pos; + if (prefix[pfxlen-1] != '/') + die("prefix must end with /"); + if (stage != 2) + die("binding merge takes only one tree"); + pos = cache_name_pos(prefix, pfxlen); + if (0 <= pos) + die("corrupt index file"); + pos = -pos-1; + if (pos < active_nr && + !strncmp(active_cache[pos]->name, prefix, pfxlen)) + die("subdirectory '%s' already exists.", prefix); + pos = cache_name_pos(prefix, pfxlen-1); + if (0 <= pos) + die("file '%.*s' already exists.", pfxlen-1, prefix); + } + if (merge) { if (stage < 2) die("just how do you expect me to merge %d trees?", stage-1); switch (stage - 1) { case 1: - fn = oneway_merge; + fn = prefix ? bind_merge : oneway_merge; break; case 2: fn = twoway_merge; @@ -839,6 +943,18 @@ int main(int argc, char **argv) } unpack_trees(fn); + + /* + * When reading only one tree (either the most basic form, + * "-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. + */ + if (trees && trees->item && (!merge || (stage == 2))) { + cache_tree_free(&active_cache_tree); + prime_cache_tree(); + } + if (write_cache(newfd, active_cache, active_nr) || commit_index_file(&cache_file)) die("unable to write new index file");