summaryrefslogtreecommitdiff
path: root/unpack-trees.c
diff options
context:
space:
mode:
Diffstat (limited to 'unpack-trees.c')
-rw-r--r--unpack-trees.c90
1 files changed, 72 insertions, 18 deletions
diff --git a/unpack-trees.c b/unpack-trees.c
index f07304f..89ca95c 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);