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

[PATCH v2 2/3] worktree: rename worktree id during worktree move

From
Caleb White <cdwhite3@pm.me>
Date
Nov 29, 2024, 22:37 UTC
Message-ID
<20241129-wt_unique_ids-v2-2-ff444e9e625a@pm.me>
In-Reply-To
<20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me>

During a `worktree move` the worktree directory is moved/renamed but the repository under `worktrees/<id>` is not updated. For example, given the following structure:

    foo/
    ├── .git/worktrees/develop-5445874156/
    └── develop/
moving `develop` to `master` results in
    foo/
    ├── .git/worktrees/develop-5445874156/
    └── master/

This works because the linking files still point to the correct repository, but this is a little weird. This teaches Git to also move/rename the repository / worktree id during a `move` so that the structure now looks like:

    foo/
    ├── .git/worktrees/master-1565465986/
    └── master/

Note that a new unique suffix is assigned to reduce the complexity of trying to parse and reuse the existing suffix.

Signed-off-by: Caleb White <cdwhite3@pm.me>
---
 builtin/worktree.c       | 24 ++++++++++++++++++++++++
 t/t2403-worktree-move.sh | 18 +++++++++---------
 2 files changed, 33 insertions(+), 9 deletions(-)
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 3ad355ca762729401fc0c8625f4fd05b154a84ec..36235546b492803707707ff208b13fe777bff1b4 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -1202,9 +1202,14 @@ static int move_worktree(int ac, const char **av, const char *prefix)
 	};
 	struct worktree **worktrees, *wt;
 	struct strbuf dst = STRBUF_INIT;
+	struct strbuf repo = STRBUF_INIT;
+	struct strbuf repo_dst = STRBUF_INIT;
 	struct strbuf errmsg = STRBUF_INIT;
 	const char *reason = NULL;
+	const char *new_id;
+	const char *suffix;
 	char *path;
+	int len;
 
 	ac = parse_options(ac, av, prefix, options, git_worktree_move_usage,
 			   0);
@@ -1250,9 +1255,28 @@ static int move_worktree(int ac, const char **av, const char *prefix)
 	if (rename(wt->path, dst.buf) == -1)
 		die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf);
 
+	strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1);
+	new_id = worktree_basename(dst.buf, &len);
+	strbuf_add(&repo_dst, new_id, dst.buf + len - new_id);
+	strbuf_realpath(&repo_dst, git_common_path("worktrees/%s", repo_dst.buf), 1);
+	suffix = getenv("GIT_TEST_WORKTREE_SUFFIX");
+	if (suffix)
+		strbuf_addf(&repo_dst, "-%s", suffix);
+	else
+		strbuf_addf(&repo_dst, "-%u", git_rand());
+	new_id = strrchr(repo_dst.buf, '/') + 1;
+	if (rename(repo.buf, repo_dst.buf) == -1)
+		die_errno(_("failed to move '%s' to '%s'"), repo.buf, repo_dst.buf);
+	else {
+		free(wt->id);
+		wt->id = xstrdup(new_id);
+	}
+
 	update_worktree_location(wt, dst.buf, use_relative_paths);
 
 	strbuf_release(&dst);
+	strbuf_release(&repo);
+	strbuf_release(&repo_dst);
 	free_worktrees(worktrees);
 	return 0;
 }
diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh
index ba3f05c16a4969fb84d98052ae375ef162f3e73a..703aa58d10643e99ffaf803aa38dabfd4af68a10 100755
--- a/t/t2403-worktree-move.sh
+++ b/t/t2403-worktree-move.sh
@@ -250,26 +250,26 @@ test_expect_success 'not remove a repo with initialized submodule' '
 test_expect_success 'move worktree with absolute path to relative path' '
 	test_config worktree.useRelativePaths false &&
 	GIT_TEST_WORKTREE_SUFFIX=123 git worktree add ./absolute &&
-	git worktree move --relative-paths absolute relative &&
-	echo "gitdir: ../.git/worktrees/absolute-123" >expect &&
+	GIT_TEST_WORKTREE_SUFFIX=456 git worktree move --relative-paths absolute relative &&
+	echo "gitdir: ../.git/worktrees/relative-456" >expect &&
 	test_cmp expect relative/.git &&
 	echo "../../../relative/.git" >expect &&
-	test_cmp expect .git/worktrees/absolute-123/gitdir &&
+	test_cmp expect .git/worktrees/relative-456/gitdir &&
 	test_config worktree.useRelativePaths true &&
-	git worktree move relative relative2 &&
-	echo "gitdir: ../.git/worktrees/absolute-123" >expect &&
+	GIT_TEST_WORKTREE_SUFFIX=789 git worktree move relative relative2 &&
+	echo "gitdir: ../.git/worktrees/relative2-789" >expect &&
 	test_cmp expect relative2/.git &&
 	echo "../../../relative2/.git" >expect &&
-	test_cmp expect .git/worktrees/absolute-123/gitdir
+	test_cmp expect .git/worktrees/relative2-789/gitdir
 '
 
 test_expect_success 'move worktree with relative path to absolute path' '
 	test_config worktree.useRelativePaths true &&
-	git worktree move --no-relative-paths relative2 absolute &&
-	echo "gitdir: $(pwd)/.git/worktrees/absolute-123" >expect &&
+	GIT_TEST_WORKTREE_SUFFIX=851 git worktree move --no-relative-paths relative2 absolute &&
+	echo "gitdir: $(pwd)/.git/worktrees/absolute-851" >expect &&
 	test_cmp expect absolute/.git &&
 	echo "$(pwd)/absolute/.git" >expect &&
-	test_cmp expect .git/worktrees/absolute-123/gitdir
+	test_cmp expect .git/worktrees/absolute-851/gitdir
 '
 
 test_done
-- 
2.47.0
Previous: Caleb WhiteNext: Caleb White
Message 3 of 24 in “Ensure unique worktree ids across repositories”
  1. 0/3 Ensure unique worktree ids across repositoriesCaleb White, Nov 29, 2024
  2. 1/3 worktree: add worktree with unique suffixCaleb White, Nov 29, 2024
  3. 2/3 worktree: rename worktree id during worktree moveCaleb White, Nov 29, 2024
  4. 3/3 worktree: add id to `worktree list` outputCaleb White, Nov 29, 2024
  5. rsbecker@nexbridge.comNov 29, 2024
  6. Caleb WhiteNov 29, 2024
  7. rsbecker@nexbridge.comNov 29, 2024
  8. Caleb WhiteNov 29, 2024
  9. rsbecker@nexbridge.comNov 29, 2024
  10. Caleb WhiteNov 30, 2024
  11. rsbecker@nexbridge.comNov 30, 2024
  12. Caleb WhiteNov 30, 2024
  13. rsbecker@nexbridge.comNov 30, 2024
  14. Junio C HamanoDec 2, 2024
  15. shejialuoDec 2, 2024
  16. Junio C HamanoDec 3, 2024
  17. Eric SunshineDec 3, 2024
  18. Junio C HamanoDec 3, 2024
  19. rsbecker@nexbridge.comDec 3, 2024
  20. Junio C HamanoDec 3, 2024
  21. Caleb WhiteDec 3, 2024
  22. Junio C HamanoDec 3, 2024
  23. Caleb WhiteDec 3, 2024
  24. shejialuoDec 3, 2024

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.