summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2019-05-13 10:49:44 (GMT)
committerJunio C Hamano <gitster@pobox.com>2019-05-15 05:17:18 (GMT)
commit105df73e71a9eb901d7ca96f12ce3645729ae486 (patch)
treed29c7f1b342b5fe01913f40600af74d772a21b12
parentaeb582a98374c094361cba1bd756dc6307432c42 (diff)
downloadgit-105df73e71a9eb901d7ca96f12ce3645729ae486.zip
git-105df73e71a9eb901d7ca96f12ce3645729ae486.tar.gz
git-105df73e71a9eb901d7ca96f12ce3645729ae486.tar.bz2
worktree add: be tolerant of corrupt worktrees
find_worktree() can die() unexpectedly because it uses real_path() instead of the gentler version. When it's used in 'git worktree add' [1] and there's a bad worktree, this die() could prevent people from adding new worktrees. The "bad" condition to trigger this is when a parent of the worktree's location is deleted. Then real_path() will complain. Use the other version so that bad worktrees won't affect 'worktree add'. The bad ones will eventually be pruned, we just have to tolerate them for a bit. [1] added in cb56f55c16 (worktree: disallow adding same path multiple times, 2018-08-28), or since v2.20.0. Though the real bug in find_worktree() is much older. Reported-by: Shaheed Haque <shaheedhaque@gmail.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rwxr-xr-xt/t2025-worktree-add.sh12
-rw-r--r--worktree.c7
2 files changed, 17 insertions, 2 deletions
diff --git a/t/t2025-worktree-add.sh b/t/t2025-worktree-add.sh
index 286bba3..d83a9f0 100755
--- a/t/t2025-worktree-add.sh
+++ b/t/t2025-worktree-add.sh
@@ -570,4 +570,16 @@ test_expect_success '"add" an existing locked but missing worktree' '
git worktree add --force --force --detach gnoo
'
+test_expect_success '"add" should not fail because of another bad worktree' '
+ git init add-fail &&
+ (
+ cd add-fail &&
+ test_commit first &&
+ mkdir sub &&
+ git worktree add sub/to-be-deleted &&
+ rm -rf sub &&
+ git worktree add second
+ )
+'
+
test_done
diff --git a/worktree.c b/worktree.c
index d6a0ee7..c79b3e4 100644
--- a/worktree.c
+++ b/worktree.c
@@ -222,9 +222,12 @@ struct worktree *find_worktree(struct worktree **list,
free(to_free);
return NULL;
}
- for (; *list; list++)
- if (!fspathcmp(path, real_path((*list)->path)))
+ for (; *list; list++) {
+ const char *wt_path = real_path_if_valid((*list)->path);
+
+ if (wt_path && !fspathcmp(path, wt_path))
break;
+ }
free(path);
free(to_free);
return *list;