From c5ab03f26c992e30f355fba129f70db0f290fcd7 Mon Sep 17 00:00:00 2001
From: Junio C Hamano <gitster@pobox.com>
Date: Sun, 14 Dec 2008 19:40:09 -0800
Subject: [PATCH] merge-recursive: do not clobber untracked working tree
 garbage

When merge-recursive wanted to create a new file in the work tree (either
as the final result, or a hint for reference purposes while delete/modify
conflicts), it unconditionally overwrote an untracked file in the working
tree.  Be careful not to lose whatever the user has that is not tracked.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 builtin-merge-recursive.c  | 32 ++++++++++++++++++++++++++++++++
 t/t7607-merge-overwrite.sh |  2 +-
 2 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/builtin-merge-recursive.c b/builtin-merge-recursive.c
index b9738655ad..ab9f6e0f14 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 513097c1a1..49f4e1599a 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" &&
-- 
2.48.1