lstat_cache(): print a warning if doing ping-pong between cache types
[gitweb.git] / merge-recursive.c
index 0e988f2a0081803f5ee30adbf7a548c2c8a00a05..b97026bd5cc1d2ef1b46a9ef3dcd7562ad52c377 100644 (file)
@@ -447,6 +447,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;
@@ -462,6 +486,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;
@@ -525,7 +557,8 @@ static void update_file_flags(struct merge_options *o,
                        char *lnk = xmemdupz(buf, size);
                        safe_create_leading_directories_const(path);
                        unlink(path);
-                       symlink(lnk, path);
+                       if (symlink(lnk, path))
+                               die("failed to symlink %s: %s", path, strerror(errno));
                        free(lnk);
                } else
                        die("do not know what to do with %06o %s '%s'",
@@ -901,6 +934,11 @@ static int process_renames(struct merge_options *o,
                                       ren1_src, ren1_dst, branch1,
                                       branch2);
                                update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
+                               update_stages(ren1_dst, NULL,
+                                               branch1 == o->branch1 ?
+                                               ren1->pair->two : NULL,
+                                               branch1 == o->branch1 ?
+                                               NULL : ren1->pair->two, 1);
                        } else if (!sha_eq(dst_other.sha1, null_sha1)) {
                                const char *new_path;
                                clean_merge = 0;