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>
This commit is contained in:
Nguyễn Thái Ngọc Duy
2018-02-12 16:49:40 +07:00
committed by Junio C Hamano
parent cc73385cf6
commit ee6763af0a
4 changed files with 36 additions and 7 deletions

View File

@ -674,7 +674,7 @@ static int move_worktree(int ac, const char **av, const char *prefix)
reason); reason);
die(_("cannot move a locked working tree")); die(_("cannot move a locked working tree"));
} }
if (validate_worktree(wt, &errmsg)) if (validate_worktree(wt, &errmsg, 0))
die(_("validation failed, cannot move working tree: %s"), die(_("validation failed, cannot move working tree: %s"),
errmsg.buf); errmsg.buf);
strbuf_release(&errmsg); strbuf_release(&errmsg);
@ -799,15 +799,17 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
reason); reason);
die(_("cannot remove a locked working tree")); die(_("cannot remove a locked working tree"));
} }
if (validate_worktree(wt, &errmsg)) if (validate_worktree(wt, &errmsg, WT_VALIDATE_WORKTREE_MISSING_OK))
die(_("validation failed, cannot remove working tree: %s"), die(_("validation failed, cannot remove working tree: %s"),
errmsg.buf); errmsg.buf);
strbuf_release(&errmsg); strbuf_release(&errmsg);
if (!force) if (file_exists(wt->path)) {
check_clean_worktree(wt, av[0]); if (!force)
check_clean_worktree(wt, av[0]);
ret |= delete_git_work_tree(wt); ret |= delete_git_work_tree(wt);
}
/* /*
* continue on even if ret is non-zero, there's no going back * continue on even if ret is non-zero, there's no going back
* from here. * from here.

View File

@ -126,4 +126,21 @@ test_expect_success 'force remove worktree with untracked file' '
test_path_is_missing destination test_path_is_missing destination
' '
test_expect_success 'remove missing worktree' '
git worktree add to-be-gone &&
test -d .git/worktrees/to-be-gone &&
mv to-be-gone gone &&
git worktree remove to-be-gone &&
test_path_is_missing .git/worktrees/to-be-gone
'
test_expect_success 'NOT remove missing-but-locked worktree' '
git worktree add gone-but-locked &&
git worktree lock gone-but-locked &&
test -d .git/worktrees/gone-but-locked &&
mv gone-but-locked really-gone-now &&
test_must_fail git worktree remove gone-but-locked &&
test_path_is_dir .git/worktrees/gone-but-locked
'
test_done test_done

View File

@ -267,7 +267,8 @@ static void strbuf_addf_gently(struct strbuf *buf, const char *fmt, ...)
va_end(params); va_end(params);
} }
int validate_worktree(const struct worktree *wt, struct strbuf *errmsg) int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
unsigned flags)
{ {
struct strbuf wt_path = STRBUF_INIT; struct strbuf wt_path = STRBUF_INIT;
char *path = NULL; char *path = NULL;
@ -303,6 +304,12 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg)
goto done; goto done;
} }
if (flags & WT_VALIDATE_WORKTREE_MISSING_OK &&
!file_exists(wt->path)) {
ret = 0;
goto done;
}
if (!file_exists(wt_path.buf)) { if (!file_exists(wt_path.buf)) {
strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf); strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf);
goto done; goto done;

View File

@ -61,12 +61,15 @@ extern int is_main_worktree(const struct worktree *wt);
*/ */
extern const char *is_worktree_locked(struct worktree *wt); extern const char *is_worktree_locked(struct worktree *wt);
#define WT_VALIDATE_WORKTREE_MISSING_OK (1 << 0)
/* /*
* Return zero if the worktree is in good condition. Error message is * Return zero if the worktree is in good condition. Error message is
* returned if "errmsg" is not NULL. * returned if "errmsg" is not NULL.
*/ */
extern int validate_worktree(const struct worktree *wt, extern int validate_worktree(const struct worktree *wt,
struct strbuf *errmsg); struct strbuf *errmsg,
unsigned flags);
/* /*
* Update worktrees/xxx/gitdir with the new path. * Update worktrees/xxx/gitdir with the new path.