aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin-merge-recursive.c32
-rwxr-xr-xt/t7607-merge-overwrite.sh2
2 files changed, 33 insertions, 1 deletions
diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index b9738655a..ab9f6e0f1 100644
--- a/builtin-merge-recursive.c
+++ b/builtin-merge-recursive.c
@@ -471,6 +471,30 @@ static void flush_buffer(int fd, const char *buf, unsigned long size)
}
}
+static int would_lose_untracked(const char *path)
+{
+ int pos = cache_name_pos(path, strlen(path));
+
+ if (pos < 0)
+ pos = -1 - pos;
+ while (pos < active_nr &&
+ !strcmp(path, active_cache[pos]->name)) {
+ /*
+ * If stage #0, it is definitely tracked.
+ * If it has stage #2 then it was tracked
+ * before this merge started. All other
+ * cases the path was not tracked.
+ */
+ switch (ce_stage(active_cache[pos])) {
+ case 0:
+ case 2:
+ return 0;
+ }
+ pos++;
+ }
+ return file_exists(path);
+}
+
static int make_room_for_path(const char *path)
{
int status;
@@ -486,6 +510,14 @@ static int make_room_for_path(const char *path)
die(msg, path, "");
}
+ /*
+ * Do not unlink a file in the work tree if we are not
+ * tracking it.
+ */
+ if (would_lose_untracked(path))
+ return error("refusing to lose untracked file at '%s'",
+ path);
+
/* Successful unlink is good.. */
if (!unlink(path))
return 0;
diff --git a/t/t7607-merge-overwrite.sh b/t/t7607-merge-overwrite.sh
index 513097c1a..49f4e1599 100755
--- a/t/t7607-merge-overwrite.sh
+++ b/t/t7607-merge-overwrite.sh
@@ -53,7 +53,7 @@ test_expect_success 'will not overwrite staged changes' '
test_cmp important c2.c
'
-test_expect_failure 'will not overwrite removed file' '
+test_expect_success 'will not overwrite removed file' '
git reset --hard c1 &&
git rm c1.c &&
git commit -m "rm c1.c" &&