git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 7/7] worktree: make "move" refuse to move atop missing registered worktree

From
Eric Sunshine <sunshine@sunshineco.com>
Date
Jun 10, 2020, 06:30 UTC
Message-ID
<20200610063049.74666-8-sunshine@sunshineco.com>
In-Reply-To
<20200610063049.74666-1-sunshine@sunshineco.com>

"git worktree add" takes special care to avoid creating a new worktree at a location already registered to an existing worktree even if that worktree is missing (which can happen, for instance, if the worktree resides on removable media). "git worktree move", however, is not so careful when validating the destination location and will happily move the source worktree atop the location of a missing worktree. This leads to the anomalous situation of multiple worktrees being associated with the same path, which is expressly forbidden by design. For example:

    $ git clone foo.git
    $ cd foo
    $ git worktree add ../bar
    $ git worktree add ../baz
    $ rm -rf ../bar
    $ git worktree move ../baz ../bar
    $ git worktree list
    .../foo beefd00f [master]
    .../bar beefd00f [bar]
    .../bar beefd00f [baz]
    $ git worktree remove ../bar
    fatal: validation failed, cannot remove working tree:
        '.../bar' does not point back to '.git/worktrees/bar'

Fix this shortcoming by enhancing "git worktree move" to perform the same additional validation of the destination directory as done by "git worktree add".

While at it, add a test to verify that "git worktree move" won't move a worktree atop an existing (non-worktree) path -- a restriction which has always been in place but was never tested.

Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
 Documentation/git-worktree.txt |  4 +++-
 builtin/worktree.c             |  3 +--
 t/t2403-worktree-move.sh       | 21 +++++++++++++++++++++
 3 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt
index 85d92c9761..4796c3c05e 100644
--- a/Documentation/git-worktree.txt
+++ b/Documentation/git-worktree.txt
@@ -126,7 +126,9 @@ OPTIONS
 	locked working tree path, specify `--force` twice.
 +
 `move` refuses to move a locked working tree unless `--force` is specified
-twice.
+twice. If the destination is already assigned to some other working tree but is
+missing (for instance, if `<new-path>` was deleted manually), then `--force`
+allows the move to proceed; use --force twice if the destination is locked.
 +
 `remove` refuses to remove an unclean working tree unless `--force` is used.
 To remove a locked working tree, specify `--force` twice.
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 8fcf3f38fb..1238b6bab1 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -863,8 +863,7 @@ static int move_worktree(int ac, const char **av, const char *prefix)
 		strbuf_trim_trailing_dir_sep(&dst);
 		strbuf_addstr(&dst, sep);
 	}
-	if (file_exists(dst.buf))
-		die(_("target '%s' already exists"), dst.buf);
+	check_candidate_path(dst.buf, force, worktrees, "move");
 
 	validate_no_submodules(wt);
 
diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh
index 939d18d728..a4e1a178e0 100755
--- a/t/t2403-worktree-move.sh
+++ b/t/t2403-worktree-move.sh
@@ -112,6 +112,27 @@ test_expect_success 'move locked worktree (force)' '
 	git worktree move --force --force flump ploof
 '
 
+test_expect_success 'refuse to move worktree atop existing path' '
+	>bobble &&
+	git worktree add --detach beeble &&
+	test_must_fail git worktree move beeble bobble
+'
+
+test_expect_success 'move atop existing but missing worktree' '
+	git worktree add --detach gnoo &&
+	git worktree add --detach pneu &&
+	rm -fr pneu &&
+	test_must_fail git worktree move gnoo pneu &&
+	git worktree move --force gnoo pneu &&
+
+	git worktree add --detach nu &&
+	git worktree lock nu &&
+	rm -fr nu &&
+	test_must_fail git worktree move pneu nu &&
+	test_must_fail git worktree --force move pneu nu &&
+	git worktree move --force --force pneu nu
+'
+
 test_expect_success 'move a repo with uninitialized submodule' '
 	git init withsub &&
 	(
-- 
2.27.0.90.gabb59f83a2
Previous: Eric SunshineNext: Eric Sunshine
Message 9 of 13 in “worktree: tighten duplicate path detection”
  1. 0/7 worktree: tighten duplicate path detectionEric Sunshine, Jun 10, 2020
  2. 1/7 worktree: factor out repeated string literalEric Sunshine, Jun 10, 2020
  3. 2/7 worktree: give "should be pruned?" function more meaningful nameEric Sunshine, Jun 10, 2020
  4. 6/7 worktree: generalize candidate worktree path validationEric Sunshine, Jun 10, 2020
  5. Shourya ShuklaJun 10, 2020
  6. Eric SunshineJun 10, 2020
  7. 3/7 worktree: make high-level pruning re-usableEric Sunshine, Jun 10, 2020
  8. 5/7 worktree: prune linked worktree referencing main worktree pathEric Sunshine, Jun 10, 2020
  9. 7/7 worktree: make "move" refuse to move atop missing registered worktreeEric Sunshine, Jun 10, 2020
  10. 4/7 worktree: prune duplicate entries referencing same worktree pathEric Sunshine, Jun 10, 2020
  11. Shourya ShuklaJun 10, 2020
  12. Eric SunshineJun 10, 2020
  13. Junio C HamanoJun 10, 2020

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.