diff options
Diffstat (limited to 'unpack-trees.c')
-rw-r--r-- | unpack-trees.c | 90 |
1 files changed, 72 insertions, 18 deletions
diff --git a/unpack-trees.c b/unpack-trees.c index f07304f1b7..89ca95ce90 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -111,17 +111,17 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts, strvec_init(&opts->msgs_to_free); if (!strcmp(cmd, "checkout")) - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("Your local changes to the following files would be overwritten by checkout:\n%%s" "Please commit your changes or stash them before you switch branches.") : _("Your local changes to the following files would be overwritten by checkout:\n%%s"); else if (!strcmp(cmd, "merge")) - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("Your local changes to the following files would be overwritten by merge:\n%%s" "Please commit your changes or stash them before you merge.") : _("Your local changes to the following files would be overwritten by merge:\n%%s"); else - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("Your local changes to the following files would be overwritten by %s:\n%%s" "Please commit your changes or stash them before you %s.") : _("Your local changes to the following files would be overwritten by %s:\n%%s"); @@ -132,17 +132,17 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts, _("Updating the following directories would lose untracked files in them:\n%s"); if (!strcmp(cmd, "checkout")) - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("The following untracked working tree files would be removed by checkout:\n%%s" "Please move or remove them before you switch branches.") : _("The following untracked working tree files would be removed by checkout:\n%%s"); else if (!strcmp(cmd, "merge")) - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("The following untracked working tree files would be removed by merge:\n%%s" "Please move or remove them before you merge.") : _("The following untracked working tree files would be removed by merge:\n%%s"); else - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("The following untracked working tree files would be removed by %s:\n%%s" "Please move or remove them before you %s.") : _("The following untracked working tree files would be removed by %s:\n%%s"); @@ -150,17 +150,17 @@ void setup_unpack_trees_porcelain(struct unpack_trees_options *opts, strvec_pushf(&opts->msgs_to_free, msg, cmd, cmd); if (!strcmp(cmd, "checkout")) - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("The following untracked working tree files would be overwritten by checkout:\n%%s" "Please move or remove them before you switch branches.") : _("The following untracked working tree files would be overwritten by checkout:\n%%s"); else if (!strcmp(cmd, "merge")) - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("The following untracked working tree files would be overwritten by merge:\n%%s" "Please move or remove them before you merge.") : _("The following untracked working tree files would be overwritten by merge:\n%%s"); else - msg = advice_commit_before_merge + msg = advice_enabled(ADVICE_COMMIT_BEFORE_MERGE) ? _("The following untracked working tree files would be overwritten by %s:\n%%s" "Please move or remove them before you %s.") : _("The following untracked working tree files would be overwritten by %s:\n%%s"); @@ -1255,7 +1255,7 @@ static int sparse_dir_matches_path(const struct cache_entry *ce, static struct cache_entry *find_cache_entry(struct traverse_info *info, const struct name_entry *p) { - struct cache_entry *ce; + const char *path; int pos = find_cache_pos(info, p->path, p->pathlen); struct unpack_trees_options *o = info->data; @@ -1281,9 +1281,11 @@ static struct cache_entry *find_cache_entry(struct traverse_info *info, * paths (e.g. "subdir-"). */ while (pos >= 0) { - ce = o->src_index->cache[pos]; + struct cache_entry *ce = o->src_index->cache[pos]; - if (strncmp(ce->name, p->path, p->pathlen)) + if (!skip_prefix(ce->name, info->traverse_path, &path) || + strncmp(path, p->path, p->pathlen) || + path[p->pathlen] != '/') return NULL; if (S_ISSPARSEDIR(ce->ce_mode) && @@ -1692,9 +1694,15 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options static struct cache_entry *dfc; struct pattern_list pl; int free_pattern_list = 0; + struct dir_struct dir = DIR_INIT; + + if (o->reset == UNPACK_RESET_INVALID) + BUG("o->reset had a value of 1; should be UNPACK_TREES_*_UNTRACKED"); if (len > MAX_UNPACK_TREES) die("unpack_trees takes at most %d trees", MAX_UNPACK_TREES); + if (o->dir) + BUG("o->dir is for internal use only"); trace_performance_enter(); trace2_region_enter("unpack_trees", "unpack_trees", the_repository); @@ -1705,6 +1713,16 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options ensure_full_index(o->dst_index); } + if (o->reset == UNPACK_RESET_OVERWRITE_UNTRACKED && + o->preserve_ignored) + BUG("UNPACK_RESET_OVERWRITE_UNTRACKED incompatible with preserved ignored files"); + + if (!o->preserve_ignored) { + o->dir = &dir; + o->dir->flags |= DIR_SHOW_IGNORED; + setup_standard_excludes(o->dir); + } + if (!core_apply_sparse_checkout || !o->update) o->skip_sparse_checkout = 1; if (!o->skip_sparse_checkout && !o->pl) { @@ -1866,6 +1884,10 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options done: if (free_pattern_list) clear_pattern_list(&pl); + if (o->dir) { + dir_clear(o->dir); + o->dir = NULL; + } trace2_region_leave("unpack_trees", "unpack_trees", the_repository); trace_performance_leave("unpack_trees"); return ret; @@ -2134,9 +2156,10 @@ static int verify_clean_subdirectory(const struct cache_entry *ce, if (o->dir) d.exclude_per_dir = o->dir->exclude_per_dir; i = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL); + dir_clear(&d); + free(pathbuf); if (i) return add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name); - free(pathbuf); return cnt; } @@ -2156,9 +2179,15 @@ static int icase_exists(struct unpack_trees_options *o, const char *name, int le return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE); } +enum absent_checking_type { + COMPLETELY_ABSENT, + ABSENT_ANY_DIRECTORY +}; + static int check_ok_to_remove(const char *name, int len, int dtype, const struct cache_entry *ce, struct stat *st, enum unpack_trees_error_types error_type, + enum absent_checking_type absent_type, struct unpack_trees_options *o) { const struct cache_entry *result; @@ -2193,6 +2222,10 @@ static int check_ok_to_remove(const char *name, int len, int dtype, return 0; } + /* If we only care about directories, then we can remove */ + if (absent_type == ABSENT_ANY_DIRECTORY) + return 0; + /* * The previous round may already have decided to * delete this path, which is in a subdirectory that @@ -2213,12 +2246,14 @@ static int check_ok_to_remove(const char *name, int len, int dtype, */ static int verify_absent_1(const struct cache_entry *ce, enum unpack_trees_error_types error_type, + enum absent_checking_type absent_type, struct unpack_trees_options *o) { int len; struct stat st; - if (o->index_only || o->reset || !o->update) + if (o->index_only || !o->update || + o->reset == UNPACK_RESET_OVERWRITE_UNTRACKED) return 0; len = check_leading_path(ce->name, ce_namelen(ce), 0); @@ -2238,7 +2273,8 @@ static int verify_absent_1(const struct cache_entry *ce, NULL, o); else ret = check_ok_to_remove(path, len, DT_UNKNOWN, NULL, - &st, error_type, o); + &st, error_type, + absent_type, o); } free(path); return ret; @@ -2253,7 +2289,7 @@ static int verify_absent_1(const struct cache_entry *ce, return check_ok_to_remove(ce->name, ce_namelen(ce), ce_to_dtype(ce), ce, &st, - error_type, o); + error_type, absent_type, o); } } @@ -2263,14 +2299,23 @@ static int verify_absent(const struct cache_entry *ce, { if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE)) return 0; - return verify_absent_1(ce, error_type, o); + return verify_absent_1(ce, error_type, COMPLETELY_ABSENT, o); +} + +static int verify_absent_if_directory(const struct cache_entry *ce, + enum unpack_trees_error_types error_type, + struct unpack_trees_options *o) +{ + if (!o->skip_sparse_checkout && (ce->ce_flags & CE_NEW_SKIP_WORKTREE)) + return 0; + return verify_absent_1(ce, error_type, ABSENT_ANY_DIRECTORY, o); } static int verify_absent_sparse(const struct cache_entry *ce, enum unpack_trees_error_types error_type, struct unpack_trees_options *o) { - return verify_absent_1(ce, error_type, o); + return verify_absent_1(ce, error_type, COMPLETELY_ABSENT, o); } static int merged_entry(const struct cache_entry *ce, @@ -2344,6 +2389,12 @@ static int merged_entry(const struct cache_entry *ce, * Previously unmerged entry left as an existence * marker by read_index_unmerged(); */ + if (verify_absent_if_directory(merge, + ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o)) { + discard_cache_entry(merge); + return -1; + } + invalidate_ce_path(old, o); } @@ -2361,7 +2412,10 @@ static int deleted_entry(const struct cache_entry *ce, if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o)) return -1; return 0; + } else if (verify_absent_if_directory(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o)) { + return -1; } + if (!(old->ce_flags & CE_CONFLICTED) && verify_uptodate(old, o)) return -1; add_entry(o, ce, CE_REMOVE, 0); |