Merge branch 'es/worktree-avoid-duplication-fix'
In rare cases "git worktree add <path>" could think that <path> was already a registered worktree even when it wasn't and refuse to add the new worktree. This has been corrected. * es/worktree-avoid-duplication-fix: worktree: don't allow "add" validation to be fooled by suffix matching worktree: add utility to find worktree by pathname worktree: improve find_worktree() documentation
This commit is contained in:
@ -234,14 +234,7 @@ static void validate_worktree_add(const char *path, const struct add_opts *opts)
|
|||||||
die(_("'%s' already exists"), path);
|
die(_("'%s' already exists"), path);
|
||||||
|
|
||||||
worktrees = get_worktrees(0);
|
worktrees = get_worktrees(0);
|
||||||
/*
|
wt = find_worktree_by_path(worktrees, path);
|
||||||
* find_worktree()'s suffix matching may undesirably find the main
|
|
||||||
* rather than a linked worktree (for instance, when the basenames
|
|
||||||
* of the main worktree and the one being created are the same).
|
|
||||||
* We're only interested in linked worktrees, so skip the main
|
|
||||||
* worktree with +1.
|
|
||||||
*/
|
|
||||||
wt = find_worktree(worktrees + 1, NULL, path);
|
|
||||||
if (!wt)
|
if (!wt)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
|
@ -570,6 +570,15 @@ test_expect_success '"add" an existing locked but missing worktree' '
|
|||||||
git worktree add --force --force --detach gnoo
|
git worktree add --force --force --detach gnoo
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success '"add" not tripped up by magic worktree matching"' '
|
||||||
|
# if worktree "sub1/bar" exists, "git worktree add bar" in distinct
|
||||||
|
# directory `sub2` should not mistakenly complain that `bar` is an
|
||||||
|
# already-registered worktree
|
||||||
|
mkdir sub1 sub2 &&
|
||||||
|
git -C sub1 --git-dir=../.git worktree add --detach bozo &&
|
||||||
|
git -C sub2 --git-dir=../.git worktree add --detach bozo
|
||||||
|
'
|
||||||
|
|
||||||
test_expect_success FUNNYNAMES 'sanitize generated worktree name' '
|
test_expect_success FUNNYNAMES 'sanitize generated worktree name' '
|
||||||
git worktree add --detach ". weird*..?.lock.lock" &&
|
git worktree add --detach ". weird*..?.lock.lock" &&
|
||||||
test -d .git/worktrees/---weird-.-
|
test -d .git/worktrees/---weird-.-
|
||||||
|
14
worktree.c
14
worktree.c
@ -211,7 +211,6 @@ struct worktree *find_worktree(struct worktree **list,
|
|||||||
const char *arg)
|
const char *arg)
|
||||||
{
|
{
|
||||||
struct worktree *wt;
|
struct worktree *wt;
|
||||||
char *path;
|
|
||||||
char *to_free = NULL;
|
char *to_free = NULL;
|
||||||
|
|
||||||
if ((wt = find_worktree_by_suffix(list, arg)))
|
if ((wt = find_worktree_by_suffix(list, arg)))
|
||||||
@ -219,11 +218,17 @@ struct worktree *find_worktree(struct worktree **list,
|
|||||||
|
|
||||||
if (prefix)
|
if (prefix)
|
||||||
arg = to_free = prefix_filename(prefix, arg);
|
arg = to_free = prefix_filename(prefix, arg);
|
||||||
path = real_pathdup(arg, 0);
|
wt = find_worktree_by_path(list, arg);
|
||||||
if (!path) {
|
|
||||||
free(to_free);
|
free(to_free);
|
||||||
|
return wt;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct worktree *find_worktree_by_path(struct worktree **list, const char *p)
|
||||||
|
{
|
||||||
|
char *path = real_pathdup(p, 0);
|
||||||
|
|
||||||
|
if (!path)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
for (; *list; list++) {
|
for (; *list; list++) {
|
||||||
const char *wt_path = real_path_if_valid((*list)->path);
|
const char *wt_path = real_path_if_valid((*list)->path);
|
||||||
|
|
||||||
@ -231,7 +236,6 @@ struct worktree *find_worktree(struct worktree **list,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
free(path);
|
free(path);
|
||||||
free(to_free);
|
|
||||||
return *list;
|
return *list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
worktree.h
20
worktree.h
@ -44,13 +44,29 @@ int submodule_uses_worktrees(const char *path);
|
|||||||
const char *get_worktree_git_dir(const struct worktree *wt);
|
const char *get_worktree_git_dir(const struct worktree *wt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Search a worktree that can be unambiguously identified by
|
* Search for the worktree identified unambiguously by `arg` -- typically
|
||||||
* "arg". "prefix" must not be NULL.
|
* supplied by the user via the command-line -- which may be a pathname or some
|
||||||
|
* shorthand uniquely identifying a worktree, thus making it convenient for the
|
||||||
|
* user to specify a worktree with minimal typing. For instance, if the last
|
||||||
|
* component (say, "foo") of a worktree's pathname is unique among worktrees
|
||||||
|
* (say, "work/foo" and "work/bar"), it can be used to identify the worktree
|
||||||
|
* unambiguously.
|
||||||
|
*
|
||||||
|
* `prefix` should be the `prefix` handed to top-level Git commands along with
|
||||||
|
* `argc` and `argv`.
|
||||||
|
*
|
||||||
|
* Return the worktree identified by `arg`, or NULL if not found.
|
||||||
*/
|
*/
|
||||||
struct worktree *find_worktree(struct worktree **list,
|
struct worktree *find_worktree(struct worktree **list,
|
||||||
const char *prefix,
|
const char *prefix,
|
||||||
const char *arg);
|
const char *arg);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the worktree corresponding to `path`, or NULL if no such worktree
|
||||||
|
* exists.
|
||||||
|
*/
|
||||||
|
struct worktree *find_worktree_by_path(struct worktree **, const char *path);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return true if the given worktree is the main one.
|
* Return true if the given worktree is the main one.
|
||||||
*/
|
*/
|
||||||
|
Reference in New Issue
Block a user