From: Junio C Hamano Date: Fri, 11 May 2007 06:44:53 +0000 (-0700) Subject: read-tree -m -u: avoid getting confused by intermediate symlinks. X-Git-Tag: v1.5.2~41 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/16a4c6176ad096881d0021f1a922fbcc2835f799 read-tree -m -u: avoid getting confused by intermediate symlinks. 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 --- diff --git a/t/t4122-apply-symlink-inside.sh b/t/t4122-apply-symlink-inside.sh index 37c9a9f254..3ddfe64b02 100755 --- a/t/t4122-apply-symlink-inside.sh +++ b/t/t4122-apply-symlink-inside.sh @@ -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 diff --git a/unpack-trees.c b/unpack-trees.c index 675a9998dc..906ce69ea6 100644 --- a/unpack-trees.c +++ b/unpack-trees.c @@ -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)