Browse Source

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 <junkio@cox.net>
maint
Junio C Hamano 18 years ago
parent
commit
16a4c6176a
  1. 1
      t/t4122-apply-symlink-inside.sh
  2. 14
      unpack-trees.c

1
t/t4122-apply-symlink-inside.sh

@ -34,7 +34,6 @@ test_expect_success setup '
test_expect_success apply ' test_expect_success apply '


git checkout test && git checkout test &&
git reset --hard && #### checkout seems to be buggy
git diff --exit-code test && git diff --exit-code test &&
git diff --exit-code --cached test && git diff --exit-code --cached test &&
git apply --index test.patch git apply --index test.patch

14
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 * directories, in case this unlink is the removal of the
* last entry in the directory -- empty directories are removed. * 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; char *cp, *prev;


if (has_symlink_leading_path(name, last_symlink))
return;
if (unlink(name)) if (unlink(name))
return; return;
prev = NULL; prev = NULL;
@ -291,11 +293,12 @@ static void unlink_entry(char *name)


static struct checkout state; static struct checkout state;
static void check_updates(struct cache_entry **src, int nr, 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 short mask = htons(CE_UPDATE);
unsigned cnt = 0, total = 0; unsigned cnt = 0, total = 0;
struct progress progress; struct progress progress;
char last_symlink[PATH_MAX];


if (o->update && o->verbose_update) { if (o->update && o->verbose_update) {
for (total = cnt = 0; cnt < nr; cnt++) { for (total = cnt = 0; cnt < nr; cnt++) {
@ -309,6 +312,7 @@ static void check_updates(struct cache_entry **src, int nr,
cnt = 0; cnt = 0;
} }


*last_symlink = '\0';
while (nr--) { while (nr--) {
struct cache_entry *ce = *src++; struct cache_entry *ce = *src++;


@ -317,13 +321,15 @@ static void check_updates(struct cache_entry **src, int nr,
display_progress(&progress, ++cnt); display_progress(&progress, ++cnt);
if (!ce->ce_mode) { if (!ce->ce_mode) {
if (o->update) if (o->update)
unlink_entry(ce->name); unlink_entry(ce->name, last_symlink);
continue; continue;
} }
if (ce->ce_flags & mask) { if (ce->ce_flags & mask) {
ce->ce_flags &= ~mask; ce->ce_flags &= ~mask;
if (o->update) if (o->update) {
checkout_entry(ce, &state, NULL); checkout_entry(ce, &state, NULL);
*last_symlink = '\0';
}
} }
} }
if (total) if (total)

Loading…
Cancel
Save