summaryrefslogtreecommitdiff
path: root/unpack-trees.c
diff options
context:
space:
mode:
Diffstat (limited to 'unpack-trees.c')
-rw-r--r--unpack-trees.c403
1 files changed, 273 insertions, 130 deletions
diff --git a/unpack-trees.c b/unpack-trees.c
index 75f54cac97..d5a453079a 100644
--- a/unpack-trees.c
+++ b/unpack-trees.c
@@ -13,37 +13,94 @@
* Error messages expected by scripts out of plumbing commands such as
* read-tree. Non-scripted Porcelain is not required to use these messages
* and in fact are encouraged to reword them to better suit their particular
- * situation better. See how "git checkout" replaces not_uptodate_file to
- * explain why it does not allow switching between branches when you have
- * local changes, for example.
+ * situation better. See how "git checkout" and "git merge" replaces
+ * them using setup_unpack_trees_porcelain(), for example.
*/
-static struct unpack_trees_error_msgs unpack_plumbing_errors = {
- /* would_overwrite */
+const char *unpack_plumbing_errors[NB_UNPACK_TREES_ERROR_TYPES] = {
+ /* ERROR_WOULD_OVERWRITE */
"Entry '%s' would be overwritten by merge. Cannot merge.",
- /* not_uptodate_file */
+ /* ERROR_NOT_UPTODATE_FILE */
"Entry '%s' not uptodate. Cannot merge.",
- /* not_uptodate_dir */
+ /* ERROR_NOT_UPTODATE_DIR */
"Updating '%s' would lose untracked files in it",
- /* would_lose_untracked */
- "Untracked working tree file '%s' would be %s by merge.",
+ /* ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN */
+ "Untracked working tree file '%s' would be overwritten by merge.",
- /* bind_overlap */
+ /* ERROR_WOULD_LOSE_UNTRACKED_REMOVED */
+ "Untracked working tree file '%s' would be removed by merge.",
+
+ /* ERROR_BIND_OVERLAP */
"Entry '%s' overlaps with '%s'. Cannot bind.",
- /* sparse_not_uptodate_file */
+ /* ERROR_SPARSE_NOT_UPTODATE_FILE */
"Entry '%s' not uptodate. Cannot update sparse checkout.",
- /* would_lose_orphaned */
- "Working tree file '%s' would be %s by sparse checkout update.",
+ /* ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN */
+ "Working tree file '%s' would be overwritten by sparse checkout update.",
+
+ /* ERROR_WOULD_LOSE_ORPHANED_REMOVED */
+ "Working tree file '%s' would be removed by sparse checkout update.",
};
-#define ERRORMSG(o,fld) \
- ( ((o) && (o)->msgs.fld) \
- ? ((o)->msgs.fld) \
- : (unpack_plumbing_errors.fld) )
+#define ERRORMSG(o,type) \
+ ( ((o) && (o)->msgs[(type)]) \
+ ? ((o)->msgs[(type)]) \
+ : (unpack_plumbing_errors[(type)]) )
+
+void setup_unpack_trees_porcelain(struct unpack_trees_options *opts,
+ const char *cmd)
+{
+ int i;
+ const char **msgs = opts->msgs;
+ const char *msg;
+ char *tmp;
+ const char *cmd2 = strcmp(cmd, "checkout") ? cmd : "switch branches";
+ if (advice_commit_before_merge)
+ msg = "Your local changes to the following files would be overwritten by %s:\n%%s"
+ "Please, commit your changes or stash them before you can %s.";
+ else
+ msg = "Your local changes to the following files would be overwritten by %s:\n%%s";
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen(cmd2) - 2);
+ sprintf(tmp, msg, cmd, cmd2);
+ msgs[ERROR_WOULD_OVERWRITE] = tmp;
+ msgs[ERROR_NOT_UPTODATE_FILE] = tmp;
+
+ msgs[ERROR_NOT_UPTODATE_DIR] =
+ "Updating the following directories would lose untracked files in it:\n%s";
+
+ if (advice_commit_before_merge)
+ msg = "The following untracked working tree files would be %s by %s:\n%%s"
+ "Please move or remove them before you can %s.";
+ else
+ msg = "The following untracked working tree files would be %s by %s:\n%%s";
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("removed") + strlen(cmd2) - 4);
+ sprintf(tmp, msg, "removed", cmd, cmd2);
+ msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = tmp;
+ tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("overwritten") + strlen(cmd2) - 4);
+ sprintf(tmp, msg, "overwritten", cmd, cmd2);
+ msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = tmp;
+
+ /*
+ * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
+ * cannot easily display it as a list.
+ */
+ msgs[ERROR_BIND_OVERLAP] = "Entry '%s' overlaps with '%s'. Cannot bind.";
+
+ msgs[ERROR_SPARSE_NOT_UPTODATE_FILE] =
+ "Cannot update sparse checkout: the following entries are not up-to-date:\n%s";
+ msgs[ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN] =
+ "The following Working tree files would be overwritten by sparse checkout update:\n%s";
+ msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
+ "The following Working tree files would be removed by sparse checkout update:\n%s";
+
+ opts->show_all_errors = 1;
+ /* rejected paths may not have a static buffer */
+ for (i = 0; i < ARRAY_SIZE(opts->unpack_rejects); i++)
+ opts->unpack_rejects[i].strdup_strings = 1;
+}
static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
unsigned int set, unsigned int clear)
@@ -53,6 +110,9 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
clear |= CE_HASHED | CE_UNHASHED;
+ if (set & CE_REMOVE)
+ set |= CE_WT_REMOVE;
+
memcpy(new, ce, size);
new->next = NULL;
new->ce_flags = (new->ce_flags & ~clear) | set;
@@ -60,23 +120,58 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
}
/*
+ * add error messages on path <path>
+ * corresponding to the type <e> with the message <msg>
+ * indicating if it should be display in porcelain or not
+ */
+static int add_rejected_path(struct unpack_trees_options *o,
+ enum unpack_trees_error_types e,
+ const char *path)
+{
+ if (!o->show_all_errors)
+ return error(ERRORMSG(o, e), path);
+
+ /*
+ * Otherwise, insert in a list for future display by
+ * display_error_msgs()
+ */
+ string_list_append(&o->unpack_rejects[e], path);
+ return -1;
+}
+
+/*
+ * display all the error messages stored in a nice way
+ */
+static void display_error_msgs(struct unpack_trees_options *o)
+{
+ int e, i;
+ int something_displayed = 0;
+ for (e = 0; e < NB_UNPACK_TREES_ERROR_TYPES; e++) {
+ struct string_list *rejects = &o->unpack_rejects[e];
+ if (rejects->nr > 0) {
+ struct strbuf path = STRBUF_INIT;
+ something_displayed = 1;
+ for (i = 0; i < rejects->nr; i++)
+ strbuf_addf(&path, "\t%s\n", rejects->items[i].string);
+ error(ERRORMSG(o, e), path.buf);
+ strbuf_release(&path);
+ }
+ string_list_clear(rejects, 0);
+ }
+ if (something_displayed)
+ printf("Aborting\n");
+}
+
+/*
* Unlink the last component and schedule the leading directories for
* removal, such that empty directories get removed.
*/
static void unlink_entry(struct cache_entry *ce)
{
- if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
+ if (!check_leading_path(ce->name, ce_namelen(ce)))
+ return;
+ if (remove_or_warn(ce->ce_mode, ce->name))
return;
- if (S_ISGITLINK(ce->ce_mode)) {
- if (rmdir(ce->name)) {
- warning("unable to rmdir %s: %s",
- ce->name, strerror(errno));
- return;
- }
- }
- else
- if (unlink_or_warn(ce->name))
- return;
schedule_dir_for_removal(ce->name, ce_namelen(ce));
}
@@ -92,7 +187,7 @@ static int check_updates(struct unpack_trees_options *o)
if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < index->cache_nr; cnt++) {
struct cache_entry *ce = index->cache[cnt];
- if (ce->ce_flags & (CE_UPDATE | CE_REMOVE | CE_WT_REMOVE))
+ if (ce->ce_flags & (CE_UPDATE | CE_WT_REMOVE))
total++;
}
@@ -112,12 +207,6 @@ static int check_updates(struct unpack_trees_options *o)
unlink_entry(ce);
continue;
}
-
- if (ce->ce_flags & CE_REMOVE) {
- display_progress(progress, ++cnt);
- if (o->update)
- unlink_entry(ce);
- }
}
remove_marked_cache_entries(&o->result);
remove_scheduled_dirs();
@@ -140,15 +229,12 @@ static int check_updates(struct unpack_trees_options *o)
}
static int verify_uptodate_sparse(struct cache_entry *ce, struct unpack_trees_options *o);
-static int verify_absent_sparse(struct cache_entry *ce, const char *action, struct unpack_trees_options *o);
+static int verify_absent_sparse(struct cache_entry *ce, enum unpack_trees_error_types, struct unpack_trees_options *o);
static int will_have_skip_worktree(const struct cache_entry *ce, struct unpack_trees_options *o)
{
const char *basename;
- if (ce_stage(ce))
- return 0;
-
basename = strrchr(ce->name, '/');
basename = basename ? basename+1 : ce->name;
return excluded_from_list(ce->name, ce_namelen(ce), basename, NULL, o->el) <= 0;
@@ -158,19 +244,36 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt
{
int was_skip_worktree = ce_skip_worktree(ce);
- if (will_have_skip_worktree(ce, o))
+ if (!ce_stage(ce) && will_have_skip_worktree(ce, o))
ce->ce_flags |= CE_SKIP_WORKTREE;
else
ce->ce_flags &= ~CE_SKIP_WORKTREE;
/*
- * We only care about files getting into the checkout area
- * If merge strategies want to remove some, go ahead, this
- * flag will be removed eventually in unpack_trees() if it's
- * outside checkout area.
+ * if (!was_skip_worktree && !ce_skip_worktree()) {
+ * This is perfectly normal. Move on;
+ * }
*/
- if (ce->ce_flags & CE_REMOVE)
- return 0;
+
+ /*
+ * Merge strategies may set CE_UPDATE|CE_REMOVE outside checkout
+ * area as a result of ce_skip_worktree() shortcuts in
+ * verify_absent() and verify_uptodate().
+ * Make sure they don't modify worktree if they are already
+ * outside checkout area
+ */
+ if (was_skip_worktree && ce_skip_worktree(ce)) {
+ ce->ce_flags &= ~CE_UPDATE;
+
+ /*
+ * By default, when CE_REMOVE is on, CE_WT_REMOVE is also
+ * on to get that file removed from both index and worktree.
+ * If that file is already outside worktree area, don't
+ * bother remove it.
+ */
+ if (ce->ce_flags & CE_REMOVE)
+ ce->ce_flags &= ~CE_WT_REMOVE;
+ }
if (!was_skip_worktree && ce_skip_worktree(ce)) {
/*
@@ -183,7 +286,7 @@ static int apply_sparse_checkout(struct cache_entry *ce, struct unpack_trees_opt
ce->ce_flags |= CE_WT_REMOVE;
}
if (was_skip_worktree && !ce_skip_worktree(ce)) {
- if (verify_absent_sparse(ce, "overwritten", o))
+ if (verify_absent_sparse(ce, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
return -1;
ce->ce_flags |= CE_UPDATE;
}
@@ -287,9 +390,11 @@ static void add_same_unmerged(struct cache_entry *ce,
static int unpack_index_entry(struct cache_entry *ce,
struct unpack_trees_options *o)
{
- struct cache_entry *src[5] = { ce, NULL, };
+ struct cache_entry *src[5] = { NULL };
int ret;
+ src[0] = ce;
+
mark_ce_used(ce, o);
if (ce_stage(ce)) {
if (o->skip_unmerged) {
@@ -335,6 +440,7 @@ static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long
{
int i, ret, bottom;
struct tree_desc t[MAX_UNPACK_TREES];
+ void *buf[MAX_UNPACK_TREES];
struct traverse_info newinfo;
struct name_entry *p;
@@ -352,12 +458,16 @@ static int traverse_trees_recursive(int n, unsigned long dirmask, unsigned long
const unsigned char *sha1 = NULL;
if (dirmask & 1)
sha1 = names[i].sha1;
- fill_tree_descriptor(t+i, sha1);
+ buf[i] = fill_tree_descriptor(t+i, sha1);
}
bottom = switch_cache_bottom(&newinfo);
ret = traverse_trees(n, t, &newinfo);
restore_cache_bottom(&newinfo, bottom);
+
+ for (i = 0; i < n; i++)
+ free(buf[i]);
+
return ret;
}
@@ -528,9 +638,17 @@ static int find_cache_pos(struct traverse_info *info,
const char *ce_name, *ce_slash;
int cmp, ce_len;
- if (!ce_in_traverse_path(ce, info))
+ if (ce->ce_flags & CE_UNPACKED) {
+ /*
+ * cache_bottom entry is already unpacked, so
+ * we can never match it; don't check it
+ * again.
+ */
+ if (pos == o->cache_bottom)
+ ++o->cache_bottom;
continue;
- if (ce->ce_flags & CE_UNPACKED)
+ }
+ if (!ce_in_traverse_path(ce, info))
continue;
ce_name = ce->name + pfxlen;
ce_slash = strchr(ce_name, '/');
@@ -748,6 +866,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
setup_traverse_info(&info, prefix);
info.fn = unpack_callback;
info.data = o;
+ info.show_all_errors = o->show_all_errors;
if (o->prefix) {
/*
@@ -796,14 +915,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
ret = -1;
goto done;
}
- /*
- * Merge strategies may set CE_UPDATE|CE_REMOVE outside checkout
- * area as a result of ce_skip_worktree() shortcuts in
- * verify_absent() and verify_uptodate(). Clear them.
- */
- if (ce_skip_worktree(ce))
- ce->ce_flags &= ~(CE_UPDATE | CE_REMOVE);
- else
+ if (!ce_skip_worktree(ce))
empty_worktree = 0;
}
@@ -827,6 +939,8 @@ done:
return ret;
return_failed:
+ if (o->show_all_errors)
+ display_error_msgs(o);
mark_all_ce_unused(o->src_index);
ret = unpack_failed(o, NULL);
goto done;
@@ -836,7 +950,7 @@ return_failed:
static int reject_merge(struct cache_entry *ce, struct unpack_trees_options *o)
{
- return error(ERRORMSG(o, would_overwrite), ce->name);
+ return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
}
static int same(struct cache_entry *a, struct cache_entry *b)
@@ -858,11 +972,11 @@ static int same(struct cache_entry *a, struct cache_entry *b)
*/
static int verify_uptodate_1(struct cache_entry *ce,
struct unpack_trees_options *o,
- const char *error_msg)
+ enum unpack_trees_error_types error_type)
{
struct stat st;
- if (o->index_only || (!ce_skip_worktree(ce) && (o->reset || ce_uptodate(ce))))
+ if (o->index_only || (!((ce->ce_flags & CE_VALID) || ce_skip_worktree(ce)) && (o->reset || ce_uptodate(ce))))
return 0;
if (!lstat(ce->name, &st)) {
@@ -883,7 +997,7 @@ static int verify_uptodate_1(struct cache_entry *ce,
if (errno == ENOENT)
return 0;
return o->gently ? -1 :
- error(error_msg, ce->name);
+ add_rejected_path(o, error_type, ce->name);
}
static int verify_uptodate(struct cache_entry *ce,
@@ -891,13 +1005,13 @@ static int verify_uptodate(struct cache_entry *ce,
{
if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
return 0;
- return verify_uptodate_1(ce, o, ERRORMSG(o, not_uptodate_file));
+ return verify_uptodate_1(ce, o, ERROR_NOT_UPTODATE_FILE);
}
static int verify_uptodate_sparse(struct cache_entry *ce,
struct unpack_trees_options *o)
{
- return verify_uptodate_1(ce, o, ERRORMSG(o, sparse_not_uptodate_file));
+ return verify_uptodate_1(ce, o, ERROR_SPARSE_NOT_UPTODATE_FILE);
}
static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_options *o)
@@ -913,13 +1027,15 @@ static void invalidate_ce_path(struct cache_entry *ce, struct unpack_trees_optio
* Currently, git does not checkout subprojects during a superproject
* checkout, so it is not going to overwrite anything.
*/
-static int verify_clean_submodule(struct cache_entry *ce, const char *action,
+static int verify_clean_submodule(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
return 0;
}
-static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
+static int verify_clean_subdirectory(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
/*
@@ -940,7 +1056,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
*/
if (!hashcmp(sha1, ce->sha1))
return 0;
- return verify_clean_submodule(ce, action, o);
+ return verify_clean_submodule(ce, error_type, o);
}
/*
@@ -984,7 +1100,7 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
i = read_directory(&d, pathbuf, namelen+1, NULL);
if (i)
return o->gently ? -1 :
- error(ERRORMSG(o, not_uptodate_dir), ce->name);
+ add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
free(pathbuf);
return cnt;
}
@@ -997,91 +1113,116 @@ static int verify_clean_subdirectory(struct cache_entry *ce, const char *action,
* See if we can find a case-insensitive match in the index that also
* matches the stat information, and assume it's that other file!
*/
-static int icase_exists(struct unpack_trees_options *o, struct cache_entry *dst, struct stat *st)
+static int icase_exists(struct unpack_trees_options *o, const char *name, int len, struct stat *st)
{
struct cache_entry *src;
- src = index_name_exists(o->src_index, dst->name, ce_namelen(dst), 1);
+ src = index_name_exists(o->src_index, name, len, 1);
return src && !ie_match_stat(o->src_index, src, st, CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE);
}
+static int check_ok_to_remove(const char *name, int len, int dtype,
+ struct cache_entry *ce, struct stat *st,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
+{
+ struct cache_entry *result;
+
+ /*
+ * It may be that the 'lstat()' succeeded even though
+ * target 'ce' was absent, because there is an old
+ * entry that is different only in case..
+ *
+ * Ignore that lstat() if it matches.
+ */
+ if (ignore_case && icase_exists(o, name, len, st))
+ return 0;
+
+ if (o->dir && excluded(o->dir, name, &dtype))
+ /*
+ * ce->name is explicitly excluded, so it is Ok to
+ * overwrite it.
+ */
+ return 0;
+ if (S_ISDIR(st->st_mode)) {
+ /*
+ * We are checking out path "foo" and
+ * found "foo/." in the working tree.
+ * This is tricky -- if we have modified
+ * files that are in "foo/" we would lose
+ * them.
+ */
+ if (verify_clean_subdirectory(ce, error_type, o) < 0)
+ return -1;
+ return 0;
+ }
+
+ /*
+ * The previous round may already have decided to
+ * delete this path, which is in a subdirectory that
+ * is being replaced with a blob.
+ */
+ result = index_name_exists(&o->result, name, len, 0);
+ if (result) {
+ if (result->ce_flags & CE_REMOVE)
+ return 0;
+ }
+
+ return o->gently ? -1 :
+ add_rejected_path(o, error_type, name);
+}
+
/*
* We do not want to remove or overwrite a working tree file that
* is not tracked, unless it is ignored.
*/
-static int verify_absent_1(struct cache_entry *ce, const char *action,
- struct unpack_trees_options *o,
- const char *error_msg)
+static int verify_absent_1(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
+ struct unpack_trees_options *o)
{
+ int len;
struct stat st;
if (o->index_only || o->reset || !o->update)
return 0;
- if (has_symlink_or_noent_leading_path(ce->name, ce_namelen(ce)))
+ len = check_leading_path(ce->name, ce_namelen(ce));
+ if (!len)
return 0;
+ else if (len > 0) {
+ char path[PATH_MAX + 1];
+ memcpy(path, ce->name, len);
+ path[len] = 0;
+ lstat(path, &st);
+
+ return check_ok_to_remove(path, len, DT_UNKNOWN, NULL, &st,
+ error_type, o);
+ } else if (!lstat(ce->name, &st))
+ return check_ok_to_remove(ce->name, ce_namelen(ce),
+ ce_to_dtype(ce), ce, &st,
+ error_type, o);
- if (!lstat(ce->name, &st)) {
- int dtype = ce_to_dtype(ce);
- struct cache_entry *result;
-
- /*
- * It may be that the 'lstat()' succeeded even though
- * target 'ce' was absent, because there is an old
- * entry that is different only in case..
- *
- * Ignore that lstat() if it matches.
- */
- if (ignore_case && icase_exists(o, ce, &st))
- return 0;
-
- if (o->dir && excluded(o->dir, ce->name, &dtype))
- /*
- * ce->name is explicitly excluded, so it is Ok to
- * overwrite it.
- */
- return 0;
- if (S_ISDIR(st.st_mode)) {
- /*
- * We are checking out path "foo" and
- * found "foo/." in the working tree.
- * This is tricky -- if we have modified
- * files that are in "foo/" we would lose
- * them.
- */
- if (verify_clean_subdirectory(ce, action, o) < 0)
- return -1;
- return 0;
- }
-
- /*
- * The previous round may already have decided to
- * delete this path, which is in a subdirectory that
- * is being replaced with a blob.
- */
- result = index_name_exists(&o->result, ce->name, ce_namelen(ce), 0);
- if (result) {
- if (result->ce_flags & CE_REMOVE)
- return 0;
- }
-
- return o->gently ? -1 :
- error(ERRORMSG(o, would_lose_untracked), ce->name, action);
- }
return 0;
}
-static int verify_absent(struct cache_entry *ce, const char *action,
+
+static int verify_absent(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
if (!o->skip_sparse_checkout && will_have_skip_worktree(ce, o))
return 0;
- return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_untracked));
+ return verify_absent_1(ce, error_type, o);
}
-static int verify_absent_sparse(struct cache_entry *ce, const char *action,
+static int verify_absent_sparse(struct cache_entry *ce,
+ enum unpack_trees_error_types error_type,
struct unpack_trees_options *o)
{
- return verify_absent_1(ce, action, o, ERRORMSG(o, would_lose_orphaned));
+ enum unpack_trees_error_types orphaned_error = error_type;
+ if (orphaned_error == ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN)
+ orphaned_error = ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN;
+
+ return verify_absent_1(ce, orphaned_error, o);
}
static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
@@ -1090,8 +1231,10 @@ static int merged_entry(struct cache_entry *merge, struct cache_entry *old,
int update = CE_UPDATE;
if (!old) {
- if (verify_absent(merge, "overwritten", o))
+ if (verify_absent(merge, ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN, o))
return -1;
+ if (!o->skip_sparse_checkout && will_have_skip_worktree(merge, o))
+ update |= CE_SKIP_WORKTREE;
invalidate_ce_path(merge, o);
} else if (!(old->ce_flags & CE_CONFLICTED)) {
/*
@@ -1128,7 +1271,7 @@ static int deleted_entry(struct cache_entry *ce, struct cache_entry *old,
{
/* Did it exist in the index? */
if (!old) {
- if (verify_absent(ce, "removed", o))
+ if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
return -1;
return 0;
}
@@ -1277,7 +1420,7 @@ int threeway_merge(struct cache_entry **stages, struct unpack_trees_options *o)
if (index)
return deleted_entry(index, index, o);
if (ce && !head_deleted) {
- if (verify_absent(ce, "removed", o))
+ if (verify_absent(ce, ERROR_WOULD_LOSE_UNTRACKED_REMOVED, o))
return -1;
}
return 0;
@@ -1410,7 +1553,7 @@ int bind_merge(struct cache_entry **src,
o->merge_size);
if (a && old)
return o->gently ? -1 :
- error(ERRORMSG(o, bind_overlap), a->name, old->name);
+ error(ERRORMSG(o, ERROR_BIND_OVERLAP), a->name, old->name);
if (!a)
return keep_entry(old, o);
else