read-tree -m -u: avoid getting confused by intermediate symlinks.
authorJunio C Hamano <junkio@cox.net>
Fri, 11 May 2007 06:44:53 +0000 (23:44 -0700)
committerJunio C Hamano <junkio@cox.net>
Sat, 12 May 2007 05:33:31 +0000 (22:33 -0700)
When switching from a branch with both x86_64/boot/Makefile and
i386/boot/Makefile to another branch that has x86_64/boot as a
symlink pointing at ../i386/boot, the code incorrectly removed
i386/boot/Makefile.

This was because we first removed everything under x86_64/boot
to make room to create a symbolic link x86_64/boot, then removed
x86_64/boot/Makefile which no longer exists but now is pointing
at i386/boot/Makefile, thanks to the symlink we just created.

This fixes it by using the has_symlink_leading_path() function
introduced previously for git-apply in the checkout codepath.
Earlier, "git checkout" was broken in t4122 test due to this
bug, and the test had an extra "git reset --hard" as a
workaround, which is removed because it is not needed anymore.

Signed-off-by: Junio C Hamano <junkio@cox.net>
t/t4122-apply-symlink-inside.sh
unpack-trees.c

index 37c9a9f254d626939ef28398ec15bec606a9c588..3ddfe64b02490c2fa2e8cf7445aa518e0de8bf1b 100755 (executable)
@@ -34,7 +34,6 @@ test_expect_success setup '
 test_expect_success apply '
 
        git checkout test &&
-       git reset --hard && #### checkout seems to be buggy
        git diff --exit-code test &&
        git diff --exit-code --cached test &&
        git apply --index test.patch
index 675a9998dcbab528faf2cf34ab1a66f884a36300..906ce69ea6daf98cdb4f9dd3d6498264159b6b76 100644 (file)
@@ -264,10 +264,12 @@ static int unpack_trees_rec(struct tree_entry_list **posns, int len,
  * directories, in case this unlink is the removal of the
  * last entry in the directory -- empty directories are removed.
  */
-static void unlink_entry(char *name)
+static void unlink_entry(char *name, char *last_symlink)
 {
        char *cp, *prev;
 
+       if (has_symlink_leading_path(name, last_symlink))
+               return;
        if (unlink(name))
                return;
        prev = NULL;
@@ -291,11 +293,12 @@ static void unlink_entry(char *name)
 
 static struct checkout state;
 static void check_updates(struct cache_entry **src, int nr,
-               struct unpack_trees_options *o)
+                       struct unpack_trees_options *o)
 {
        unsigned short mask = htons(CE_UPDATE);
        unsigned cnt = 0, total = 0;
        struct progress progress;
+       char last_symlink[PATH_MAX];
 
        if (o->update && o->verbose_update) {
                for (total = cnt = 0; cnt < nr; cnt++) {
@@ -309,6 +312,7 @@ static void check_updates(struct cache_entry **src, int nr,
                cnt = 0;
        }
 
+       *last_symlink = '\0';
        while (nr--) {
                struct cache_entry *ce = *src++;
 
@@ -317,13 +321,15 @@ static void check_updates(struct cache_entry **src, int nr,
                                display_progress(&progress, ++cnt);
                if (!ce->ce_mode) {
                        if (o->update)
-                               unlink_entry(ce->name);
+                               unlink_entry(ce->name, last_symlink);
                        continue;
                }
                if (ce->ce_flags & mask) {
                        ce->ce_flags &= ~mask;
-                       if (o->update)
+                       if (o->update) {
                                checkout_entry(ce, &state, NULL);
+                               *last_symlink = '\0';
+                       }
                }
        }
        if (total)