Skip to content

Commit 49e5043

Browse files
committed
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
2 parents 2cbb058 + bb69b3b commit 49e5043

File tree

4 files changed

+38
-16
lines changed

4 files changed

+38
-16
lines changed

builtin/worktree.c

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -234,14 +234,7 @@ static void validate_worktree_add(const char *path, const struct add_opts *opts)
234234
die(_("'%s' already exists"), path);
235235

236236
worktrees = get_worktrees(0);
237-
/*
238-
* find_worktree()'s suffix matching may undesirably find the main
239-
* rather than a linked worktree (for instance, when the basenames
240-
* of the main worktree and the one being created are the same).
241-
* We're only interested in linked worktrees, so skip the main
242-
* worktree with +1.
243-
*/
244-
wt = find_worktree(worktrees + 1, NULL, path);
237+
wt = find_worktree_by_path(worktrees, path);
245238
if (!wt)
246239
goto done;
247240

t/t2400-worktree-add.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,6 +570,15 @@ test_expect_success '"add" an existing locked but missing worktree' '
570570
git worktree add --force --force --detach gnoo
571571
'
572572

573+
test_expect_success '"add" not tripped up by magic worktree matching"' '
574+
# if worktree "sub1/bar" exists, "git worktree add bar" in distinct
575+
# directory `sub2` should not mistakenly complain that `bar` is an
576+
# already-registered worktree
577+
mkdir sub1 sub2 &&
578+
git -C sub1 --git-dir=../.git worktree add --detach bozo &&
579+
git -C sub2 --git-dir=../.git worktree add --detach bozo
580+
'
581+
573582
test_expect_success FUNNYNAMES 'sanitize generated worktree name' '
574583
git worktree add --detach ". weird*..?.lock.lock" &&
575584
test -d .git/worktrees/---weird-.-

worktree.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -211,27 +211,31 @@ struct worktree *find_worktree(struct worktree **list,
211211
const char *arg)
212212
{
213213
struct worktree *wt;
214-
char *path;
215214
char *to_free = NULL;
216215

217216
if ((wt = find_worktree_by_suffix(list, arg)))
218217
return wt;
219218

220219
if (prefix)
221220
arg = to_free = prefix_filename(prefix, arg);
222-
path = real_pathdup(arg, 0);
223-
if (!path) {
224-
free(to_free);
221+
wt = find_worktree_by_path(list, arg);
222+
free(to_free);
223+
return wt;
224+
}
225+
226+
struct worktree *find_worktree_by_path(struct worktree **list, const char *p)
227+
{
228+
char *path = real_pathdup(p, 0);
229+
230+
if (!path)
225231
return NULL;
226-
}
227232
for (; *list; list++) {
228233
const char *wt_path = real_path_if_valid((*list)->path);
229234

230235
if (wt_path && !fspathcmp(path, wt_path))
231236
break;
232237
}
233238
free(path);
234-
free(to_free);
235239
return *list;
236240
}
237241

worktree.h

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,29 @@ int submodule_uses_worktrees(const char *path);
4444
const char *get_worktree_git_dir(const struct worktree *wt);
4545

4646
/*
47-
* Search a worktree that can be unambiguously identified by
48-
* "arg". "prefix" must not be NULL.
47+
* Search for the worktree identified unambiguously by `arg` -- typically
48+
* supplied by the user via the command-line -- which may be a pathname or some
49+
* shorthand uniquely identifying a worktree, thus making it convenient for the
50+
* user to specify a worktree with minimal typing. For instance, if the last
51+
* component (say, "foo") of a worktree's pathname is unique among worktrees
52+
* (say, "work/foo" and "work/bar"), it can be used to identify the worktree
53+
* unambiguously.
54+
*
55+
* `prefix` should be the `prefix` handed to top-level Git commands along with
56+
* `argc` and `argv`.
57+
*
58+
* Return the worktree identified by `arg`, or NULL if not found.
4959
*/
5060
struct worktree *find_worktree(struct worktree **list,
5161
const char *prefix,
5262
const char *arg);
5363

64+
/*
65+
* Return the worktree corresponding to `path`, or NULL if no such worktree
66+
* exists.
67+
*/
68+
struct worktree *find_worktree_by_path(struct worktree **, const char *path);
69+
5470
/*
5571
* Return true if the given worktree is the main one.
5672
*/

0 commit comments

Comments
 (0)