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);
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"),
errmsg.buf);
strbuf_release(&errmsg);
@ -799,15 +799,17 @@ static int remove_worktree(int ac, const char **av, const char *prefix)
reason);
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"),
errmsg.buf);
strbuf_release(&errmsg);
if (!force)
check_clean_worktree(wt, av[0]);
if (file_exists(wt->path)) {
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
* from here.

View File

@ -126,4 +126,21 @@ test_expect_success 'force remove worktree with untracked file' '
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

View File

@ -267,7 +267,8 @@ static void strbuf_addf_gently(struct strbuf *buf, const char *fmt, ...)
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;
char *path = NULL;
@ -303,6 +304,12 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg)
goto done;
}
if (flags & WT_VALIDATE_WORKTREE_MISSING_OK &&
!file_exists(wt->path)) {
ret = 0;
goto done;
}
if (!file_exists(wt_path.buf)) {
strbuf_addf_gently(errmsg, _("'%s' does not exist"), wt_path.buf);
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);
#define WT_VALIDATE_WORKTREE_MISSING_OK (1 << 0)
/*
* Return zero if the worktree is in good condition. Error message is
* returned if "errmsg" is not NULL.
*/
extern int validate_worktree(const struct worktree *wt,
struct strbuf *errmsg);
struct strbuf *errmsg,
unsigned flags);
/*
* Update worktrees/xxx/gitdir with the new path.