X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=read-tree.c;h=5580f15ba2c89f9fd1ed35de0b0183487d024bf8;hb=8e1618f9612a78ea09b2a926797c781fe06027c9;hp=8c9ffe123255bfeb199ea90f055ac8d1df49ddb8;hpb=e6ee623b7be2a59a3f3d1ff8c513d72b6f15344f;p=git.git diff --git a/read-tree.c b/read-tree.c index 8c9ffe12..5580f15b 100644 --- a/read-tree.c +++ b/read-tree.c @@ -3,97 +3,340 @@ * * Copyright (C) Linus Torvalds, 2005 */ +#define DBRT_DEBUG 1 + #include "cache.h" -static int stage = 0; +#include "object.h" +#include "tree.h" + +static int merge = 0; static int update = 0; +static int index_only = 0; +static int nontrivial_merge = 0; +static int trivial_merges_only = 0; +static int aggressive = 0; -static int unpack_tree(unsigned char *sha1) -{ - void *buffer; - unsigned long size; - int ret; +static int head_idx = -1; +static int merge_size = 0; - buffer = read_object_with_reference(sha1, "tree", &size, NULL); - if (!buffer) - return -1; - ret = read_tree(buffer, size, stage); - free(buffer); +static struct object_list *trees = NULL; + +static struct cache_entry df_conflict_entry = { +}; + +static struct tree_entry_list df_conflict_list = { + .name = NULL, + .next = &df_conflict_list +}; + +typedef int (*merge_fn_t)(struct cache_entry **src); + +static int entcmp(char *name1, int dir1, char *name2, int dir2) +{ + int len1 = strlen(name1); + int len2 = strlen(name2); + int len = len1 < len2 ? len1 : len2; + int ret = memcmp(name1, name2, len); + unsigned char c1, c2; + if (ret) + return ret; + c1 = name1[len]; + c2 = name2[len]; + if (!c1 && dir1) + c1 = '/'; + if (!c2 && dir2) + c2 = '/'; + ret = (c1 < c2) ? -1 : (c1 > c2) ? 1 : 0; + if (c1 && c2 && !ret) + ret = len1 - len2; return ret; } -static char *lockfile_name; - -static void remove_lock_file(void) +static int unpack_trees_rec(struct tree_entry_list **posns, int len, + const char *base, merge_fn_t fn, int *indpos) { - if (lockfile_name) - unlink(lockfile_name); + int baselen = strlen(base); + int src_size = len + 1; + do { + int i; + char *first; + int firstdir = 0; + int pathlen; + unsigned ce_size; + struct tree_entry_list **subposns; + struct cache_entry **src; + int any_files = 0; + int any_dirs = 0; + char *cache_name; + int ce_stage; + + /* Find the first name in the input. */ + + first = NULL; + cache_name = NULL; + + /* Check the cache */ + if (merge && *indpos < active_nr) { + /* This is a bit tricky: */ + /* If the index has a subdirectory (with + * contents) as the first name, it'll get a + * filename like "foo/bar". But that's after + * "foo", so the entry in trees will get + * handled first, at which point we'll go into + * "foo", and deal with "bar" from the index, + * because the base will be "foo/". The only + * way we can actually have "foo/bar" first of + * all the things is if the trees don't + * contain "foo" at all, in which case we'll + * handle "foo/bar" without going into the + * directory, but that's fine (and will return + * an error anyway, with the added unknown + * file case. + */ + + cache_name = active_cache[*indpos]->name; + if (strlen(cache_name) > baselen && + !memcmp(cache_name, base, baselen)) { + cache_name += baselen; + first = cache_name; + } else { + cache_name = NULL; + } + } + +#if DBRT_DEBUG > 1 + if (first) + printf("index %s\n", first); +#endif + for (i = 0; i < len; i++) { + if (!posns[i] || posns[i] == &df_conflict_list) + continue; +#if DBRT_DEBUG > 1 + printf("%d %s\n", i + 1, posns[i]->name); +#endif + if (!first || entcmp(first, firstdir, + posns[i]->name, + posns[i]->directory) > 0) { + first = posns[i]->name; + firstdir = posns[i]->directory; + } + } + /* No name means we're done */ + if (!first) + return 0; + + pathlen = strlen(first); + ce_size = cache_entry_size(baselen + pathlen); + + src = xmalloc(sizeof(struct cache_entry *) * src_size); + memset(src, 0, sizeof(struct cache_entry *) * src_size); + + subposns = xmalloc(sizeof(struct tree_list_entry *) * len); + memset(subposns, 0, sizeof(struct tree_list_entry *) * len); + + if (cache_name && !strcmp(cache_name, first)) { + any_files = 1; + src[0] = active_cache[*indpos]; + remove_cache_entry_at(*indpos); + } + + for (i = 0; i < len; i++) { + struct cache_entry *ce; + + if (!posns[i] || + (posns[i] != &df_conflict_list && + strcmp(first, posns[i]->name))) { + continue; + } + + if (posns[i] == &df_conflict_list) { + src[i + merge] = &df_conflict_entry; + continue; + } + + if (posns[i]->directory) { + any_dirs = 1; + parse_tree(posns[i]->item.tree); + subposns[i] = posns[i]->item.tree->entries; + posns[i] = posns[i]->next; + src[i + merge] = &df_conflict_entry; + continue; + } + + if (!merge) + ce_stage = 0; + else if (i + 1 < head_idx) + ce_stage = 1; + else if (i + 1 > head_idx) + ce_stage = 3; + else + ce_stage = 2; + + ce = xmalloc(ce_size); + memset(ce, 0, ce_size); + ce->ce_mode = create_ce_mode(posns[i]->mode); + ce->ce_flags = create_ce_flags(baselen + pathlen, + ce_stage); + memcpy(ce->name, base, baselen); + memcpy(ce->name + baselen, first, pathlen + 1); + + any_files = 1; + + memcpy(ce->sha1, posns[i]->item.any->sha1, 20); + src[i + merge] = ce; + subposns[i] = &df_conflict_list; + posns[i] = posns[i]->next; + } + if (any_files) { + if (merge) { + int ret; + +#if DBRT_DEBUG > 1 + printf("%s:\n", first); + for (i = 0; i < src_size; i++) { + printf(" %d ", i); + if (src[i]) + printf("%s\n", sha1_to_hex(src[i]->sha1)); + else + printf("\n"); + } +#endif + ret = fn(src); + +#if DBRT_DEBUG > 1 + printf("Added %d entries\n", ret); +#endif + *indpos += ret; + } else { + for (i = 0; i < src_size; i++) { + if (src[i]) { + add_cache_entry(src[i], ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK); + } + } + } + } + if (any_dirs) { + char *newbase = xmalloc(baselen + 2 + pathlen); + memcpy(newbase, base, baselen); + memcpy(newbase + baselen, first, pathlen); + newbase[baselen + pathlen] = '/'; + newbase[baselen + pathlen + 1] = '\0'; + if (unpack_trees_rec(subposns, len, newbase, fn, + indpos)) + return -1; + free(newbase); + } + free(subposns); + free(src); + } while (1); } -static int path_matches(struct cache_entry *a, struct cache_entry *b) +static void reject_merge(struct cache_entry *ce) { - int len = ce_namelen(a); - return ce_namelen(b) == len && - !memcmp(a->name, b->name, len); + die("Entry '%s' would be overwritten by merge. Cannot merge.", + ce->name); } -static int same(struct cache_entry *a, struct cache_entry *b) +/* Unlink the last component and attempt to remove leading + * directories, in case this unlink is the removal of the + * last entry in the directory -- empty directories are removed. + */ +static void unlink_entry(char *name) { - return a->ce_mode == b->ce_mode && - !memcmp(a->sha1, b->sha1, 20); + char *cp, *prev; + + if (unlink(name)) + return; + prev = NULL; + while (1) { + int status; + cp = strrchr(name, '/'); + if (prev) + *prev = '/'; + if (!cp) + break; + + *cp = 0; + status = rmdir(name); + if (status) { + *cp = '/'; + break; + } + prev = cp; + } } +static void check_updates(struct cache_entry **src, int nr) +{ + static struct checkout state = { + .base_dir = "", + .force = 1, + .quiet = 1, + .refresh_cache = 1, + }; + unsigned short mask = htons(CE_UPDATE); + while (nr--) { + struct cache_entry *ce = *src++; + if (!ce->ce_mode) { + if (update) + unlink_entry(ce->name); + continue; + } + if (ce->ce_flags & mask) { + ce->ce_flags &= ~mask; + if (update) + checkout_entry(ce, &state); + } + } +} -/* - * This removes all trivial merges that don't change the tree - * and collapses them to state 0. - * - * _Any_ other merge is left to user policy. That includes "both - * created the same file", and "both removed the same file" - which are - * trivial, but the user might still want to _note_ it. - */ -static struct cache_entry *merge_entries(struct cache_entry *a, - struct cache_entry *b, - struct cache_entry *c) +static int unpack_trees(merge_fn_t fn) { - int len = ce_namelen(a); + int indpos = 0; + unsigned len = object_list_length(trees); + struct tree_entry_list **posns; + int i; + struct object_list *posn = trees; + merge_size = len; + + if (len) { + posns = xmalloc(len * sizeof(struct tree_entry_list *)); + for (i = 0; i < len; i++) { + posns[i] = ((struct tree *) posn->item)->entries; + posn = posn->next; + } + if (unpack_trees_rec(posns, len, "", fn, &indpos)) + return -1; + } - /* - * Are they all the same filename? We won't do - * any name merging - */ - if (ce_namelen(b) != len || - ce_namelen(c) != len || - memcmp(a->name, b->name, len) || - memcmp(a->name, c->name, len)) - return NULL; + if (trivial_merges_only && nontrivial_merge) + die("Merge requires file-level merging"); - /* - * Ok, all three entries describe the same - * filename, but maybe the contents or file - * mode have changed? - * - * The trivial cases end up being the ones where two - * out of three files are the same: - * - both destinations the same, trivially take either - * - one of the destination versions hasn't changed, - * take the other. - * - * The "all entries exactly the same" case falls out as - * a special case of any of the "two same" cases. - * - * Here "a" is "original", and "b" and "c" are the two - * trees we are merging. - */ - if (same(b,c)) - return c; - if (same(a,b)) - return c; - if (same(a,c)) - return b; - return NULL; + check_updates(active_cache, active_nr); + return 0; +} + +static int list_tree(unsigned char *sha1) +{ + struct tree *tree = parse_tree_indirect(sha1); + if (!tree) + return -1; + object_list_append(&tree->object, &trees); + return 0; } +static int same(struct cache_entry *a, struct cache_entry *b) +{ + if (!!a != !!b) + return 0; + if (!a && !b) + return 1; + return a->ce_mode == b->ce_mode && + !memcmp(a->sha1, b->sha1, 20); +} + + /* * When a CE gets turned into an unmerged entry, we * want it to be up-to-date @@ -102,6 +345,9 @@ static void verify_uptodate(struct cache_entry *ce) { struct stat st; + if (index_only) + return; + if (!lstat(ce->name, &st)) { unsigned changed = ce_match_stat(ce, &st); if (!changed) @@ -113,271 +359,407 @@ static void verify_uptodate(struct cache_entry *ce) die("Entry '%s' not uptodate. Cannot merge.", ce->name); } -/* - * If the old tree contained a CE that isn't even in the - * result, that's always a problem, regardless of whether - * it's up-to-date or not (ie it can be a file that we - * have updated but not committed yet). - */ -static void reject_merge(struct cache_entry *ce) +static int merged_entry(struct cache_entry *merge, struct cache_entry *old) +{ + merge->ce_flags |= htons(CE_UPDATE); + if (old) { + /* + * See if we can re-use the old CE directly? + * That way we get the uptodate stat info. + * + * This also removes the UPDATE flag on + * a match. + */ + if (same(old, merge)) { + *merge = *old; + } else { + verify_uptodate(old); + } + } + merge->ce_flags &= ~htons(CE_STAGEMASK); + add_cache_entry(merge, ADD_CACHE_OK_TO_ADD); + return 1; +} + +static int deleted_entry(struct cache_entry *ce, struct cache_entry *old) { - die("Entry '%s' would be overwritten by merge. Cannot merge.", ce->name); + if (old) + verify_uptodate(old); + ce->ce_mode = 0; + add_cache_entry(ce, ADD_CACHE_OK_TO_ADD); + return 1; } -#define CHECK_OLD(ce) if (old && same(old, ce)) { verify_uptodate(old); old = NULL; } +static int keep_entry(struct cache_entry *ce) +{ + add_cache_entry(ce, ADD_CACHE_OK_TO_ADD); + return 1; +} -static void trivially_merge_cache(struct cache_entry **src, int nr) +#if DBRT_DEBUG +static void show_stage_entry(FILE *o, + const char *label, const struct cache_entry *ce) { - struct cache_entry **dst = src; - struct cache_entry *old = NULL; + if (!ce) + fprintf(o, "%s (missing)\n", label); + else + fprintf(o, "%s%06o %s %d\t%s\n", + label, + ntohl(ce->ce_mode), + sha1_to_hex(ce->sha1), + ce_stage(ce), + ce->name); +} +#endif - while (nr--) { - struct cache_entry *ce, *result; +static int threeway_merge(struct cache_entry **stages) +{ + struct cache_entry *index; + struct cache_entry *head; + struct cache_entry *remote = stages[head_idx + 1]; + int count; + int head_match = 0; + int remote_match = 0; + + int df_conflict_head = 0; + int df_conflict_remote = 0; + + int any_anc_missing = 0; + int no_anc_exists = 1; + int i; + + for (i = 1; i < head_idx; i++) { + if (!stages[i]) + any_anc_missing = 1; + else + no_anc_exists = 0; + } - ce = *src++; + index = stages[0]; + head = stages[head_idx]; - /* We throw away original cache entries except for the stat information */ - if (!ce_stage(ce)) { - if (old) - reject_merge(old); - old = ce; - active_nr--; - continue; - } - if (old && !path_matches(old, ce)) - reject_merge(old); - if (nr > 2 && (result = merge_entries(ce, src[1], src[2])) != NULL) { - result->ce_flags |= htons(CE_UPDATE); - /* - * See if we can re-use the old CE directly? - * That way we get the uptodate stat info. - * - * This also removes the UPDATE flag on - * a match. - */ - if (old && same(old, result)) { - *result = *old; - old = NULL; + if (head == &df_conflict_entry) { + df_conflict_head = 1; + head = NULL; + } + + if (remote == &df_conflict_entry) { + df_conflict_remote = 1; + remote = NULL; + } + + /* First, if there's a #16 situation, note that to prevent #13 + * and #14. + */ + if (!same(remote, head)) { + for (i = 1; i < head_idx; i++) { + if (same(stages[i], head)) { + head_match = i; + } + if (same(stages[i], remote)) { + remote_match = i; } - CHECK_OLD(ce); - CHECK_OLD(src[1]); - CHECK_OLD(src[2]); - ce = result; - ce->ce_flags &= ~htons(CE_STAGEMASK); - src += 2; - nr -= 2; - active_nr -= 2; } + } + /* We start with cases where the index is allowed to match + * something other than the head: #14(ALT) and #2ALT, where it + * is permitted to match the result instead. + */ + /* #14, #14ALT, #2ALT */ + if (remote && !df_conflict_head && head_match && !remote_match) { + if (index && !same(index, remote) && !same(index, head)) + reject_merge(index); + return merged_entry(remote, index); + } + /* + * If we have an entry in the index cache, then we want to + * make sure that it matches head. + */ + if (index && !same(index, head)) { + reject_merge(index); + } + + if (head) { + /* #5ALT, #15 */ + if (same(head, remote)) + return merged_entry(head, index); + /* #13, #3ALT */ + if (!df_conflict_remote && remote_match && !head_match) + return merged_entry(head, index); + } + + /* #1 */ + if (!head && !remote && any_anc_missing) + return 0; + + /* Under the new "aggressive" rule, we resolve mostly trivial + * cases that we historically had git-merge-one-file resolve. + */ + if (aggressive) { + int head_deleted = !head && !df_conflict_head; + int remote_deleted = !remote && !df_conflict_remote; /* - * If we had an old entry that we now effectively - * overwrite, make sure it wasn't dirty. + * Deleted in both. + * Deleted in one and unchanged in the other. */ - CHECK_OLD(ce); - *dst++ = ce; - } - if (old) - reject_merge(old); -} + if ((head_deleted && remote_deleted) || + (head_deleted && remote && remote_match) || + (remote_deleted && head && head_match)) + return 0; -/* - * When we find a "stage2" entry in the two-way merge, that's - * the one that will remain. If we have an exact old match, - * we don't care whether the file is up-to-date or not, we just - * re-use the thing directly. - * - * If we didn't have an exact match, then we want to make sure - * that we've seen a stage1 that matched the old, and that the - * old file was up-to-date. Because it will be gone after this - * merge.. - */ -static void twoway_check(struct cache_entry *old, int seen_stage1, struct cache_entry *ce) -{ - if (path_matches(old, ce)) { /* - * This also removes the UPDATE flag on - * a match + * Added in both, identically. */ - if (same(old, ce)) { - *ce = *old; - return; + if (no_anc_exists && head && remote && same(head, remote)) + return merged_entry(head, index); + + } + + /* Below are "no merge" cases, which require that the index be + * up-to-date to avoid the files getting overwritten with + * conflict resolution files. + */ + if (index) { + verify_uptodate(index); + } + + nontrivial_merge = 1; + + /* #2, #3, #4, #6, #7, #9, #11. */ + count = 0; + if (!head_match || !remote_match) { + for (i = 1; i < head_idx; i++) { + if (stages[i]) { + keep_entry(stages[i]); + count++; + break; + } } - if (!seen_stage1) - reject_merge(old); } - verify_uptodate(old); +#if DBRT_DEBUG + else { + fprintf(stderr, "read-tree: warning #16 detected\n"); + show_stage_entry(stderr, "head ", stages[head_match]); + show_stage_entry(stderr, "remote ", stages[remote_match]); + } +#endif + if (head) { count += keep_entry(head); } + if (remote) { count += keep_entry(remote); } + return count; } /* * Two-way merge. * - * The rule is: - * - every current entry has to match the old tree - * - if the current entry matches the new tree, we leave it - * as-is. Otherwise we require that it be up-to-date. + * The rule is to "carry forward" what is in the index without losing + * information across a "fast forward", favoring a successful merge + * over a merge failure when it makes sense. For details of the + * "carry forward" rule, please see . + * */ -static void twoway_merge(struct cache_entry **src, int nr) +static int twoway_merge(struct cache_entry **src) { - int seen_stage1 = 0; - struct cache_entry *old = NULL; - struct cache_entry **dst = src; - - while (nr--) { - struct cache_entry *ce = *src++; - int stage = ce_stage(ce); - - switch (stage) { - case 0: - if (old) - reject_merge(old); - old = ce; - seen_stage1 = 0; - active_nr--; - continue; - - case 1: - active_nr--; - if (!old) - continue; - if (!path_matches(old, ce) || !same(old, ce)) - reject_merge(old); - seen_stage1 = 1; - continue; - - case 2: - ce->ce_flags |= htons(CE_UPDATE); - if (old) { - twoway_check(old, seen_stage1, ce); - old = NULL; - } - ce->ce_flags &= ~htons(CE_STAGEMASK); - *dst++ = ce; - continue; + struct cache_entry *current = src[0]; + struct cache_entry *oldtree = src[1], *newtree = src[2]; + + if (merge_size != 2) + return error("Cannot do a twoway merge of %d trees\n", + merge_size); + + if (current) { + if ((!oldtree && !newtree) || /* 4 and 5 */ + (!oldtree && newtree && + same(current, newtree)) || /* 6 and 7 */ + (oldtree && newtree && + same(oldtree, newtree)) || /* 14 and 15 */ + (oldtree && newtree && + !same(oldtree, newtree) && /* 18 and 19*/ + same(current, newtree))) { + return keep_entry(current); + } + else if (oldtree && !newtree && same(current, oldtree)) { + /* 10 or 11 */ + return deleted_entry(oldtree, current); + } + else if (oldtree && newtree && + same(current, oldtree) && !same(current, newtree)) { + /* 20 or 21 */ + return merged_entry(newtree, current); + } + else { + /* all other failures */ + if (oldtree) + reject_merge(oldtree); + if (current) + reject_merge(current); + if (newtree) + reject_merge(newtree); + return -1; } - die("impossible two-way stage"); - } - - /* - * Unmatched with a new entry? Make sure it was - * at least uptodate in the working directory _and_ - * the original tree.. - */ - if (old) { - if (!seen_stage1) - reject_merge(old); - verify_uptodate(old); } + else if (newtree) + return merged_entry(newtree, current); + else + return deleted_entry(oldtree, current); } -static void merge_stat_info(struct cache_entry **src, int nr) +/* + * One-way merge. + * + * The rule is: + * - take the stat information from stage0, take the data from stage1 + */ +static int oneway_merge(struct cache_entry **src) { - static struct cache_entry null_entry; - struct cache_entry **dst = src; - struct cache_entry *stat = &null_entry; + struct cache_entry *old = src[0]; + struct cache_entry *a = src[1]; - while (nr--) { - struct cache_entry *ce = *src++; + if (merge_size != 1) + return error("Cannot do a oneway merge of %d trees\n", + merge_size); - /* We throw away original cache entries except for the stat information */ - if (!ce_stage(ce)) { - stat = ce; - active_nr--; - continue; - } - if (path_matches(ce, stat) && same(ce, stat)) - *ce = *stat; - ce->ce_flags &= ~htons(CE_STAGEMASK); - *dst++ = ce; + if (!a) + return 0; + if (old && same(old, a)) { + return keep_entry(old); } + return merged_entry(a, NULL); } -static void check_updates(struct cache_entry **src, int nr) +static int read_cache_unmerged(void) { - static struct checkout state = { - .base_dir = "", - .force = 1, - .quiet = 1, - .refresh_cache = 1, - }; - unsigned short mask = htons(CE_UPDATE); - while (nr--) { - struct cache_entry *ce = *src++; - if (ce->ce_flags & mask) { - ce->ce_flags &= ~mask; - if (update) - checkout_entry(ce, &state); + int i, deleted; + struct cache_entry **dst; + + read_cache(); + dst = active_cache; + deleted = 0; + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + if (ce_stage(ce)) { + deleted++; + continue; } + if (deleted) + *dst = ce; + dst++; } + active_nr -= deleted; + return deleted; } -static char *read_tree_usage = "git-read-tree ( | -m [ []])"; +static const char read_tree_usage[] = "git-read-tree ( | -m [-u | -i] [ []])"; + +static struct cache_file cache_file; int main(int argc, char **argv) { - int i, newfd, merge; + int i, newfd, reset, stage = 0; unsigned char sha1[20]; - static char lockfile[MAXPATHLEN+1]; - const char *indexfile = get_index_file(); + merge_fn_t fn = NULL; - snprintf(lockfile, sizeof(lockfile), "%s.lock", indexfile); + setup_git_directory(); - newfd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0600); + newfd = hold_index_file_for_update(&cache_file, get_index_file()); if (newfd < 0) die("unable to create new cachefile"); - atexit(remove_lock_file); - lockfile_name = lockfile; + + git_config(git_default_config); merge = 0; + reset = 0; for (i = 1; i < argc; i++) { const char *arg = argv[i]; - /* "-u" means "update", meaning that a merge will update the working directory */ + /* "-u" means "update", meaning that a merge will update + * the working tree. + */ if (!strcmp(arg, "-u")) { update = 1; continue; } + /* "-i" means "index only", meaning that a merge will + * not even look at the working tree. + */ + if (!strcmp(arg, "-i")) { + index_only = 1; + continue; + } + + /* This differs from "-m" in that we'll silently ignore unmerged entries */ + if (!strcmp(arg, "--reset")) { + if (stage || merge) + usage(read_tree_usage); + reset = 1; + merge = 1; + stage = 1; + read_cache_unmerged(); + continue; + } + + if (!strcmp(arg, "--trivial")) { + trivial_merges_only = 1; + continue; + } + + if (!strcmp(arg, "--aggressive")) { + aggressive = 1; + continue; + } + /* "-m" stands for "merge", meaning we start in stage 1 */ if (!strcmp(arg, "-m")) { - int i; - if (stage) - die("-m needs to come first"); - read_cache(); - for (i = 0; i < active_nr; i++) { - if (ce_stage(active_cache[i])) - die("you need to resolve your current index first"); - } + if (stage || merge) + usage(read_tree_usage); + if (read_cache_unmerged()) + die("you need to resolve your current index first"); stage = 1; merge = 1; continue; } - if (get_sha1(arg, sha1) < 0) + + /* using -u and -i at the same time makes no sense */ + if (1 < index_only + update) usage(read_tree_usage); - if (stage > 3) + + if (get_sha1(arg, sha1) < 0) usage(read_tree_usage); - if (unpack_tree(sha1) < 0) + if (list_tree(sha1) < 0) die("failed to unpack tree object %s", arg); stage++; } + if ((update||index_only) && !merge) + usage(read_tree_usage); + if (merge) { - switch (stage) { - case 4: /* Three-way merge */ - trivially_merge_cache(active_cache, active_nr); - check_updates(active_cache, active_nr); + if (stage < 2) + die("just how do you expect me to merge %d trees?", stage-1); + switch (stage - 1) { + case 1: + fn = oneway_merge; break; - case 3: /* Update from one tree to another */ - twoway_merge(active_cache, active_nr); - check_updates(active_cache, active_nr); + case 2: + fn = twoway_merge; break; - case 2: /* Just read a tree, merge with old cache contents */ - merge_stat_info(active_cache, active_nr); + case 3: + fn = threeway_merge; break; default: - die("just how do you expect me to merge %d trees?", stage-1); + fn = threeway_merge; + break; } + + if (stage - 1 >= 3) + head_idx = stage - 2; + else + head_idx = 1; } - if (write_cache(newfd, active_cache, active_nr) || rename(lockfile, indexfile)) + + unpack_trees(fn); + if (write_cache(newfd, active_cache, active_nr) || + commit_index_file(&cache_file)) die("unable to write new index file"); - lockfile_name = NULL; return 0; }