worktree: generalize candidate worktree path validation

"git worktree add" checks that the specified path is a valid location
for a new worktree by ensuring that the path does not already exist and
is not already registered to another worktree (a path can be registered
but missing, for instance, if it resides on removable media). Since "git
worktree add" is not the only command which should perform such
validation ("git worktree move" ought to also), generalize the the
validation function for use by other callers, as well.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Eric Sunshine 2020-06-10 02:30:48 -04:00 committed by Junio C Hamano
parent 916133ef8e
commit d179af679b

View file

@ -280,34 +280,33 @@ static const char *worktree_basename(const char *path, int *olen)
return name; return name;
} }
static void validate_worktree_add(const char *path, const struct add_opts *opts) /* check that path is viable location for worktree */
static void check_candidate_path(const char *path,
int force,
struct worktree **worktrees,
const char *cmd)
{ {
struct worktree **worktrees;
struct worktree *wt; struct worktree *wt;
int locked; int locked;
if (file_exists(path) && !is_empty_dir(path)) if (file_exists(path) && !is_empty_dir(path))
die(_("'%s' already exists"), path); die(_("'%s' already exists"), path);
worktrees = get_worktrees(0);
wt = find_worktree_by_path(worktrees, path); wt = find_worktree_by_path(worktrees, path);
if (!wt) if (!wt)
goto done; return;
locked = !!worktree_lock_reason(wt); locked = !!worktree_lock_reason(wt);
if ((!locked && opts->force) || (locked && opts->force > 1)) { if ((!locked && force) || (locked && force > 1)) {
if (delete_git_dir(wt->id)) if (delete_git_dir(wt->id))
die(_("unable to re-add worktree '%s'"), path); die(_("unusable worktree destination '%s'"), path);
goto done; return;
} }
if (locked) if (locked)
die(_("'%s' is a missing but locked worktree;\nuse 'add -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"), path); die(_("'%s' is a missing but locked worktree;\nuse '%s -f -f' to override, or 'unlock' and 'prune' or 'remove' to clear"), cmd, path);
else else
die(_("'%s' is a missing but already registered worktree;\nuse 'add -f' to override, or 'prune' or 'remove' to clear"), path); die(_("'%s' is a missing but already registered worktree;\nuse '%s -f' to override, or 'prune' or 'remove' to clear"), cmd, path);
done:
free_worktrees(worktrees);
} }
static int add_worktree(const char *path, const char *refname, static int add_worktree(const char *path, const char *refname,
@ -324,8 +323,12 @@ static int add_worktree(const char *path, const char *refname,
struct commit *commit = NULL; struct commit *commit = NULL;
int is_branch = 0; int is_branch = 0;
struct strbuf sb_name = STRBUF_INIT; struct strbuf sb_name = STRBUF_INIT;
struct worktree **worktrees;
validate_worktree_add(path, opts); worktrees = get_worktrees(0);
check_candidate_path(path, opts->force, worktrees, "add");
free_worktrees(worktrees);
worktrees = NULL;
/* is 'refname' a branch or commit? */ /* is 'refname' a branch or commit? */
if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) && if (!opts->detach && !strbuf_check_branch_ref(&symref, refname) &&