worktree remove: allow it when $GIT_WORK_TREE is already gone

"git worktree remove" basically consists of two things - delete $GIT_WORK_TREE - delete $GIT_DIR (which is $SUPER_GIT_DIR/worktrees/something) If $GIT_WORK_TREE is already gone for some reason, we should be able to finish the job by deleting $GIT_DIR. Two notes: - $GIT_WORK_TREE _can_ be missing if the worktree is locked. In that case we must not delete $GIT_DIR because the real $GIT_WORK_TREE may be in a usb stick somewhere. This is already handled because we check for lock first. - validate_worktree() is still called because it may do more checks in future (and it already does something else, like checking main worktree, but that's irrelevant in this case) Noticed-by: Kaartic Sivaraam <kaartic.sivaraam@gmail.com> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Feb 12, 2018 at 16:49 UTC ee6763af0a3b97225803c6c908a29de40336cf38
4 files changed +36 -7
builtin/worktree.c
+7 -5
@@ -674,7 +674,7 @@ static int move_worktree(int ac, const char **av, const char *prefix)
674 reason);
675 die(_("cannot move a locked working tree"));
676 }
677 - if (validate_worktree(wt, &errmsg))
677 + if (validate_worktree(wt, &errmsg, 0))
678 die(_("validation failed, cannot move working tree: %s"),
679 errmsg.buf);
680 strbuf_release(&errmsg);
@@ -799,15 +799,17 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
799 reason);
800 die(_("cannot remove a locked working tree"));
801 }
802 - if (validate_worktree(wt, &errmsg))
802 + if (validate_worktree(wt, &errmsg, WT_VALIDATE_WORKTREE_MISSING_OK))
803 die(_("validation failed, cannot remove working tree: %s"),
804 errmsg.buf);
805 strbuf_release(&errmsg);
806
807 - if (!force)
808 - check_clean_worktree(wt, av[0]);
807 + if (file_exists(wt->path)) {
808 + if (!force)
809 + check_clean_worktree(wt, av[0]);
810
810 - ret |= delete_git_work_tree(wt);
811 + ret |= delete_git_work_tree(wt);
812 + }
813 /*
814 * continue on even if ret is non-zero, there's no going back
815 * from here.
t/t2028-worktree-move.sh
+17
@@ -126,4 +126,21 @@ test_expect_success 'force remove worktree with untracked file' '
126 test_path_is_missing destination
127 '
128
129 +test_expect_success 'remove missing worktree' '
130 + git worktree add to-be-gone &&
131 + test -d .git/worktrees/to-be-gone &&
132 + mv to-be-gone gone &&
133 + git worktree remove to-be-gone &&
134 + test_path_is_missing .git/worktrees/to-be-gone
135 +'
136 +
137 +test_expect_success 'NOT remove missing-but-locked worktree' '
138 + git worktree add gone-but-locked &&
139 + git worktree lock gone-but-locked &&
140 + test -d .git/worktrees/gone-but-locked &&
141 + mv gone-but-locked really-gone-now &&
142 + test_must_fail git worktree remove gone-but-locked &&
143 + test_path_is_dir .git/worktrees/gone-but-locked
144 +'
145 +
146 test_done
worktree.c
+8 -1
@@ -267,7 +267,8 @@ static void strbuf_addf_gently(struct strbuf *buf, const char *fmt, ...)
267 va_end(params);
268 }
269
270 -int validate_worktree(const struct worktree *wt, struct strbuf *errmsg)
270 +int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
271 + unsigned flags)
272 {
273 struct strbuf wt_path = STRBUF_INIT;
274 char *path = NULL;
@@ -303,6 +304,12 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg)
304 goto done;
305 }
306
307 + if (flags & WT_VALIDATE_WORKTREE_MISSING_OK &&
308 + !file_exists(wt->path)) {
309 + ret = 0;
310 + goto done;
311 + }
312 +
313 if (!file_exists(wt_path.buf)) {
314 strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf);
315 goto done;
worktree.h
+4 -1
@@ -61,12 +61,15 @@ extern int is_main_worktree(const struct worktree *wt);
61 */
62 extern const char *is_worktree_locked(struct worktree *wt);
63
64 +#define WT_VALIDATE_WORKTREE_MISSING_OK (1 << 0)
65 +
66 /*
67 * Return zero if the worktree is in good condition. Error message is
68 * returned if "errmsg" is not NULL.
69 */
70 extern int validate_worktree(const struct worktree *wt,
69 - struct strbuf *errmsg);
71 + struct strbuf *errmsg,
72 + unsigned flags);
73
74 /*
75 * Update worktrees/xxx/gitdir with the new path.