merge-recursive: do not clobber untracked working tree garbage
authorJunio C Hamano <gitster@pobox.com>
Mon, 15 Dec 2008 03:40:09 +0000 (19:40 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 15 Dec 2008 10:39:57 +0000 (02:39 -0800)
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
t/t7607-merge-overwrite.sh

index b9738655adc66386e55eccafa9ab891bdcf30960..ab9f6e0f14024cab4d0df4e1991e0e5973a0dc4b 100644 (file)
@@ -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;
index 513097c1a1cfac4d6606f8c225f45b04d69356f0..49f4e1599acd829fdd930c1f9b5bc30ac719053d 100755 (executable)
@@ -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" &&