Merge branch 'en/removing-untracked-fixes'
Various fixes in code paths that move untracked files away to make room. * en/removing-untracked-fixes: Documentation: call out commands that nuke untracked files/directories Comment important codepaths regarding nuking untracked files/dirs unpack-trees: avoid nuking untracked dir in way of locally deleted file unpack-trees: avoid nuking untracked dir in way of unmerged file Change unpack_trees' 'reset' flag into an enum Remove ignored files by default when they are in the way unpack-trees: make dir an internal-only struct unpack-trees: introduce preserve_ignored to unpack_trees_options read-tree, merge-recursive: overwrite ignored files by default checkout, read-tree: fix leak of unpack_trees_options.dir t2500: add various tests for nuking untracked files
This commit is contained in:
@ -1694,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);
|
||||
@ -1707,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) {
|
||||
@ -1868,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;
|
||||
@ -2158,9 +2178,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;
|
||||
@ -2195,6 +2221,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
|
||||
@ -2215,12 +2245,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);
|
||||
@ -2240,7 +2272,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;
|
||||
@ -2255,7 +2288,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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2265,14 +2298,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,
|
||||
@ -2346,6 +2388,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);
|
||||
}
|
||||
|
||||
@ -2363,7 +2411,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);
|
||||
|
||||
Reference in New Issue
Block a user