diff options
author | Junio C Hamano <gitster@pobox.com> | 2020-03-05 10:43:02 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2020-03-05 10:43:02 -0800 |
commit | 49e5043b09fffb0411e8bae19d60014e72a36fd0 (patch) | |
tree | 5d6afc8117d4bb235bfc36958e1375b0433a69c8 | |
parent | Merge branch 'bc/wildcard-credential' (diff) | |
parent | worktree: don't allow "add" validation to be fooled by suffix matching (diff) | |
download | tgif-49e5043b09fffb0411e8bae19d60014e72a36fd0.tar.xz |
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
-rw-r--r-- | builtin/worktree.c | 9 | ||||
-rwxr-xr-x | t/t2400-worktree-add.sh | 9 | ||||
-rw-r--r-- | worktree.c | 16 | ||||
-rw-r--r-- | worktree.h | 20 |
4 files changed, 38 insertions, 16 deletions
diff --git a/builtin/worktree.c b/builtin/worktree.c index d6bc5263f1..24f22800f3 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -234,14 +234,7 @@ static void validate_worktree_add(const char *path, const struct add_opts *opts) die(_("'%s' already exists"), path); worktrees = get_worktrees(0); - /* - * 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); + wt = find_worktree_by_path(worktrees, path); if (!wt) goto done; diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index b5ece19460..5a7495474a 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -570,6 +570,15 @@ test_expect_success '"add" an existing locked but missing worktree' ' 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' ' git worktree add --detach ". weird*..?.lock.lock" && test -d .git/worktrees/---weird-.- diff --git a/worktree.c b/worktree.c index 33c2655534..52971f7082 100644 --- a/worktree.c +++ b/worktree.c @@ -211,7 +211,6 @@ struct worktree *find_worktree(struct worktree **list, const char *arg) { struct worktree *wt; - char *path; char *to_free = NULL; if ((wt = find_worktree_by_suffix(list, arg))) @@ -219,11 +218,17 @@ struct worktree *find_worktree(struct worktree **list, if (prefix) arg = to_free = prefix_filename(prefix, arg); - path = real_pathdup(arg, 0); - if (!path) { - free(to_free); + wt = find_worktree_by_path(list, arg); + 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; - } for (; *list; list++) { const char *wt_path = real_path_if_valid((*list)->path); @@ -231,7 +236,6 @@ struct worktree *find_worktree(struct worktree **list, break; } free(path); - free(to_free); return *list; } diff --git a/worktree.h b/worktree.h index caecc7a281..d242a6e71c 100644 --- a/worktree.h +++ b/worktree.h @@ -44,14 +44,30 @@ int submodule_uses_worktrees(const char *path); const char *get_worktree_git_dir(const struct worktree *wt); /* - * Search a worktree that can be unambiguously identified by - * "arg". "prefix" must not be NULL. + * Search for the worktree identified unambiguously by `arg` -- typically + * 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, const char *prefix, 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. */ int is_main_worktree(const struct worktree *wt); |