{"thread":{"id":"62572","subject":"[PATCH v2 0/3] Ensure unique worktree ids across repositories","startedAt":"2024-11-29T22:37:45Z","lastAt":"2024-12-03T05:31:51Z","messageCount":24,"participants":["Caleb White","rsbecker@nexbridge.com","Junio C Hamano","shejialuo","Eric Sunshine"],"isPatch":true,"patchVersion":2,"patchTotal":3},"messages":[{"id":"508357","messageId":"20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me","threadId":"62572","inReplyTo":null,"subject":"[PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-29T22:37:34Z","receivedAt":"2024-11-29T22:37:45Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"The `es/worktree-repair-copied` topic added support for repairing a\nworktree from a copy scenario. I noted[1,2] that the topic added the\nability for a repository to \"take over\" a worktree from another\nrepository if the worktree_id matched a worktree inside the current\nrepository which can happen if two repositories use the same worktree name.\n\nThis series teaches Git to create worktrees with a unique suffix so\nthat the worktree_id is unique across all repositories even if they have\nthe same name. For example creating a worktree `develop` would look like:\n\n    foo/\n    ├── .git/worktrees/develop-5445874156/\n    └── develop/\n    bar/\n    ├── .git/worktrees/develop-1549518426/\n    └── develop/\n\nThe actual worktree directory name is still `develop`, but the\nworktree_id is unique and prevents the \"take over\" scenario. The suffix\nis given by the `git_rand()` function which should be sufficient to\nensure that the suffix is effectively unique (the likelihood of\na collision with the same name and suffix is extremely low).\n\nDuring a `worktree move` the worktree directory is moved/renamed but the\nrepository under `worktrees/<id>` is not updated. For example, moving\n`develop` to `master` results in\n\n    foo/\n    ├── .git/worktrees/develop-5445874156/\n    └── master/\n\nThis works because the linking files still point to the correct\nrepository, but this is a little weird. This series teaches Git to also\nmove/rename the repository / worktree id during a `move` so that the\nstructure now looks like:\n\n    foo/\n    ├── .git/worktrees/master-1565465986/\n    └── master/\n\nNote that a new unique suffix is assigned to reduce the complexity of\ntrying to parse and reuse the existing suffix.\n\nAdditionally, this series teaches `worktree list` to output the worktree\nid in the verbose and porcelain modes, which allows users and scripts to\nmore easily obtain the id for a given worktree.\n\n[1]: https://lore.kernel.org/git/20241008153035.71178-1-cdwhite3@pm.me/\n[2]: https://lore.kernel.org/git/r4zmcET41Skr_FMop47AKd7cms9E8bKPSvHuAUpnYavzKEY6JybJta0_7GfuYB0q-gD-XNcvh5VDTfiT3qthGKjqhS1sbT4M2lUABynOz2Q=@pm.me/\n\nSigned-off-by: Caleb White <cdwhite3@pm.me>\n---\nThe base for this series is obtained by merging the `cw/worktree-extension`\ntopic (2024-11-26, 20241125-wt_relative_options-v5-0-356d122ff3db@pm.me)\nonto 090d24e9af.\n\nChanges in v2:\n- Add the worktree id to `worktree list` output\n- Updated cover letter\n- Link to v1: https://lore.kernel.org/r/20241128-wt_unique_ids-v1-0-30345d010e43@pm.me\n\n---\nCaleb White (3):\n      worktree: add worktree with unique suffix\n      worktree: rename worktree id during worktree move\n      worktree: add id to `worktree list` output\n\n Documentation/git-worktree.txt     | 17 +++++--\n builtin/worktree.c                 | 35 ++++++++++++++\n t/t0035-safe-bare-repository.sh    |  4 +-\n t/t0600-reffiles-backend.sh        | 10 ++--\n t/t0601-reffiles-pack-refs.sh      |  4 +-\n t/t0610-reftable-basics.sh         | 54 +++++++++++-----------\n t/t1407-worktree-ref-store.sh      |  4 +-\n t/t1410-reflog.sh                  | 10 ++--\n t/t1415-worktree-refs.sh           | 26 +++++------\n t/t1450-fsck.sh                    | 14 +++---\n t/t1500-rev-parse.sh               |  6 +--\n t/t2400-worktree-add.sh            | 51 +++++++++++----------\n t/t2401-worktree-prune.sh          | 20 ++++----\n t/t2402-worktree-list.sh           | 16 ++++---\n t/t2403-worktree-move.sh           | 38 ++++++++--------\n t/t2405-worktree-submodule.sh      | 10 ++--\n t/t2406-worktree-repair.sh         | 93 ++++++++++++++++++++++++--------------\n t/t2407-worktree-heads.sh          | 27 +++++------\n t/t3200-branch.sh                  | 10 ++--\n t/t5304-prune.sh                   |  2 +-\n t/t7412-submodule-absorbgitdirs.sh |  4 +-\n 21 files changed, 265 insertions(+), 190 deletions(-)\n---\nbase-commit: 090d24e9af6e9f59c3f7bee97c42bb1ae3c7f559\nchange-id: 20241127-wt_unique_ids-1ffd7ea0bb19\nprerequisite-change-id: 20241025-wt_relative_options-afa41987bc32:v6\nprerequisite-patch-id: 179410e257e8eedf100f4f9faa9467cbbba4d61b\nprerequisite-patch-id: 56ffe0afeadd511c9eef5f548a371659b040acab\nprerequisite-patch-id: 809c1314e5dfa966f4f3d73b52f286f8aa89370f\nprerequisite-patch-id: cf5f9491c8f8e58d1e0e103a5f8c64c55f2896e3\nprerequisite-patch-id: 9884b33822bf4c7c3b89a9a6b49d4ab44c2670e7\nprerequisite-patch-id: 62a09496d98d78a6bd1f9150ba887ee72359c7ee\nprerequisite-patch-id: 5527e4b745963dd4fa08029491fcbfe3d91d5104\nprerequisite-patch-id: bf433443e90939a493fa586de30938f78cb77020\n\nBest regards,\n-- \nCaleb White <cdwhite3@pm.me>\n\n\n"},{"id":"508358","messageId":"20241129-wt_unique_ids-v2-1-ff444e9e625a@pm.me","threadId":"62572","inReplyTo":"20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me","subject":"[PATCH v2 1/3] worktree: add worktree with unique suffix","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-29T22:37:44Z","receivedAt":"2024-11-29T22:37:53Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"The `es/worktree-repair-copied` topic added support for repairing a\nworktree from a copy scenario. However, the topic added the\nability for a repository to \"take over\" a worktree from another\nrepository if the worktree_id matched a worktree inside the current\nrepository which can happen if two repositories use the same worktree name.\n\nThis teaches Git to create worktrees with a unique suffix so the\nworktree_id is unique across all repositories even if they have the\nsame name. For example creating a worktree `develop` would look like:\n\n    foo/\n    ├── .git/worktrees/develop-5445874156/\n    └── develop/\n    bar/\n    ├── .git/worktrees/develop-1549518426/\n    └── develop/\n\nThe actual worktree directory name is still `develop`, but the\nworktree_id is unique and prevents the \"take over\" scenario. The suffix\nis given by the `git_rand()` function. Worktree ids can already differ\nfrom the actual directory name (appended with a number like `develop1`)\nif the worktree name was already taken, so this should not be a\ndrastic change.\n\nSigned-off-by: Caleb White <cdwhite3@pm.me>\n---\n Documentation/git-worktree.txt     |  5 +-\n builtin/worktree.c                 |  6 +++\n t/t0035-safe-bare-repository.sh    |  4 +-\n t/t0600-reffiles-backend.sh        | 10 ++--\n t/t0601-reffiles-pack-refs.sh      |  4 +-\n t/t0610-reftable-basics.sh         | 54 +++++++++++-----------\n t/t1407-worktree-ref-store.sh      |  4 +-\n t/t1410-reflog.sh                  | 10 ++--\n t/t1415-worktree-refs.sh           | 26 +++++------\n t/t1450-fsck.sh                    | 14 +++---\n t/t1500-rev-parse.sh               |  6 +--\n t/t2400-worktree-add.sh            | 51 +++++++++++----------\n t/t2401-worktree-prune.sh          | 20 ++++----\n t/t2403-worktree-move.sh           | 32 ++++++-------\n t/t2405-worktree-submodule.sh      | 10 ++--\n t/t2406-worktree-repair.sh         | 93 ++++++++++++++++++++++++--------------\n t/t2407-worktree-heads.sh          | 27 +++++------\n t/t3200-branch.sh                  | 10 ++--\n t/t5304-prune.sh                   |  2 +-\n t/t7412-submodule-absorbgitdirs.sh |  4 +-\n 20 files changed, 212 insertions(+), 180 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex 8340b7f028e6c1c3bae3de0879e9754098466d14..e0604b043361828f94b58f676a5ed4f15b116348 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -352,12 +352,11 @@ DETAILS\n -------\n Each linked worktree has a private sub-directory in the repository's\n `$GIT_DIR/worktrees` directory.  The private sub-directory's name is usually\n-the base name of the linked worktree's path, possibly appended with a\n+the base name of the linked worktree's path, appended with a random\n number to make it unique.  For example, when `$GIT_DIR=/path/main/.git` the\n command `git worktree add /path/other/test-next next` creates the linked\n worktree in `/path/other/test-next` and also creates a\n-`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1`\n-if `test-next` is already taken).\n+`$GIT_DIR/worktrees/test-next-#######` directory.\n \n Within a linked worktree, `$GIT_DIR` is set to point to this private\n directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex fde9ff4dc9a734c655e95ccd62774282950cbba6..3ad355ca762729401fc0c8625f4fd05b154a84ec 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -421,6 +421,7 @@ static int add_worktree(const char *path, const char *refname,\n \tstruct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;\n \tstruct strbuf sb = STRBUF_INIT;\n \tconst char *name;\n+\tconst char *suffix;\n \tstruct strvec child_env = STRVEC_INIT;\n \tunsigned int counter = 0;\n \tint len, ret;\n@@ -455,6 +456,11 @@ static int add_worktree(const char *path, const char *refname,\n \tstrbuf_reset(&sb);\n \tname = sb_name.buf;\n \tgit_path_buf(&sb_repo, \"worktrees/%s\", name);\n+\tsuffix = getenv(\"GIT_TEST_WORKTREE_SUFFIX\");\n+\tif (suffix)\n+\t\tstrbuf_addf(&sb_repo, \"-%s\", suffix);\n+\telse\n+\t\tstrbuf_addf(&sb_repo, \"-%u\", git_rand());\n \tlen = sb_repo.len;\n \tif (safe_create_leading_directories_const(sb_repo.buf))\n \t\tdie_errno(_(\"could not create leading directories of '%s'\"),\ndiff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh\nindex d3cb2a1cb9edb8f9ad7480be6ec3e02b464046bd..30cbf7fd32e2e4afd6d680e0328ee18b791778da 100755\n--- a/t/t0035-safe-bare-repository.sh\n+++ b/t/t0035-safe-bare-repository.sh\n@@ -41,7 +41,7 @@ test_expect_success 'setup an embedded bare repo, secondary worktree and submodu\n \t\tgit -c protocol.file.allow=always \\\n \t\t\tsubmodule add --name subn -- ./bare-repo subd\n \t) &&\n-\ttest_path_is_dir outer-repo/.git/worktrees/outer-secondary &&\n+\ttest_path_is_dir outer-repo/.git/worktrees/outer-secondary-* &&\n \ttest_path_is_dir outer-repo/.git/modules/subn\n '\n \n@@ -97,7 +97,7 @@ test_expect_success 'no trace when \"bare repository\" is a subdir of .git' '\n '\n \n test_expect_success 'no trace in $GIT_DIR of secondary worktree' '\n-\texpect_accepted_implicit -C outer-repo/.git/worktrees/outer-secondary\n+\texpect_accepted_implicit -C outer-repo/.git/worktrees/outer-secondary-*\n '\n \n test_expect_success 'no trace in $GIT_DIR of a submodule' '\ndiff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh\nindex bef2b70871364931ab8b3ead950f59d11b6fe216..8da81b1ae34f5f095ba9406e8f031fd5e43ac789 100755\n--- a/t/t0600-reffiles-backend.sh\n+++ b/t/t0600-reffiles-backend.sh\n@@ -256,12 +256,12 @@ test_expect_success 'delete fails cleanly if packed-refs.new write fails' '\n \ttest_cmp unchanged actual\n '\n \n-RWT=\"test-tool ref-store worktree:wt\"\n+RWT=\"test-tool ref-store worktree:wt-123\"\n RMAIN=\"test-tool ref-store worktree:main\"\n \n test_expect_success 'setup worktree' '\n \ttest_commit first &&\n-\tgit worktree add -b wt-main wt &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add -b wt-main wt &&\n \t(\n \t\tcd wt &&\n \t\ttest_commit second\n@@ -279,9 +279,9 @@ test_expect_success 'for_each_reflog()' '\n \tmkdir -p     .git/logs/refs/bisect &&\n \techo $ZERO_OID >.git/logs/refs/bisect/random &&\n \n-\techo $ZERO_OID >.git/worktrees/wt/logs/PSEUDO_WT_HEAD &&\n-\tmkdir -p     .git/worktrees/wt/logs/refs/bisect &&\n-\techo $ZERO_OID >.git/worktrees/wt/logs/refs/bisect/wt-random &&\n+\techo $ZERO_OID >.git/worktrees/wt-123/logs/PSEUDO_WT_HEAD &&\n+\tmkdir -p     .git/worktrees/wt-123/logs/refs/bisect &&\n+\techo $ZERO_OID >.git/worktrees/wt-123/logs/refs/bisect/wt-random &&\n \n \t$RWT for-each-reflog >actual &&\n \tcat >expected <<-\\EOF &&\ndiff --git a/t/t0601-reffiles-pack-refs.sh b/t/t0601-reffiles-pack-refs.sh\nindex d8cbd3f202b5f00c9a94c5a2ea2dced6606b6f4d..d6597938caca5e6c3a6e86b860f3c0d309aa2140 100755\n--- a/t/t0601-reffiles-pack-refs.sh\n+++ b/t/t0601-reffiles-pack-refs.sh\n@@ -326,8 +326,8 @@ test_expect_success 'refs/worktree must not be packed' '\n \tgit pack-refs --all &&\n \ttest_path_is_missing .git/refs/tags/wt1 &&\n \ttest_path_is_file .git/refs/worktree/foo &&\n-\ttest_path_is_file .git/worktrees/wt1/refs/worktree/foo &&\n-\ttest_path_is_file .git/worktrees/wt2/refs/worktree/foo\n+\ttest_path_is_file .git/worktrees/wt1-*/refs/worktree/foo &&\n+\ttest_path_is_file .git/worktrees/wt2-*/refs/worktree/foo\n '\n \n # we do not want to count on running pack-refs to\ndiff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh\nindex eaf6fab6d29f01430abae3c7abf5a750d4271a36..f21fd9dbba2b77636045b297073e340209d61a2d 100755\n--- a/t/t0610-reftable-basics.sh\n+++ b/t/t0610-reftable-basics.sh\n@@ -965,11 +965,11 @@ test_expect_success 'worktree: adding worktree creates separate stack' '\n \ttest_commit -C repo A &&\n \n \tgit -C repo worktree add ../worktree &&\n-\ttest_path_is_file repo/.git/worktrees/worktree/refs/heads &&\n+\ttest_path_is_file repo/.git/worktrees/worktree-*/refs/heads &&\n \techo \"ref: refs/heads/.invalid\" >expect &&\n-\ttest_cmp expect repo/.git/worktrees/worktree/HEAD &&\n-\ttest_path_is_dir repo/.git/worktrees/worktree/reftable &&\n-\ttest_path_is_file repo/.git/worktrees/worktree/reftable/tables.list\n+\ttest_cmp expect repo/.git/worktrees/worktree-*/HEAD &&\n+\ttest_path_is_dir repo/.git/worktrees/worktree-*/reftable &&\n+\ttest_path_is_file repo/.git/worktrees/worktree-*/reftable/tables.list\n '\n \n test_expect_success 'worktree: pack-refs in main repo packs main refs' '\n@@ -982,10 +982,10 @@ test_expect_success 'worktree: pack-refs in main repo packs main refs' '\n \tGIT_TEST_REFTABLE_AUTOCOMPACTION=false \\\n \tgit -C worktree update-ref refs/worktree/per-worktree HEAD &&\n \n-\ttest_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 4 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 3 repo/.git/reftable/tables.list &&\n \tgit -C repo pack-refs &&\n-\ttest_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 4 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list\n '\n \n@@ -999,10 +999,10 @@ test_expect_success 'worktree: pack-refs in worktree packs worktree refs' '\n \tGIT_TEST_REFTABLE_AUTOCOMPACTION=false \\\n \tgit -C worktree update-ref refs/worktree/per-worktree HEAD &&\n \n-\ttest_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 4 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 3 repo/.git/reftable/tables.list &&\n \tgit -C worktree pack-refs &&\n-\ttest_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 3 repo/.git/reftable/tables.list\n '\n \n@@ -1014,12 +1014,12 @@ test_expect_success 'worktree: creating shared ref updates main stack' '\n \tgit -C repo worktree add ../worktree &&\n \tgit -C repo pack-refs &&\n \tgit -C worktree pack-refs &&\n-\ttest_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list &&\n \n \tGIT_TEST_REFTABLE_AUTOCOMPACTION=false \\\n \tgit -C worktree update-ref refs/heads/shared HEAD &&\n-\ttest_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 2 repo/.git/reftable/tables.list\n '\n \n@@ -1031,11 +1031,11 @@ test_expect_success 'worktree: creating per-worktree ref updates worktree stack'\n \tgit -C repo worktree add ../worktree &&\n \tgit -C repo pack-refs &&\n \tgit -C worktree pack-refs &&\n-\ttest_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list &&\n \n \tgit -C worktree update-ref refs/bisect/per-worktree HEAD &&\n-\ttest_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 2 repo/.git/worktrees/worktree-*/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list\n '\n \n@@ -1044,14 +1044,14 @@ test_expect_success 'worktree: creating per-worktree ref from main repo' '\n \tgit init repo &&\n \ttest_commit -C repo A &&\n \n-\tgit -C repo worktree add ../worktree &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git -C repo worktree add ../worktree &&\n \tgit -C repo pack-refs &&\n \tgit -C worktree pack-refs &&\n-\ttest_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/worktree-456/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list &&\n \n-\tgit -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD &&\n-\ttest_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\tgit -C repo update-ref worktrees/worktree-456/refs/bisect/per-worktree HEAD &&\n+\ttest_line_count = 2 repo/.git/worktrees/worktree-456/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list\n '\n \n@@ -1060,18 +1060,18 @@ test_expect_success 'worktree: creating per-worktree ref from second worktree' '\n \tgit init repo &&\n \ttest_commit -C repo A &&\n \n-\tgit -C repo worktree add ../wt1 &&\n-\tgit -C repo worktree add ../wt2 &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git -C repo worktree add ../wt1 &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git -C repo worktree add ../wt2 &&\n \tgit -C repo pack-refs &&\n \tgit -C wt1 pack-refs &&\n \tgit -C wt2 pack-refs &&\n-\ttest_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&\n-\ttest_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/wt1-123/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/wt2-456/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list &&\n \n-\tgit -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD &&\n-\ttest_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list &&\n-\ttest_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list &&\n+\tgit -C wt1 update-ref worktrees/wt2-456/refs/bisect/per-worktree HEAD &&\n+\ttest_line_count = 1 repo/.git/worktrees/wt1-123/reftable/tables.list &&\n+\ttest_line_count = 2 repo/.git/worktrees/wt2-456/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list\n '\n \n@@ -1080,18 +1080,18 @@ test_expect_success 'worktree: can create shared and per-worktree ref in one tra\n \tgit init repo &&\n \ttest_commit -C repo A &&\n \n-\tgit -C repo worktree add ../worktree &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git -C repo worktree add ../worktree &&\n \tgit -C repo pack-refs &&\n \tgit -C worktree pack-refs &&\n-\ttest_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 1 repo/.git/worktrees/worktree-123/reftable/tables.list &&\n \ttest_line_count = 1 repo/.git/reftable/tables.list &&\n \n \tcat >stdin <<-EOF &&\n-\tcreate worktrees/worktree/refs/bisect/per-worktree HEAD\n+\tcreate worktrees/worktree-123/refs/bisect/per-worktree HEAD\n \tcreate refs/branches/shared HEAD\n \tEOF\n \tgit -C repo update-ref --stdin <stdin &&\n-\ttest_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list &&\n+\ttest_line_count = 2 repo/.git/worktrees/worktree-123/reftable/tables.list &&\n \ttest_line_count = 2 repo/.git/reftable/tables.list\n '\n \ndiff --git a/t/t1407-worktree-ref-store.sh b/t/t1407-worktree-ref-store.sh\nindex 48b1c92a41450b25645d6cd782aa86c8e630164b..4d081627a1e6b55936cd4051ed760fa92e7cdc02 100755\n--- a/t/t1407-worktree-ref-store.sh\n+++ b/t/t1407-worktree-ref-store.sh\n@@ -8,12 +8,12 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n-RWT=\"test-tool ref-store worktree:wt\"\n+RWT=\"test-tool ref-store worktree:wt-456\"\n RMAIN=\"test-tool ref-store worktree:main\"\n \n test_expect_success 'setup' '\n \ttest_commit first &&\n-\tgit worktree add -b wt-main wt &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree add -b wt-main wt &&\n \t(\n \t\tcd wt &&\n \t\ttest_commit second\ndiff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh\nindex 246a3f46abafdf0e24528be59b33a4987ff791c1..c1b6b4d8fab8d261713a192478af12179f9bc917 100755\n--- a/t/t1410-reflog.sh\n+++ b/t/t1410-reflog.sh\n@@ -402,12 +402,12 @@ test_expect_success 'expire with multiple worktrees' '\n \t\tcd main-wt &&\n \t\ttest_tick &&\n \t\ttest_commit foo &&\n-\t\tgit  worktree add link-wt &&\n+\t\tGIT_TEST_WORKTREE_SUFFIX=123 git  worktree add link-wt &&\n \t\ttest_tick &&\n \t\ttest_commit -C link-wt foobar &&\n \t\ttest_tick &&\n \t\tgit reflog expire --verbose --all --expire=$test_tick &&\n-\t\ttest-tool ref-store worktree:link-wt for-each-reflog-ent HEAD >actual &&\n+\t\ttest-tool ref-store worktree:link-wt-123 for-each-reflog-ent HEAD >actual &&\n \t\ttest_must_be_empty actual\n \t)\n '\n@@ -418,17 +418,17 @@ test_expect_success 'expire one of multiple worktrees' '\n \t\tcd main-wt2 &&\n \t\ttest_tick &&\n \t\ttest_commit foo &&\n-\t\tgit worktree add link-wt &&\n+\t\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree add link-wt &&\n \t\ttest_tick &&\n \t\ttest_commit -C link-wt foobar &&\n \t\ttest_tick &&\n-\t\ttest-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \\\n+\t\ttest-tool ref-store worktree:link-wt-456 for-each-reflog-ent HEAD \\\n \t\t\t>expect-link-wt &&\n \t\tgit reflog expire --verbose --all --expire=$test_tick \\\n \t\t\t--single-worktree &&\n \t\ttest-tool ref-store worktree:main for-each-reflog-ent HEAD \\\n \t\t\t>actual-main &&\n-\t\ttest-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \\\n+\t\ttest-tool ref-store worktree:link-wt-456 for-each-reflog-ent HEAD \\\n \t\t\t>actual-link-wt &&\n \t\ttest_must_be_empty actual-main &&\n \t\ttest_cmp expect-link-wt actual-link-wt\ndiff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh\nindex eb4eec8becbfa64efcde4e866334363a866c01a2..c46bf29aa4d9ceac85147d685a1d23144ec23b2b 100755\n--- a/t/t1415-worktree-refs.sh\n+++ b/t/t1415-worktree-refs.sh\n@@ -9,8 +9,8 @@ test_expect_success 'setup' '\n \ttest_commit initial &&\n \ttest_commit wt1 &&\n \ttest_commit wt2 &&\n-\tgit worktree add wt1 wt1 &&\n-\tgit worktree add wt2 wt2 &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add wt1 wt1 &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree add wt2 wt2 &&\n \tgit checkout initial &&\n \tgit update-ref refs/worktree/foo HEAD &&\n \tgit -C wt1 update-ref refs/worktree/foo HEAD &&\n@@ -37,16 +37,16 @@ test_expect_success 'ambiguous main-worktree/HEAD' '\n '\n \n test_expect_success 'resolve worktrees/xx/HEAD' '\n-\ttest_cmp_rev worktrees/wt1/HEAD wt1 &&\n-\t( cd wt1 && test_cmp_rev worktrees/wt1/HEAD wt1 ) &&\n-\t( cd wt2 && test_cmp_rev worktrees/wt1/HEAD wt1 )\n+\ttest_cmp_rev worktrees/wt1-123/HEAD wt1 &&\n+\t( cd wt1 && test_cmp_rev worktrees/wt1-123/HEAD wt1 ) &&\n+\t( cd wt2 && test_cmp_rev worktrees/wt1-123/HEAD wt1 )\n '\n \n test_expect_success 'ambiguous worktrees/xx/HEAD' '\n-\tgit update-ref refs/heads/worktrees/wt1/HEAD $(git rev-parse HEAD) &&\n-\ttest_when_finished git update-ref -d refs/heads/worktrees/wt1/HEAD &&\n-\tgit rev-parse worktrees/wt1/HEAD 2>warn &&\n-\tgrep \"worktrees/wt1/HEAD.*ambiguous\" warn\n+\tgit update-ref refs/heads/worktrees/wt1-123/HEAD $(git rev-parse HEAD) &&\n+\ttest_when_finished git update-ref -d refs/heads/worktrees/wt1-123/HEAD &&\n+\tgit rev-parse worktrees/wt1-123/HEAD 2>warn &&\n+\tgrep \"worktrees/wt1-123/HEAD.*ambiguous\" warn\n '\n \n test_expect_success 'reflog of main-worktree/HEAD' '\n@@ -58,12 +58,12 @@ test_expect_success 'reflog of main-worktree/HEAD' '\n '\n \n test_expect_success 'reflog of worktrees/xx/HEAD' '\n-\tgit -C wt2 reflog HEAD | sed \"s/HEAD/worktrees\\/wt2\\/HEAD/\" >expected &&\n-\tgit reflog worktrees/wt2/HEAD >actual &&\n+\tgit -C wt2 reflog HEAD | sed \"s/HEAD/worktrees\\/wt2-456\\/HEAD/\" >expected &&\n+\tgit reflog worktrees/wt2-456/HEAD >actual &&\n \ttest_cmp expected actual &&\n-\tgit -C wt1 reflog worktrees/wt2/HEAD >actual.wt1 &&\n+\tgit -C wt1 reflog worktrees/wt2-456/HEAD >actual.wt1 &&\n \ttest_cmp expected actual.wt1 &&\n-\tgit -C wt2 reflog worktrees/wt2/HEAD >actual.wt2 &&\n+\tgit -C wt2 reflog worktrees/wt2-456/HEAD >actual.wt2 &&\n \ttest_cmp expected actual.wt2\n '\n \ndiff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh\nindex 280cbf3e031e1ab67ed28aa2af4c3b105b7d254e..de25ab24fd8924e288969650a658908a5e9afd22 100755\n--- a/t/t1450-fsck.sh\n+++ b/t/t1450-fsck.sh\n@@ -152,10 +152,10 @@ test_expect_success REFFILES 'HEAD link pointing at a funny object (from differe\n \n test_expect_success REFFILES 'other worktree HEAD link pointing at a funny object' '\n \ttest_when_finished \"git worktree remove -f other\" &&\n-\tgit worktree add other &&\n-\techo $ZERO_OID >.git/worktrees/other/HEAD &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add other &&\n+\techo $ZERO_OID >.git/worktrees/other-123/HEAD &&\n \ttest_must_fail git fsck 2>out &&\n-\ttest_grep \"worktrees/other/HEAD: detached HEAD points\" out\n+\ttest_grep \"worktrees/other-123/HEAD: detached HEAD points\" out\n '\n \n test_expect_success 'other worktree HEAD link pointing at missing object' '\n@@ -164,7 +164,7 @@ test_expect_success 'other worktree HEAD link pointing at missing object' '\n \tobject_id=$(echo \"Contents missing from repo\" | git hash-object --stdin) &&\n \ttest-tool -C other ref-store main update-ref msg HEAD $object_id \"\" REF_NO_DEREF,REF_SKIP_OID_VERIFICATION &&\n \ttest_must_fail git fsck 2>out &&\n-\ttest_grep \"worktrees/other/HEAD: invalid sha1 pointer\" out\n+\ttest_grep \"worktrees/other-.*/HEAD: invalid sha1 pointer\" out\n '\n \n test_expect_success 'other worktree HEAD link pointing at a funny place' '\n@@ -172,7 +172,7 @@ test_expect_success 'other worktree HEAD link pointing at a funny place' '\n \tgit worktree add other &&\n \tgit -C other symbolic-ref HEAD refs/funny/place &&\n \ttest_must_fail git fsck 2>out &&\n-\ttest_grep \"worktrees/other/HEAD points to something strange\" out\n+\ttest_grep \"worktrees/other-.*/HEAD points to something strange\" out\n '\n \n test_expect_success 'commit with multiple signatures is okay' '\n@@ -1033,7 +1033,7 @@ test_expect_success 'fsck error on gitattributes with excessive size' '\n \n test_expect_success 'fsck detects problems in worktree index' '\n \ttest_when_finished \"git worktree remove -f wt\" &&\n-\tgit worktree add wt &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add wt &&\n \n \techo \"this will be removed to break the worktree index\" >wt/file &&\n \tgit -C wt add file &&\n@@ -1042,7 +1042,7 @@ test_expect_success 'fsck detects problems in worktree index' '\n \n \ttest_must_fail git fsck --name-objects >actual 2>&1 &&\n \tcat >expect <<-EOF &&\n-\tmissing blob $blob (.git/worktrees/wt/index:file)\n+\tmissing blob $blob (.git/worktrees/wt-123/index:file)\n \tEOF\n \ttest_cmp expect actual\n '\ndiff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh\nindex 30c31918fde6539d52800e18dfbb3423b5b73491..49e0ac68858d922336a498caaa743f2f4011d28a 100755\n--- a/t/t1500-rev-parse.sh\n+++ b/t/t1500-rev-parse.sh\n@@ -80,7 +80,7 @@ test_expect_success 'setup' '\n \tgit checkout -b side &&\n \ttest_commit def &&\n \tgit checkout main &&\n-\tgit worktree add worktree side\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add worktree side\n '\n \n test_rev_parse toplevel false false true '' .git \"$ROOT/.git\"\n@@ -113,7 +113,7 @@ test_expect_success 'rev-parse --path-format=absolute' '\n \ttest_one \".\" \"$ROOT/.git\" --path-format=absolute --git-common-dir &&\n \ttest_one \"sub/dir\" \"$ROOT/.git\" --path-format=absolute --git-dir &&\n \ttest_one \"sub/dir\" \"$ROOT/.git\" --path-format=absolute --git-common-dir &&\n-\ttest_one \"worktree\" \"$ROOT/.git/worktrees/worktree\" --path-format=absolute --git-dir &&\n+\ttest_one \"worktree\" \"$ROOT/.git/worktrees/worktree-123\" --path-format=absolute --git-dir &&\n \ttest_one \"worktree\" \"$ROOT/.git\" --path-format=absolute --git-common-dir &&\n \ttest_one \".\" \"$ROOT\" --path-format=absolute --show-toplevel &&\n \ttest_one \".\" \"$ROOT/.git/objects\" --path-format=absolute --git-path objects &&\n@@ -125,7 +125,7 @@ test_expect_success 'rev-parse --path-format=relative' '\n \ttest_one \".\" \".git\" --path-format=relative --git-common-dir &&\n \ttest_one \"sub/dir\" \"../../.git\" --path-format=relative --git-dir &&\n \ttest_one \"sub/dir\" \"../../.git\" --path-format=relative --git-common-dir &&\n-\ttest_one \"worktree\" \"../.git/worktrees/worktree\" --path-format=relative --git-dir &&\n+\ttest_one \"worktree\" \"../.git/worktrees/worktree-123\" --path-format=relative --git-dir &&\n \ttest_one \"worktree\" \"../.git\" --path-format=relative --git-common-dir &&\n \ttest_one \".\" \"./\" --path-format=relative --show-toplevel &&\n \ttest_one \".\" \".git/objects\" --path-format=relative --git-path objects &&\ndiff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh\nindex bc4f4e90d6ecfedbde9082bda6f9e4eec3e3575d..33262b49f18521c805f188a10f944dbfa9f285ba 100755\n--- a/t/t2400-worktree-add.sh\n+++ b/t/t2400-worktree-add.sh\n@@ -71,21 +71,21 @@ test_expect_success '\"add\" worktree' '\n test_expect_success '\"add\" worktree with lock' '\n \tgit worktree add --detach --lock here-with-lock main &&\n \ttest_when_finished \"git worktree unlock here-with-lock || :\" &&\n-\ttest -f .git/worktrees/here-with-lock/locked\n+\ttest -f .git/worktrees/here-with-lock-*/locked\n '\n \n test_expect_success '\"add\" worktree with lock and reason' '\n \tlock_reason=\"why not\" &&\n \tgit worktree add --detach --lock --reason \"$lock_reason\" here-with-lock-reason main &&\n \ttest_when_finished \"git worktree unlock here-with-lock-reason || :\" &&\n-\ttest -f .git/worktrees/here-with-lock-reason/locked &&\n+\ttest -f .git/worktrees/here-with-lock-reason-*/locked &&\n \techo \"$lock_reason\" >expect &&\n-\ttest_cmp expect .git/worktrees/here-with-lock-reason/locked\n+\ttest_cmp expect .git/worktrees/here-with-lock-reason-*/locked\n '\n \n test_expect_success '\"add\" worktree with reason but no lock' '\n \ttest_must_fail git worktree add --detach --reason \"why not\" here-with-reason-only main &&\n-\ttest_path_is_missing .git/worktrees/here-with-reason-only/locked\n+\ttest_path_is_missing .git/worktrees/here-with-reason-only-*/locked\n '\n \n test_expect_success '\"add\" worktree from a subdir' '\n@@ -413,16 +413,16 @@ test_expect_success '\"add --orphan\" with empty repository' '\n test_expect_success '\"add\" worktree with orphan branch and lock' '\n \tgit worktree add --lock --orphan -b orphanbr orphan-with-lock &&\n \ttest_when_finished \"git worktree unlock orphan-with-lock || :\" &&\n-\ttest -f .git/worktrees/orphan-with-lock/locked\n+\ttest -f .git/worktrees/orphan-with-lock-*/locked\n '\n \n test_expect_success '\"add\" worktree with orphan branch, lock, and reason' '\n \tlock_reason=\"why not\" &&\n \tgit worktree add --detach --lock --reason \"$lock_reason\" orphan-with-lock-reason main &&\n \ttest_when_finished \"git worktree unlock orphan-with-lock-reason || :\" &&\n-\ttest -f .git/worktrees/orphan-with-lock-reason/locked &&\n+\ttest -f .git/worktrees/orphan-with-lock-reason-*/locked &&\n \techo \"$lock_reason\" >expect &&\n-\ttest_cmp expect .git/worktrees/orphan-with-lock-reason/locked\n+\ttest_cmp expect .git/worktrees/orphan-with-lock-reason-*/locked\n '\n \n # Note: Quoted arguments containing spaces are not supported.\n@@ -1088,10 +1088,10 @@ test_expect_success '\"add\" invokes post-checkout hook (branch)' '\n \tpost_checkout_hook &&\n \t{\n \t\techo $ZERO_OID $(git rev-parse HEAD) 1 &&\n-\t\techo $(pwd)/.git/worktrees/gumby &&\n+\t\techo $(pwd)/.git/worktrees/gumby-123 &&\n \t\techo $(pwd)/gumby\n \t} >hook.expect &&\n-\tgit worktree add gumby &&\n+\tGIT_TEST_WORKTREE_SUFFIX=\"123\" git worktree add gumby &&\n \ttest_cmp hook.expect gumby/hook.actual\n '\n \n@@ -1099,10 +1099,10 @@ test_expect_success '\"add\" invokes post-checkout hook (detached)' '\n \tpost_checkout_hook &&\n \t{\n \t\techo $ZERO_OID $(git rev-parse HEAD) 1 &&\n-\t\techo $(pwd)/.git/worktrees/grumpy &&\n+\t\techo $(pwd)/.git/worktrees/grumpy-456 &&\n \t\techo $(pwd)/grumpy\n \t} >hook.expect &&\n-\tgit worktree add --detach grumpy &&\n+\tGIT_TEST_WORKTREE_SUFFIX=\"456\" git worktree add --detach grumpy &&\n \ttest_cmp hook.expect grumpy/hook.actual\n '\n \n@@ -1117,10 +1117,10 @@ test_expect_success '\"add\" in other worktree invokes post-checkout hook' '\n \tpost_checkout_hook &&\n \t{\n \t\techo $ZERO_OID $(git rev-parse HEAD) 1 &&\n-\t\techo $(pwd)/.git/worktrees/guppy &&\n+\t\techo $(pwd)/.git/worktrees/guppy-789 &&\n \t\techo $(pwd)/guppy\n \t} >hook.expect &&\n-\tgit -C gloopy worktree add --detach ../guppy &&\n+\tGIT_TEST_WORKTREE_SUFFIX=\"789\" git -C gloopy worktree add --detach ../guppy &&\n \ttest_cmp hook.expect guppy/hook.actual\n '\n \n@@ -1129,11 +1129,11 @@ test_expect_success '\"add\" in bare repo invokes post-checkout hook' '\n \tgit clone --bare . bare &&\n \t{\n \t\techo $ZERO_OID $(git --git-dir=bare rev-parse HEAD) 1 &&\n-\t\techo $(pwd)/bare/worktrees/goozy &&\n+\t\techo $(pwd)/bare/worktrees/goozy-651 &&\n \t\techo $(pwd)/goozy\n \t} >hook.expect &&\n \tpost_checkout_hook bare &&\n-\tgit -C bare worktree add --detach ../goozy &&\n+\tGIT_TEST_WORKTREE_SUFFIX=\"651\" git -C bare worktree add --detach ../goozy &&\n \ttest_cmp hook.expect goozy/hook.actual\n '\n \n@@ -1165,8 +1165,9 @@ test_expect_success '\"add\" not tripped up by magic worktree matching\"' '\n '\n \n test_expect_success FUNNYNAMES 'sanitize generated worktree name' '\n-\tgit worktree add --detach \".  weird*..?.lock.lock\" &&\n-\ttest -d .git/worktrees/---weird-.-\n+\tGIT_TEST_WORKTREE_SUFFIX=\"1234\" \\\n+\t\tgit worktree add --detach \".  weird*..?.lock.lock\" &&\n+\ttest -d .git/worktrees/---weird-.--1234\n '\n \n test_expect_success '\"add\" should not fail because of another bad worktree' '\n@@ -1210,23 +1211,23 @@ test_expect_success '\"add\" with initialized submodule, with submodule.recurse se\n test_expect_success 'can create worktrees with relative paths' '\n \ttest_when_finished \"git worktree remove relative\" &&\n \ttest_config worktree.useRelativePaths false &&\n-\tgit worktree add --relative-paths ./relative &&\n-\techo \"gitdir: ../.git/worktrees/relative\" >expect &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add --relative-paths ./relative &&\n+\techo \"gitdir: ../.git/worktrees/relative-123\" >expect &&\n \ttest_cmp expect relative/.git &&\n \techo \"../../../relative/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/relative/gitdir\n+\ttest_cmp expect .git/worktrees/relative-123/gitdir\n '\n \n test_expect_success 'can create worktrees with absolute paths' '\n \ttest_config worktree.useRelativePaths true &&\n-\tgit worktree add ./relative &&\n-\techo \"gitdir: ../.git/worktrees/relative\" >expect &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add ./relative &&\n+\techo \"gitdir: ../.git/worktrees/relative-123\" >expect &&\n \ttest_cmp expect relative/.git &&\n-\tgit worktree add --no-relative-paths ./absolute &&\n-\techo \"gitdir: $(pwd)/.git/worktrees/absolute\" >expect &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree add --no-relative-paths ./absolute &&\n+\techo \"gitdir: $(pwd)/.git/worktrees/absolute-456\" >expect &&\n \ttest_cmp expect absolute/.git &&\n \techo \"$(pwd)/absolute/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/absolute/gitdir\n+\ttest_cmp expect .git/worktrees/absolute-456/gitdir\n '\n \n test_expect_success 'move repo without breaking relative internal links' '\ndiff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh\nindex 5eb52b9abbf29514dc082c260ebb7a5e8e63aae0..856fcdd19d376d3448ee0be46592fe68d44617c4 100755\n--- a/t/t2401-worktree-prune.sh\n+++ b/t/t2401-worktree-prune.sh\n@@ -83,29 +83,29 @@ test_expect_success 'not prune locked checkout' '\n test_expect_success 'not prune recent checkouts' '\n \ttest_when_finished rm -r .git/worktrees &&\n \tgit worktree add jlm HEAD &&\n-\ttest -d .git/worktrees/jlm &&\n+\ttest -d .git/worktrees/jlm-* &&\n \trm -rf jlm &&\n \tgit worktree prune --verbose --expire=2.days.ago &&\n-\ttest -d .git/worktrees/jlm\n+\ttest -d .git/worktrees/jlm-*\n '\n \n test_expect_success 'not prune proper checkouts' '\n \ttest_when_finished rm -r .git/worktrees &&\n \tgit worktree add --detach \"$PWD/nop\" main &&\n \tgit worktree prune &&\n-\ttest -d .git/worktrees/nop\n+\ttest -d .git/worktrees/nop-*\n '\n \n test_expect_success 'prune duplicate (linked/linked)' '\n \ttest_when_finished rm -fr .git/worktrees w1 w2 &&\n-\tgit worktree add --detach w1 &&\n-\tgit worktree add --detach w2 &&\n-\tsed \"s/w2/w1/\" .git/worktrees/w2/gitdir >.git/worktrees/w2/gitdir.new &&\n-\tmv .git/worktrees/w2/gitdir.new .git/worktrees/w2/gitdir &&\n+\tGIT_TEST_WORKTREE_SUFFIX=1 git worktree add --detach w1 &&\n+\tGIT_TEST_WORKTREE_SUFFIX=2 git worktree add --detach w2 &&\n+\tsed \"s/w2/w1/\" .git/worktrees/w2-2/gitdir >.git/worktrees/w2-2/gitdir.new &&\n+\tmv .git/worktrees/w2-2/gitdir.new .git/worktrees/w2-2/gitdir &&\n \tgit worktree prune --verbose 2>actual &&\n \ttest_grep \"duplicate entry\" actual &&\n-\ttest -d .git/worktrees/w1 &&\n-\t! test -d .git/worktrees/w2\n+\ttest -d .git/worktrees/w1-1 &&\n+\t! test -d .git/worktrees/w2-2\n '\n \n test_expect_success 'prune duplicate (main/linked)' '\n@@ -117,7 +117,7 @@ test_expect_success 'prune duplicate (main/linked)' '\n \tmv repo wt &&\n \tgit -C wt worktree prune --verbose 2>actual &&\n \ttest_grep \"duplicate entry\" actual &&\n-\t! test -d .git/worktrees/wt\n+\t! test -d .git/worktrees/wt-*\n '\n \n test_expect_success 'not prune proper worktrees inside linked worktree with relative paths' '\ndiff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh\nindex 422c1a05580057b18ab8bfdfe38da4d723749493..ba3f05c16a4969fb84d98052ae375ef162f3e73a 100755\n--- a/t/t2403-worktree-move.sh\n+++ b/t/t2403-worktree-move.sh\n@@ -24,27 +24,27 @@ test_expect_success 'lock main worktree' '\n test_expect_success 'lock linked worktree' '\n \tgit worktree lock --reason hahaha source &&\n \techo hahaha >expected &&\n-\ttest_cmp expected .git/worktrees/source/locked\n+\ttest_cmp expected .git/worktrees/source-*/locked\n '\n \n test_expect_success 'lock linked worktree from another worktree' '\n-\trm .git/worktrees/source/locked &&\n+\trm .git/worktrees/source-*/locked &&\n \tgit worktree add elsewhere &&\n \tgit -C elsewhere worktree lock --reason hahaha ../source &&\n \techo hahaha >expected &&\n-\ttest_cmp expected .git/worktrees/source/locked\n+\ttest_cmp expected .git/worktrees/source-*/locked\n '\n \n test_expect_success 'lock worktree twice' '\n \ttest_must_fail git worktree lock source &&\n \techo hahaha >expected &&\n-\ttest_cmp expected .git/worktrees/source/locked\n+\ttest_cmp expected .git/worktrees/source-*/locked\n '\n \n test_expect_success 'lock worktree twice (from the locked worktree)' '\n \ttest_must_fail git -C source worktree lock . &&\n \techo hahaha >expected &&\n-\ttest_cmp expected .git/worktrees/source/locked\n+\ttest_cmp expected .git/worktrees/source-*/locked\n '\n \n test_expect_success 'unlock main worktree' '\n@@ -183,19 +183,19 @@ test_expect_success 'force remove worktree with untracked file' '\n \n test_expect_success 'remove missing worktree' '\n \tgit worktree add to-be-gone &&\n-\ttest -d .git/worktrees/to-be-gone &&\n+\ttest -d .git/worktrees/to-be-gone-* &&\n \tmv to-be-gone gone &&\n \tgit worktree remove to-be-gone &&\n-\ttest_path_is_missing .git/worktrees/to-be-gone\n+\ttest_path_is_missing .git/worktrees/to-be-gone-*\n '\n \n test_expect_success 'NOT remove missing-but-locked worktree' '\n \tgit worktree add gone-but-locked &&\n \tgit worktree lock gone-but-locked &&\n-\ttest -d .git/worktrees/gone-but-locked &&\n+\ttest -d .git/worktrees/gone-but-locked-* &&\n \tmv gone-but-locked really-gone-now &&\n \ttest_must_fail git worktree remove gone-but-locked &&\n-\ttest_path_is_dir .git/worktrees/gone-but-locked\n+\ttest_path_is_dir .git/worktrees/gone-but-locked-*\n '\n \n test_expect_success 'proper error when worktree not found' '\n@@ -249,27 +249,27 @@ test_expect_success 'not remove a repo with initialized submodule' '\n \n test_expect_success 'move worktree with absolute path to relative path' '\n \ttest_config worktree.useRelativePaths false &&\n-\tgit worktree add ./absolute &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add ./absolute &&\n \tgit worktree move --relative-paths absolute relative &&\n-\techo \"gitdir: ../.git/worktrees/absolute\" >expect &&\n+\techo \"gitdir: ../.git/worktrees/absolute-123\" >expect &&\n \ttest_cmp expect relative/.git &&\n \techo \"../../../relative/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/absolute/gitdir &&\n+\ttest_cmp expect .git/worktrees/absolute-123/gitdir &&\n \ttest_config worktree.useRelativePaths true &&\n \tgit worktree move relative relative2 &&\n-\techo \"gitdir: ../.git/worktrees/absolute\" >expect &&\n+\techo \"gitdir: ../.git/worktrees/absolute-123\" >expect &&\n \ttest_cmp expect relative2/.git &&\n \techo \"../../../relative2/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/absolute/gitdir\n+\ttest_cmp expect .git/worktrees/absolute-123/gitdir\n '\n \n test_expect_success 'move worktree with relative path to absolute path' '\n \ttest_config worktree.useRelativePaths true &&\n \tgit worktree move --no-relative-paths relative2 absolute &&\n-\techo \"gitdir: $(pwd)/.git/worktrees/absolute\" >expect &&\n+\techo \"gitdir: $(pwd)/.git/worktrees/absolute-123\" >expect &&\n \ttest_cmp expect absolute/.git &&\n \techo \"$(pwd)/absolute/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/absolute/gitdir\n+\ttest_cmp expect .git/worktrees/absolute-123/gitdir\n '\n \n test_done\ndiff --git a/t/t2405-worktree-submodule.sh b/t/t2405-worktree-submodule.sh\nindex 1d7f60563387f9c2f53dfc3a79ac0289afe57611..5479b2a74aa0d9b1e8880ed7c038307ffa1d0c54 100755\n--- a/t/t2405-worktree-submodule.sh\n+++ b/t/t2405-worktree-submodule.sh\n@@ -9,6 +9,7 @@ TEST_PASSES_SANITIZE_LEAK=true\n . ./test-lib.sh\n \n base_path=$(pwd -P)\n+suffix=4567\n \n test_expect_success 'setup: create origin repos'  '\n \tgit config --global protocol.file.allow always &&\n@@ -61,9 +62,10 @@ test_expect_success 'submodule is checked out after manually adding submodule wo\n '\n \n test_expect_success 'checkout --recurse-submodules uses $GIT_DIR for submodules in a linked worktree' '\n-\tgit -C main worktree add \"$base_path/checkout-recurse\" --detach  &&\n+\tGIT_TEST_WORKTREE_SUFFIX=$suffix \\\n+\t\tgit -C main worktree add \"$base_path/checkout-recurse\" --detach  &&\n \tgit -C checkout-recurse submodule update --init &&\n-\techo \"gitdir: ../../main/.git/worktrees/checkout-recurse/modules/sub\" >expect-gitfile &&\n+\techo \"gitdir: ../../main/.git/worktrees/checkout-recurse-$suffix/modules/sub\" >expect-gitfile &&\n \tcat checkout-recurse/sub/.git >actual-gitfile &&\n \ttest_cmp expect-gitfile actual-gitfile &&\n \tgit -C main/sub rev-parse HEAD >expect-head-main &&\n@@ -82,14 +84,14 @@ test_expect_success 'core.worktree is removed in $GIT_DIR/modules/<name>/config,\n \tgit -C checkout-recurse/sub config --get core.worktree >actual-linked &&\n \ttest_cmp expect-linked actual-linked &&\n \tgit -C checkout-recurse checkout --recurse-submodules first &&\n-\ttest_expect_code 1 git -C main/.git/worktrees/checkout-recurse/modules/sub config --get core.worktree >linked-config &&\n+\ttest_expect_code 1 git -C main/.git/worktrees/checkout-recurse-$suffix/modules/sub config --get core.worktree >linked-config &&\n \ttest_must_be_empty linked-config &&\n \tgit -C main/sub config --get core.worktree >actual-main &&\n \ttest_cmp expect-main actual-main\n '\n \n test_expect_success 'unsetting core.worktree does not prevent running commands directly against the submodule repository' '\n-\tgit -C main/.git/worktrees/checkout-recurse/modules/sub log\n+\tgit -C main/.git/worktrees/checkout-recurse-$suffix/modules/sub log\n '\n \n test_done\ndiff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh\nindex 49b70b999518d47e1edd72a61a847b427f4c67a1..49d020f5fe786014ddc428bcb74cb706f8cef3d1 100755\n--- a/t/t2406-worktree-repair.sh\n+++ b/t/t2406-worktree-repair.sh\n@@ -106,8 +106,8 @@ test_expect_success 'repo not found; .git not file' '\n \n test_expect_success 'repo not found; .git not referencing repo' '\n \ttest_when_finished \"rm -rf side not-a-repo && git worktree prune\" &&\n-\tgit worktree add --detach side &&\n-\tsed s,\\.git/worktrees/side$,not-a-repo, side/.git >side/.newgit &&\n+\tGIT_TEST_WORKTREE_SUFFIX=1234 git worktree add --detach side &&\n+\tsed s,\\.git/worktrees/side-1234$,not-a-repo, side/.git >side/.newgit &&\n \tmv side/.newgit side/.git &&\n \tmkdir not-a-repo &&\n \ttest_must_fail git worktree repair side 2>err &&\n@@ -127,41 +127,41 @@ test_expect_success 'repo not found; .git file broken' '\n test_expect_success 'repair broken gitdir' '\n \ttest_when_finished \"rm -rf orig moved && git worktree prune\" &&\n \tgit worktree add --detach orig &&\n-\tsed s,orig/\\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&\n-\trm .git/worktrees/orig/gitdir &&\n+\tsed s,orig/\\.git$,moved/.git, .git/worktrees/orig-*/gitdir >expect &&\n+\trm .git/worktrees/orig-*/gitdir &&\n \tmv orig moved &&\n \tgit worktree repair moved 2>err &&\n-\ttest_cmp expect .git/worktrees/orig/gitdir &&\n+\ttest_cmp expect .git/worktrees/orig-*/gitdir &&\n \ttest_grep \"gitdir unreadable\" err\n '\n \n test_expect_success 'repair incorrect gitdir' '\n \ttest_when_finished \"rm -rf orig moved && git worktree prune\" &&\n \tgit worktree add --detach orig &&\n-\tsed s,orig/\\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&\n+\tsed s,orig/\\.git$,moved/.git, .git/worktrees/orig-*/gitdir >expect &&\n \tmv orig moved &&\n \tgit worktree repair moved 2>err &&\n-\ttest_cmp expect .git/worktrees/orig/gitdir &&\n+\ttest_cmp expect .git/worktrees/orig-*/gitdir &&\n \ttest_grep \"gitdir incorrect\" err\n '\n \n test_expect_success 'repair gitdir (implicit) from linked worktree' '\n \ttest_when_finished \"rm -rf orig moved && git worktree prune\" &&\n \tgit worktree add --detach orig &&\n-\tsed s,orig/\\.git$,moved/.git, .git/worktrees/orig/gitdir >expect &&\n+\tsed s,orig/\\.git$,moved/.git, .git/worktrees/orig-*/gitdir >expect &&\n \tmv orig moved &&\n \tgit -C moved worktree repair 2>err &&\n-\ttest_cmp expect .git/worktrees/orig/gitdir &&\n+\ttest_cmp expect .git/worktrees/orig-*/gitdir &&\n \ttest_grep \"gitdir incorrect\" err\n '\n \n test_expect_success 'unable to repair gitdir (implicit) from main worktree' '\n \ttest_when_finished \"rm -rf orig moved && git worktree prune\" &&\n \tgit worktree add --detach orig &&\n-\tcat .git/worktrees/orig/gitdir >expect &&\n+\tcat .git/worktrees/orig-*/gitdir >expect &&\n \tmv orig moved &&\n \tgit worktree repair 2>err &&\n-\ttest_cmp expect .git/worktrees/orig/gitdir &&\n+\ttest_cmp expect .git/worktrees/orig-*/gitdir &&\n \ttest_must_be_empty err\n '\n \n@@ -170,15 +170,15 @@ test_expect_success 'repair multiple gitdir files' '\n \t\tgit worktree prune\" &&\n \tgit worktree add --detach orig1 &&\n \tgit worktree add --detach orig2 &&\n-\tsed s,orig1/\\.git$,moved1/.git, .git/worktrees/orig1/gitdir >expect1 &&\n-\tsed s,orig2/\\.git$,moved2/.git, .git/worktrees/orig2/gitdir >expect2 &&\n+\tsed s,orig1/\\.git$,moved1/.git, .git/worktrees/orig1-*/gitdir >expect1 &&\n+\tsed s,orig2/\\.git$,moved2/.git, .git/worktrees/orig2-*/gitdir >expect2 &&\n \tmv orig1 moved1 &&\n \tmv orig2 moved2 &&\n \tgit worktree repair moved1 moved2 2>err &&\n-\ttest_cmp expect1 .git/worktrees/orig1/gitdir &&\n-\ttest_cmp expect2 .git/worktrees/orig2/gitdir &&\n-\ttest_grep \"gitdir incorrect:.*orig1/gitdir$\" err &&\n-\ttest_grep \"gitdir incorrect:.*orig2/gitdir$\" err\n+\ttest_cmp expect1 .git/worktrees/orig1-*/gitdir &&\n+\ttest_cmp expect2 .git/worktrees/orig2-*/gitdir &&\n+\ttest_grep \"gitdir incorrect:.*orig1-.*/gitdir$\" err &&\n+\ttest_grep \"gitdir incorrect:.*orig2-.*/gitdir$\" err\n '\n \n test_expect_success 'repair moved main and linked worktrees' '\n@@ -186,14 +186,12 @@ test_expect_success 'repair moved main and linked worktrees' '\n \ttest_create_repo main &&\n \ttest_commit -C main init &&\n \tgit -C main worktree add --detach ../side &&\n-\tsed \"s,side/\\.git$,sidemoved/.git,\" \\\n-\t\tmain/.git/worktrees/side/gitdir >expect-gitdir &&\n-\tsed \"s,main/.git/worktrees/side$,mainmoved/.git/worktrees/side,\" \\\n-\t\tside/.git >expect-gitfile &&\n+\tsed \"s,side,sidemoved,\" main/.git/worktrees/side-*/gitdir >expect-gitdir &&\n+\tsed \"s,main,mainmoved,\" side/.git >expect-gitfile &&\n \tmv main mainmoved &&\n \tmv side sidemoved &&\n \tgit -C mainmoved worktree repair ../sidemoved &&\n-\ttest_cmp expect-gitdir mainmoved/.git/worktrees/side/gitdir &&\n+\ttest_cmp expect-gitdir mainmoved/.git/worktrees/side-*/gitdir &&\n \ttest_cmp expect-gitfile sidemoved/.git\n '\n \n@@ -203,16 +201,15 @@ test_expect_success 'repair copied main and linked worktrees' '\n \tgit -C orig init main &&\n \ttest_commit -C orig/main nothing &&\n \tgit -C orig/main worktree add ../linked &&\n-\tcp orig/main/.git/worktrees/linked/gitdir orig/main.expect &&\n+\tcp orig/main/.git/worktrees/linked-*/gitdir orig/main.expect &&\n \tcp orig/linked/.git orig/linked.expect &&\n \tcp -R orig dup &&\n \tsed \"s,orig/linked/\\.git$,dup/linked/.git,\" orig/main.expect >dup/main.expect &&\n-\tsed \"s,orig/main/\\.git/worktrees/linked$,dup/main/.git/worktrees/linked,\" \\\n-\t\torig/linked.expect >dup/linked.expect &&\n+\tsed \"s,orig,dup,\" orig/linked.expect >dup/linked.expect &&\n \tgit -C dup/main worktree repair ../linked &&\n-\ttest_cmp orig/main.expect orig/main/.git/worktrees/linked/gitdir &&\n+\ttest_cmp orig/main.expect orig/main/.git/worktrees/linked-*/gitdir &&\n \ttest_cmp orig/linked.expect orig/linked/.git &&\n-\ttest_cmp dup/main.expect dup/main/.git/worktrees/linked/gitdir &&\n+\ttest_cmp dup/main.expect dup/main/.git/worktrees/linked-*/gitdir &&\n \ttest_cmp dup/linked.expect dup/linked/.git\n '\n \n@@ -221,11 +218,11 @@ test_expect_success 'repair worktree with relative path with missing gitfile' '\n \ttest_create_repo main &&\n \tgit -C main config worktree.useRelativePaths true &&\n \ttest_commit -C main init &&\n-\tgit -C main worktree add --detach ../wt &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git -C main worktree add --detach ../wt &&\n \trm wt/.git &&\n \ttest_path_is_missing wt/.git &&\n \tgit -C main worktree repair &&\n-\techo \"gitdir: ../main/.git/worktrees/wt\" >expect &&\n+\techo \"gitdir: ../main/.git/worktrees/wt-123\" >expect &&\n \ttest_cmp expect wt/.git\n '\n \n@@ -233,12 +230,12 @@ test_expect_success 'repair absolute worktree to use relative paths' '\n \ttest_when_finished \"rm -rf main side sidemoved\" &&\n \ttest_create_repo main &&\n \ttest_commit -C main init &&\n-\tgit -C main worktree add --detach ../side &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git -C main worktree add --detach ../side &&\n \techo \"../../../../sidemoved/.git\" >expect-gitdir &&\n-\techo \"gitdir: ../main/.git/worktrees/side\" >expect-gitfile &&\n+\techo \"gitdir: ../main/.git/worktrees/side-456\" >expect-gitfile &&\n \tmv side sidemoved &&\n \tgit -C main worktree repair --relative-paths ../sidemoved &&\n-\ttest_cmp expect-gitdir main/.git/worktrees/side/gitdir &&\n+\ttest_cmp expect-gitdir main/.git/worktrees/side-456/gitdir &&\n \ttest_cmp expect-gitfile sidemoved/.git\n '\n \n@@ -246,13 +243,39 @@ test_expect_success 'repair relative worktree to use absolute paths' '\n \ttest_when_finished \"rm -rf main side sidemoved\" &&\n \ttest_create_repo main &&\n \ttest_commit -C main init &&\n-\tgit -C main worktree add --relative-paths --detach ../side &&\n+\tGIT_TEST_WORKTREE_SUFFIX=789 git -C main worktree add --relative-paths --detach ../side &&\n \techo \"$(pwd)/sidemoved/.git\" >expect-gitdir &&\n-\techo \"gitdir: $(pwd)/main/.git/worktrees/side\" >expect-gitfile &&\n+\techo \"gitdir: $(pwd)/main/.git/worktrees/side-789\" >expect-gitfile &&\n \tmv side sidemoved &&\n \tgit -C main worktree repair ../sidemoved &&\n-\ttest_cmp expect-gitdir main/.git/worktrees/side/gitdir &&\n+\ttest_cmp expect-gitdir main/.git/worktrees/side-789/gitdir &&\n \ttest_cmp expect-gitfile sidemoved/.git\n '\n \n+test_expect_success 'does not repair worktrees from another repo' '\n+\ttest_when_finished \"rm -rf repo1 repo2\" &&\n+\tmkdir -p repo1 &&\n+\tgit -C repo1 init main &&\n+\ttest_commit -C repo1/main nothing &&\n+\tgit -C repo1/main worktree add ../linked &&\n+\tcp repo1/main/.git/worktrees/linked-*/gitdir repo1/main.expect &&\n+\tcp repo1/linked/.git repo1/linked.expect &&\n+\tmkdir -p repo2 &&\n+\tgit -C repo2 init main &&\n+\ttest_commit -C repo2/main nothing &&\n+\tgit -C repo2/main worktree add ../linked &&\n+\tcp repo2/main/.git/worktrees/linked-*/gitdir repo2/main.expect &&\n+\tcp repo2/linked/.git repo2/linked.expect &&\n+\tgit -C repo1/main worktree repair ../../repo2/linked &&\n+\ttest_cmp repo1/main.expect repo1/main/.git/worktrees/linked-*/gitdir &&\n+\ttest_cmp repo1/linked.expect repo1/linked/.git &&\n+\ttest_cmp repo2/main.expect repo2/main/.git/worktrees/linked-*/gitdir &&\n+\ttest_cmp repo2/linked.expect repo2/linked/.git &&\n+\tgit -C repo2/main worktree repair ../../repo1/linked &&\n+\ttest_cmp repo1/main.expect repo1/main/.git/worktrees/linked-*/gitdir &&\n+\ttest_cmp repo1/linked.expect repo1/linked/.git &&\n+\ttest_cmp repo2/main.expect repo2/main/.git/worktrees/linked-*/gitdir &&\n+\ttest_cmp repo2/linked.expect repo2/linked/.git\n+'\n+\n test_done\ndiff --git a/t/t2407-worktree-heads.sh b/t/t2407-worktree-heads.sh\nindex f6835c91dcc49cfeb23881fe0ef7a96629bfb2e6..1587dadfd1e1fa122edccc62ffd9aa4c20f0ec80 100755\n--- a/t/t2407-worktree-heads.sh\n+++ b/t/t2407-worktree-heads.sh\n@@ -19,7 +19,8 @@ test_expect_success 'setup' '\n \t\ttest_commit $i &&\n \t\tgit branch wt-$i &&\n \t\tgit branch fake-$i &&\n-\t\tgit worktree add wt-$i wt-$i || return 1\n+\t\tGIT_TEST_WORKTREE_SUFFIX=$i \\\n+\t\t\tgit worktree add wt-$i wt-$i || return 1\n \tdone &&\n \n \t# Create a server that updates each branch by one commit\n@@ -132,20 +133,20 @@ test_expect_success 'refuse to overwrite when in error states' '\n \ttest_when_finished rm -rf .git/worktrees/wt-*/BISECT_* &&\n \n \t# Both branches are currently under rebase.\n-\tmkdir -p .git/worktrees/wt-3/rebase-merge &&\n-\ttouch .git/worktrees/wt-3/rebase-merge/interactive &&\n-\techo refs/heads/fake-1 >.git/worktrees/wt-3/rebase-merge/head-name &&\n-\techo refs/heads/fake-2 >.git/worktrees/wt-3/rebase-merge/onto &&\n-\tmkdir -p .git/worktrees/wt-4/rebase-merge &&\n-\ttouch .git/worktrees/wt-4/rebase-merge/interactive &&\n-\techo refs/heads/fake-2 >.git/worktrees/wt-4/rebase-merge/head-name &&\n-\techo refs/heads/fake-1 >.git/worktrees/wt-4/rebase-merge/onto &&\n+\tmkdir -p .git/worktrees/wt-3-3/rebase-merge &&\n+\ttouch .git/worktrees/wt-3-3/rebase-merge/interactive &&\n+\techo refs/heads/fake-1 >.git/worktrees/wt-3-3/rebase-merge/head-name &&\n+\techo refs/heads/fake-2 >.git/worktrees/wt-3-3/rebase-merge/onto &&\n+\tmkdir -p .git/worktrees/wt-4-4/rebase-merge &&\n+\ttouch .git/worktrees/wt-4-4/rebase-merge/interactive &&\n+\techo refs/heads/fake-2 >.git/worktrees/wt-4-4/rebase-merge/head-name &&\n+\techo refs/heads/fake-1 >.git/worktrees/wt-4-4/rebase-merge/onto &&\n \n \t# Both branches are currently under bisect.\n-\ttouch .git/worktrees/wt-4/BISECT_LOG &&\n-\techo refs/heads/fake-2 >.git/worktrees/wt-4/BISECT_START &&\n-\ttouch .git/worktrees/wt-1/BISECT_LOG &&\n-\techo refs/heads/fake-1 >.git/worktrees/wt-1/BISECT_START &&\n+\ttouch .git/worktrees/wt-4-4/BISECT_LOG &&\n+\techo refs/heads/fake-2 >.git/worktrees/wt-4-4/BISECT_START &&\n+\ttouch .git/worktrees/wt-1-1/BISECT_LOG &&\n+\techo refs/heads/fake-1 >.git/worktrees/wt-1-1/BISECT_START &&\n \n \tfor i in 1 2\n \tdo\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex ccfa6a720d090c2f7f2a085f60065bdcfaf8d1d9..e44497ac94394119662115b1f6aa035c7f0565d2 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -246,14 +246,14 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n '\n \n test_expect_success REFFILES 'git branch -M fails if updating any linked working tree fails' '\n-\tgit worktree add -b baz bazdir1 &&\n-\tgit worktree add -f bazdir2 baz &&\n-\ttouch .git/worktrees/bazdir1/HEAD.lock &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add -b baz bazdir1 &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree add -f bazdir2 baz &&\n+\ttouch .git/worktrees/bazdir1-123/HEAD.lock &&\n \ttest_must_fail git branch -M baz bam &&\n \ttest $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&\n \tgit branch -M bam baz &&\n-\trm .git/worktrees/bazdir1/HEAD.lock &&\n-\ttouch .git/worktrees/bazdir2/HEAD.lock &&\n+\trm .git/worktrees/bazdir1-123/HEAD.lock &&\n+\ttouch .git/worktrees/bazdir2-456/HEAD.lock &&\n \ttest_must_fail git branch -M baz bam &&\n \ttest $(git -C bazdir1 rev-parse --abbrev-ref HEAD) = bam &&\n \trm -rf bazdir1 bazdir2 &&\ndiff --git a/t/t5304-prune.sh b/t/t5304-prune.sh\nindex e641df0116c24404e4892a0e30af4ef4bf8db493..0e98c6627a98ed197d7ab1ff41e8dd41eeaff3ac 100755\n--- a/t/t5304-prune.sh\n+++ b/t/t5304-prune.sh\n@@ -293,7 +293,7 @@ test_expect_success 'prune: handle HEAD in multiple worktrees' '\n \techo \"new blob for third-worktree\" >third-worktree/blob &&\n \tgit -C third-worktree add blob &&\n \tgit -C third-worktree commit -m \"third\" &&\n-\trm .git/worktrees/third-worktree/index &&\n+\trm .git/worktrees/third-worktree-*/index &&\n \ttest_must_fail git -C third-worktree show :blob &&\n \tgit prune --expire=now &&\n \tgit -C third-worktree show HEAD:blob >actual &&\ndiff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh\nindex f77832185765585e2bda1677f8cbbe13841127f7..acf9544e35966f054cbc90c37e84377c9f461f2b 100755\n--- a/t/t7412-submodule-absorbgitdirs.sh\n+++ b/t/t7412-submodule-absorbgitdirs.sh\n@@ -123,7 +123,7 @@ test_expect_success 'absorb the git dir outside of primary worktree' '\n \ttest_when_finished \"rm -rf repo-bare.git\" &&\n \tgit clone --bare . repo-bare.git &&\n \ttest_when_finished \"rm -rf repo-wt\" &&\n-\tgit -C repo-bare.git worktree add ../repo-wt &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git -C repo-bare.git worktree add ../repo-wt &&\n \n \ttest_when_finished \"rm -f .gitconfig\" &&\n \ttest_config_global protocol.file.allow always &&\n@@ -134,7 +134,7 @@ test_expect_success 'absorb the git dir outside of primary worktree' '\n \tcat >expect <<-EOF &&\n \tMigrating git directory of '\\''sub2'\\'' from\n \t'\\''$cwd/repo-wt/sub2/.git'\\'' to\n-\t'\\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\\''\n+\t'\\''$cwd/repo-bare.git/worktrees/repo-wt-123/modules/sub2'\\''\n \tEOF\n \tgit -C repo-wt submodule absorbgitdirs 2>actual &&\n \ttest_cmp expect actual\n\n-- \n2.47.0\n\n\n"},{"id":"508359","messageId":"20241129-wt_unique_ids-v2-2-ff444e9e625a@pm.me","threadId":"62572","inReplyTo":"20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me","subject":"[PATCH v2 2/3] worktree: rename worktree id during worktree move","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-29T22:37:51Z","receivedAt":"2024-11-29T22:37:59Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"During a `worktree move` the worktree directory is moved/renamed but the\nrepository under `worktrees/<id>` is not updated. For example, given the\nfollowing structure:\n\n    foo/\n    ├── .git/worktrees/develop-5445874156/\n    └── develop/\n\nmoving `develop` to `master` results in\n\n    foo/\n    ├── .git/worktrees/develop-5445874156/\n    └── master/\n\nThis works because the linking files still point to the correct\nrepository, but this is a little weird. This teaches Git to also\nmove/rename the repository / worktree id during a `move` so that the\nstructure now looks like:\n\n    foo/\n    ├── .git/worktrees/master-1565465986/\n    └── master/\n\nNote that a new unique suffix is assigned to reduce the complexity of\ntrying to parse and reuse the existing suffix.\n\nSigned-off-by: Caleb White <cdwhite3@pm.me>\n---\n builtin/worktree.c       | 24 ++++++++++++++++++++++++\n t/t2403-worktree-move.sh | 18 +++++++++---------\n 2 files changed, 33 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 3ad355ca762729401fc0c8625f4fd05b154a84ec..36235546b492803707707ff208b13fe777bff1b4 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -1202,9 +1202,14 @@ static int move_worktree(int ac, const char **av, const char *prefix)\n \t};\n \tstruct worktree **worktrees, *wt;\n \tstruct strbuf dst = STRBUF_INIT;\n+\tstruct strbuf repo = STRBUF_INIT;\n+\tstruct strbuf repo_dst = STRBUF_INIT;\n \tstruct strbuf errmsg = STRBUF_INIT;\n \tconst char *reason = NULL;\n+\tconst char *new_id;\n+\tconst char *suffix;\n \tchar *path;\n+\tint len;\n \n \tac = parse_options(ac, av, prefix, options, git_worktree_move_usage,\n \t\t\t   0);\n@@ -1250,9 +1255,28 @@ static int move_worktree(int ac, const char **av, const char *prefix)\n \tif (rename(wt->path, dst.buf) == -1)\n \t\tdie_errno(_(\"failed to move '%s' to '%s'\"), wt->path, dst.buf);\n \n+\tstrbuf_realpath(&repo, git_common_path(\"worktrees/%s\", wt->id), 1);\n+\tnew_id = worktree_basename(dst.buf, &len);\n+\tstrbuf_add(&repo_dst, new_id, dst.buf + len - new_id);\n+\tstrbuf_realpath(&repo_dst, git_common_path(\"worktrees/%s\", repo_dst.buf), 1);\n+\tsuffix = getenv(\"GIT_TEST_WORKTREE_SUFFIX\");\n+\tif (suffix)\n+\t\tstrbuf_addf(&repo_dst, \"-%s\", suffix);\n+\telse\n+\t\tstrbuf_addf(&repo_dst, \"-%u\", git_rand());\n+\tnew_id = strrchr(repo_dst.buf, '/') + 1;\n+\tif (rename(repo.buf, repo_dst.buf) == -1)\n+\t\tdie_errno(_(\"failed to move '%s' to '%s'\"), repo.buf, repo_dst.buf);\n+\telse {\n+\t\tfree(wt->id);\n+\t\twt->id = xstrdup(new_id);\n+\t}\n+\n \tupdate_worktree_location(wt, dst.buf, use_relative_paths);\n \n \tstrbuf_release(&dst);\n+\tstrbuf_release(&repo);\n+\tstrbuf_release(&repo_dst);\n \tfree_worktrees(worktrees);\n \treturn 0;\n }\ndiff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh\nindex ba3f05c16a4969fb84d98052ae375ef162f3e73a..703aa58d10643e99ffaf803aa38dabfd4af68a10 100755\n--- a/t/t2403-worktree-move.sh\n+++ b/t/t2403-worktree-move.sh\n@@ -250,26 +250,26 @@ test_expect_success 'not remove a repo with initialized submodule' '\n test_expect_success 'move worktree with absolute path to relative path' '\n \ttest_config worktree.useRelativePaths false &&\n \tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add ./absolute &&\n-\tgit worktree move --relative-paths absolute relative &&\n-\techo \"gitdir: ../.git/worktrees/absolute-123\" >expect &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree move --relative-paths absolute relative &&\n+\techo \"gitdir: ../.git/worktrees/relative-456\" >expect &&\n \ttest_cmp expect relative/.git &&\n \techo \"../../../relative/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/absolute-123/gitdir &&\n+\ttest_cmp expect .git/worktrees/relative-456/gitdir &&\n \ttest_config worktree.useRelativePaths true &&\n-\tgit worktree move relative relative2 &&\n-\techo \"gitdir: ../.git/worktrees/absolute-123\" >expect &&\n+\tGIT_TEST_WORKTREE_SUFFIX=789 git worktree move relative relative2 &&\n+\techo \"gitdir: ../.git/worktrees/relative2-789\" >expect &&\n \ttest_cmp expect relative2/.git &&\n \techo \"../../../relative2/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/absolute-123/gitdir\n+\ttest_cmp expect .git/worktrees/relative2-789/gitdir\n '\n \n test_expect_success 'move worktree with relative path to absolute path' '\n \ttest_config worktree.useRelativePaths true &&\n-\tgit worktree move --no-relative-paths relative2 absolute &&\n-\techo \"gitdir: $(pwd)/.git/worktrees/absolute-123\" >expect &&\n+\tGIT_TEST_WORKTREE_SUFFIX=851 git worktree move --no-relative-paths relative2 absolute &&\n+\techo \"gitdir: $(pwd)/.git/worktrees/absolute-851\" >expect &&\n \ttest_cmp expect absolute/.git &&\n \techo \"$(pwd)/absolute/.git\" >expect &&\n-\ttest_cmp expect .git/worktrees/absolute-123/gitdir\n+\ttest_cmp expect .git/worktrees/absolute-851/gitdir\n '\n \n test_done\n\n-- \n2.47.0\n\n\n"},{"id":"508360","messageId":"20241129-wt_unique_ids-v2-3-ff444e9e625a@pm.me","threadId":"62572","inReplyTo":"20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me","subject":"[PATCH v2 3/3] worktree: add id to `worktree list` output","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-29T22:37:58Z","receivedAt":"2024-11-29T22:38:04Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"The worktree id is relatively hidden from the user, however, there may\nbe times where a user or script needs to determine the worktree id for a\nlinked worktree (e.g., to manually operate on some refs). While the id\nis stored in the worktree `.git` file, it would be nice if there was an\neasier method of obtaining it. This teaches Git to output the worktree id\n(for linked worktrees) in the `worktree list` verbose and porcelain modes.\n\nSigned-off-by: Caleb White <cdwhite3@pm.me>\n---\n Documentation/git-worktree.txt | 12 +++++++++++-\n builtin/worktree.c             |  5 +++++\n t/t2402-worktree-list.sh       | 16 ++++++++++------\n 3 files changed, 26 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt\nindex e0604b043361828f94b58f676a5ed4f15b116348..2bd8118852a97251fc1081d19ea9756428d190f4 100644\n--- a/Documentation/git-worktree.txt\n+++ b/Documentation/git-worktree.txt\n@@ -428,16 +428,21 @@ $ git worktree list\n \n For these annotations, a reason might also be available and this can be\n seen using the verbose mode. The annotation is then moved to the next line\n-indented followed by the additional information.\n+indented followed by the additional information. In verbose mode, the worktree\n+id is also shown on the next line if available.\n \n ------------\n $ git worktree list --verbose\n /path/to/linked-worktree              abcd1234 [master]\n+\tid: linked-worktree-12345678\n /path/to/locked-worktree-no-reason    abcd5678 (detached HEAD) locked\n+\tid: locked-worktree-no-reason-89765464\n /path/to/locked-worktree-with-reason  1234abcd (brancha)\n \tlocked: worktree path is mounted on a portable device\n+\tid: locked-worktree-with-reason-41564654\n /path/to/prunable-worktree            5678abc1 (detached HEAD)\n \tprunable: gitdir file points to non-existent location\n+\tid: prunable-worktree-98454651\n ------------\n \n Note that the annotation is moved to the next line if the additional\n@@ -461,24 +466,29 @@ worktree /path/to/bare-source\n bare\n \n worktree /path/to/linked-worktree\n+id linked-worktree-12345678\n HEAD abcd1234abcd1234abcd1234abcd1234abcd1234\n branch refs/heads/master\n \n worktree /path/to/other-linked-worktree\n+id other-linked-worktree-879456466\n HEAD 1234abc1234abc1234abc1234abc1234abc1234a\n detached\n \n worktree /path/to/linked-worktree-locked-no-reason\n+id locked-worktree-no-reason-89765464\n HEAD 5678abc5678abc5678abc5678abc5678abc5678c\n branch refs/heads/locked-no-reason\n locked\n \n worktree /path/to/linked-worktree-locked-with-reason\n+id locked-worktree-with-reason-41564654\n HEAD 3456def3456def3456def3456def3456def3456b\n branch refs/heads/locked-with-reason\n locked reason why is locked\n \n worktree /path/to/linked-worktree-prunable\n+id prunable-worktree-98454651\n HEAD 1233def1234def1234def1234def1234def1234b\n detached\n prunable gitdir file points to non-existent location\ndiff --git a/builtin/worktree.c b/builtin/worktree.c\nindex 36235546b492803707707ff208b13fe777bff1b4..fca8a9cda51643e434b5f8905e32e537c6b4418b 100644\n--- a/builtin/worktree.c\n+++ b/builtin/worktree.c\n@@ -944,6 +944,8 @@ static void show_worktree_porcelain(struct worktree *wt, int line_terminator)\n \tconst char *reason;\n \n \tprintf(\"worktree %s%c\", wt->path, line_terminator);\n+\tif (!is_main_worktree(wt))\n+\t\tprintf(\"id %s%c\", wt->id, line_terminator);\n \tif (wt->is_bare)\n \t\tprintf(\"bare%c\", line_terminator);\n \telse {\n@@ -1009,6 +1011,9 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len)\n \telse if (reason)\n \t\tstrbuf_addstr(&sb, \" prunable\");\n \n+\tif (verbose && !is_main_worktree(wt))\n+\t\tstrbuf_addf(&sb, \"\\n\\tid: %s\", wt->id);\n+\n \tprintf(\"%s\\n\", sb.buf);\n \tstrbuf_release(&sb);\n }\ndiff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh\nindex 780daa6cd6351f8fa9434619cc212aade8f01420..502d35cabb837121d178937673b580cd767d17aa 100755\n--- a/t/t2402-worktree-list.sh\n+++ b/t/t2402-worktree-list.sh\n@@ -56,8 +56,9 @@ test_expect_success '\"list\" all worktrees --porcelain' '\n \techo \"branch $(git symbolic-ref HEAD)\" >>expect &&\n \techo >>expect &&\n \ttest_when_finished \"rm -rf here actual expect && git worktree prune\" &&\n-\tgit worktree add --detach here main &&\n+\tGIT_TEST_WORKTREE_SUFFIX=123 git worktree add --detach here main &&\n \techo \"worktree $(git -C here rev-parse --show-toplevel)\" >>expect &&\n+\techo \"id here-123\" >>expect &&\n \techo \"HEAD $(git rev-parse HEAD)\" >>expect &&\n \techo \"detached\" >>expect &&\n \techo >>expect &&\n@@ -71,9 +72,10 @@ test_expect_success '\"list\" all worktrees --porcelain -z' '\n \tprintf \"worktree %sQHEAD %sQbranch %sQQ\" \\\n \t\t\"$(git rev-parse --show-toplevel)\" \\\n \t\t$(git rev-parse HEAD --symbolic-full-name HEAD) >expect &&\n-\tgit worktree add --detach here main &&\n-\tprintf \"worktree %sQHEAD %sQdetachedQQ\" \\\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree add --detach here main &&\n+\tprintf \"worktree %sQid %sQHEAD %sQdetachedQQ\" \\\n \t\t\"$(git -C here rev-parse --show-toplevel)\" \\\n+\t\t\"here-456\" \\\n \t\t\"$(git rev-parse HEAD)\" >>expect &&\n \tgit worktree list --porcelain -z >_actual &&\n \tnul_to_q <_actual >actual &&\n@@ -166,16 +168,17 @@ test_expect_success '\"list\" --verbose and --porcelain mutually exclusive' '\n test_expect_success '\"list\" all worktrees --verbose with locked' '\n \ttest_when_finished \"rm -rf locked1 locked2 out actual expect && git worktree prune\" &&\n \tgit worktree add locked1 --detach &&\n-\tgit worktree add locked2 --detach &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git worktree add locked2 --detach &&\n \tgit worktree lock locked1 &&\n \ttest_when_finished \"git worktree unlock locked1\" &&\n \tgit worktree lock locked2 --reason \"with reason\" &&\n \ttest_when_finished \"git worktree unlock locked2\" &&\n \techo \"$(git -C locked2 rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)\" >expect &&\n \tprintf \"\\tlocked: with reason\\n\" >>expect &&\n+\tprintf \"\\tid: locked2-456\\n\" >>expect &&\n \tgit worktree list --verbose >out &&\n \tgrep \"/locked1  *[0-9a-f].* locked$\" out &&\n-\tsed -n \"s/  */ /g;/\\/locked2  *[0-9a-f].*$/,/locked: .*$/p\" <out >actual &&\n+\tsed -n \"s/  */ /g;/\\/locked2  *[0-9a-f].*$/,/id: .*$/p\" <out >actual &&\n \ttest_cmp actual expect\n '\n \n@@ -211,11 +214,12 @@ test_expect_success '\"list\" all worktrees from bare main' '\n \n test_expect_success '\"list\" all worktrees --porcelain from bare main' '\n \ttest_when_finished \"rm -rf there actual expect && git -C bare1 worktree prune\" &&\n-\tgit -C bare1 worktree add --detach ../there main &&\n+\tGIT_TEST_WORKTREE_SUFFIX=456 git -C bare1 worktree add --detach ../there main &&\n \techo \"worktree $(pwd)/bare1\" >expect &&\n \techo \"bare\" >>expect &&\n \techo >>expect &&\n \techo \"worktree $(git -C there rev-parse --show-toplevel)\" >>expect &&\n+\techo \"id there-456\" >>expect &&\n \techo \"HEAD $(git -C there rev-parse HEAD)\" >>expect &&\n \techo \"detached\" >>expect &&\n \techo >>expect &&\n\n-- \n2.47.0\n\n\n"},{"id":"508361","messageId":"00c401db42b1$99c4d5a0$cd4e80e0$@nexbridge.com","threadId":"62572","inReplyTo":"20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me","subject":"RE: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2024-11-29T22:54:03Z","receivedAt":"2024-11-29T22:54:30Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On November 29, 2024 5:38 PM, Caleb White writes:\n>The `es/worktree-repair-copied` topic added support for repairing a worktree from\n>a copy scenario. I noted[1,2] that the topic added the ability for a repository to\n>\"take over\" a worktree from another repository if the worktree_id matched a\n>worktree inside the current repository which can happen if two repositories use the\n>same worktree name.\n>\n>This series teaches Git to create worktrees with a unique suffix so that the\n>worktree_id is unique across all repositories even if they have the same name. For\n>example creating a worktree `develop` would look like:\n>\n>    foo/\n>    ├── .git/worktrees/develop-5445874156/\n>    └── develop/\n>    bar/\n>    ├── .git/worktrees/develop-1549518426/\n>    └── develop/\n>\n>The actual worktree directory name is still `develop`, but the worktree_id is unique\n>and prevents the \"take over\" scenario. The suffix is given by the `git_rand()` function\n>which should be sufficient to ensure that the suffix is effectively unique (the\n>likelihood of a collision with the same name and suffix is extremely low).\n>\n>During a `worktree move` the worktree directory is moved/renamed but the\n>repository under `worktrees/<id>` is not updated. For example, moving `develop` to\n>`master` results in\n>\n>    foo/\n>    ├── .git/worktrees/develop-5445874156/\n>    └── master/\n>\n>This works because the linking files still point to the correct repository, but this is a\n>little weird. This series teaches Git to also move/rename the repository / worktree id\n>during a `move` so that the structure now looks like:\n>\n>    foo/\n>    ├── .git/worktrees/master-1565465986/\n>    └── master/\n>\n>Note that a new unique suffix is assigned to reduce the complexity of trying to parse\n>and reuse the existing suffix.\n>\n>Additionally, this series teaches `worktree list` to output the worktree id in the\n>verbose and porcelain modes, which allows users and scripts to more easily obtain\n>the id for a given worktree.\n>\n>[1]: https://lore.kernel.org/git/20241008153035.71178-1-cdwhite3@pm.me/\n>[2]:\n>https://lore.kernel.org/git/r4zmcET41Skr_FMop47AKd7cms9E8bKPSvHuAUpnYav\n>zKEY6JybJta0_7GfuYB0q-gD-\n>XNcvh5VDTfiT3qthGKjqhS1sbT4M2lUABynOz2Q=@pm.me/\n>\n>Signed-off-by: Caleb White <cdwhite3@pm.me>\n>---\n>The base for this series is obtained by merging the `cw/worktree-extension` topic\n>(2024-11-26, 20241125-wt_relative_options-v5-0-356d122ff3db@pm.me)\n>onto 090d24e9af.\n>\n>Changes in v2:\n>- Add the worktree id to `worktree list` output\n>- Updated cover letter\n>- Link to v1: https://lore.kernel.org/r/20241128-wt_unique_ids-v1-0-\n>30345d010e43@pm.me\n>\n>---\n>Caleb White (3):\n>      worktree: add worktree with unique suffix\n>      worktree: rename worktree id during worktree move\n>      worktree: add id to `worktree list` output\n>\n> Documentation/git-worktree.txt     | 17 +++++--\n> builtin/worktree.c                 | 35 ++++++++++++++\n> t/t0035-safe-bare-repository.sh    |  4 +-\n> t/t0600-reffiles-backend.sh        | 10 ++--\n> t/t0601-reffiles-pack-refs.sh      |  4 +-\n> t/t0610-reftable-basics.sh         | 54 +++++++++++-----------\n> t/t1407-worktree-ref-store.sh      |  4 +-\n> t/t1410-reflog.sh                  | 10 ++--\n> t/t1415-worktree-refs.sh           | 26 +++++------\n> t/t1450-fsck.sh                    | 14 +++---\n> t/t1500-rev-parse.sh               |  6 +--\n> t/t2400-worktree-add.sh            | 51 +++++++++++----------\n> t/t2401-worktree-prune.sh          | 20 ++++----\n> t/t2402-worktree-list.sh           | 16 ++++---\n> t/t2403-worktree-move.sh           | 38 ++++++++--------\n> t/t2405-worktree-submodule.sh      | 10 ++--\n> t/t2406-worktree-repair.sh         | 93 ++++++++++++++++++++++++--------------\n> t/t2407-worktree-heads.sh          | 27 +++++------\n> t/t3200-branch.sh                  | 10 ++--\n> t/t5304-prune.sh                   |  2 +-\n> t/t7412-submodule-absorbgitdirs.sh |  4 +-\n> 21 files changed, 265 insertions(+), 190 deletions(-)\n>---\n>base-commit: 090d24e9af6e9f59c3f7bee97c42bb1ae3c7f559\n>change-id: 20241127-wt_unique_ids-1ffd7ea0bb19\n>prerequisite-change-id: 20241025-wt_relative_options-afa41987bc32:v6\n>prerequisite-patch-id: 179410e257e8eedf100f4f9faa9467cbbba4d61b\n>prerequisite-patch-id: 56ffe0afeadd511c9eef5f548a371659b040acab\n>prerequisite-patch-id: 809c1314e5dfa966f4f3d73b52f286f8aa89370f\n>prerequisite-patch-id: cf5f9491c8f8e58d1e0e103a5f8c64c55f2896e3\n>prerequisite-patch-id: 9884b33822bf4c7c3b89a9a6b49d4ab44c2670e7\n>prerequisite-patch-id: 62a09496d98d78a6bd1f9150ba887ee72359c7ee\n>prerequisite-patch-id: 5527e4b745963dd4fa08029491fcbfe3d91d5104\n>prerequisite-patch-id: bf433443e90939a493fa586de30938f78cb77020\n\nGeneral comment on this series: Is there a mechanism of preserving existing\nfunctionality for those of us who have existing scripts that depend on the\nexisting branch and worktree naming?\n\n"},{"id":"508362","messageId":"D5Z1L479JERN.80KZ7NA9BWNJ@pm.me","threadId":"62572","inReplyTo":"00c401db42b1$99c4d5a0$cd4e80e0$@nexbridge.com","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-29T23:13:41Z","receivedAt":"2024-11-29T23:13:47Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Fri Nov 29, 2024 at 4:54 PM CST, rsbecker wrote:\n> General comment on this series: Is there a mechanism of preserving existing\n> functionality for those of us who have existing scripts that depend on the\n> existing branch and worktree naming?\n\nExisting worktrees will continue to work as they do now. The only change\nis the worktree id for new worktrees. However, there's not an option to\npreserve the existing behavior for new worktrees (nor do I think there\nshould be).\n\nAs stated in the v1 threads, the worktree id is already not guaranteed\nto be equal to the worktree/branch name (there's several ways that this\ncan occur), so it's buggy behavior for scripts to make this assumption.\nAny script that needs the worktree id should be parsing it from the \n`.git` file, `git rev-parse --git-dir`, or (with the changes in this\nseries) `git worktree list`.\n\nBest,\n\nCaleb\n\n"},{"id":"508363","messageId":"00c501db42b4$ea97e050$bfc7a0f0$@nexbridge.com","threadId":"62572","inReplyTo":"D5Z1L479JERN.80KZ7NA9BWNJ@pm.me","subject":"RE: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2024-11-29T23:17:47Z","receivedAt":"2024-11-29T23:18:06Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On November 29, 2024 6:14 PM, Caleb White writes:\n>On Fri Nov 29, 2024 at 4:54 PM CST, rsbecker wrote:\n>> General comment on this series: Is there a mechanism of preserving\n>> existing functionality for those of us who have existing scripts that\n>> depend on the existing branch and worktree naming?\n>\n>Existing worktrees will continue to work as they do now. The only change is the\n>worktree id for new worktrees. However, there's not an option to preserve the\n>existing behavior for new worktrees (nor do I think there should be).\n\nI do not agree. Companies that have existing scripts should have some way to\npreserve their investment. Just saying \"No more worktrees for you\" is not\nreally considerate.\n\n>As stated in the v1 threads, the worktree id is already not guaranteed to be equal to\n>the worktree/branch name (there's several ways that this can occur), so it's buggy\n>behavior for scripts to make this assumption.\n>Any script that needs the worktree id should be parsing it from the `.git` file, `git rev-\n>parse --git-dir`, or (with the changes in this\n>series) `git worktree list`.\n\nI agree, but I think having some kind of notice beyond one release is important, rather\nthan pulling the rug out from under people.\n\nJust my suggestion that there should be a migration period of this critical function.\n--Randall\n\n"},{"id":"508364","messageId":"D5Z1X36NVZ28.1FPA05CU9GFRL@pm.me","threadId":"62572","inReplyTo":"00c501db42b4$ea97e050$bfc7a0f0$@nexbridge.com","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-29T23:29:19Z","receivedAt":"2024-11-29T23:29:25Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Fri Nov 29, 2024 at 5:17 PM CST, rsbecker wrote:\n> On November 29, 2024 6:14 PM, Caleb White writes:\n>>On Fri Nov 29, 2024 at 4:54 PM CST, rsbecker wrote:\n>>> General comment on this series: Is there a mechanism of preserving\n>>> existing functionality for those of us who have existing scripts that\n>>> depend on the existing branch and worktree naming?\n>>\n>>Existing worktrees will continue to work as they do now. The only change is the\n>>worktree id for new worktrees. However, there's not an option to preserve the\n>>existing behavior for new worktrees (nor do I think there should be).\n>\n> I do not agree. Companies that have existing scripts should have some way to\n> preserve their investment. Just saying \"No more worktrees for you\" is not\n> really considerate.\n\nHow exactly are your scripts depending on the worktree id? There are\nvery few reasons a script might need to know the worktree id, and\nI suspect that there's some confusion here. The worktree name is still\nused with the `git worktree` commands, so there no change on that front.\n\nBest,\n\nCaleb\n\n"},{"id":"508365","messageId":"00c801db42b8$a03539a0$e09face0$@nexbridge.com","threadId":"62572","inReplyTo":"D5Z1X36NVZ28.1FPA05CU9GFRL@pm.me","subject":"RE: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2024-11-29T23:44:20Z","receivedAt":"2024-11-29T23:44:39Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On November 29, 2024 6:29 PM, Caleb White wrote:\n>On Fri Nov 29, 2024 at 5:17 PM CST, rsbecker wrote:\n>> On November 29, 2024 6:14 PM, Caleb White writes:\n>>>On Fri Nov 29, 2024 at 4:54 PM CST, rsbecker wrote:\n>>>> General comment on this series: Is there a mechanism of preserving\n>>>> existing functionality for those of us who have existing scripts\n>>>> that depend on the existing branch and worktree naming?\n>>>\n>>>Existing worktrees will continue to work as they do now. The only\n>>>change is the worktree id for new worktrees. However, there's not an\n>>>option to preserve the existing behavior for new worktrees (nor do I think there\n>should be).\n>>\n>> I do not agree. Companies that have existing scripts should have some\n>> way to preserve their investment. Just saying \"No more worktrees for\n>> you\" is not really considerate.\n>\n>How exactly are your scripts depending on the worktree id? There are very few\n>reasons a script might need to know the worktree id, and I suspect that there's\n>some confusion here. The worktree name is still used with the `git worktree`\n>commands, so there no change on that front.\n\nThe graphic describing this showed the id in addition to the worktree name.\nDuring cleanup detection, the directory of the worktree is significant. If that\nObservation is wrong, I retract all this.\n\n"},{"id":"508366","messageId":"D5Z2R71VW1JF.1FZE1Z0V8H6Q7@pm.me","threadId":"62572","inReplyTo":"00c801db42b8$a03539a0$e09face0$@nexbridge.com","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-30T00:08:39Z","receivedAt":"2024-11-30T00:08:44Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Fri Nov 29, 2024 at 5:44 PM CST, rsbecker wrote:\n> On November 29, 2024 6:29 PM, Caleb White wrote:\n>>On Fri Nov 29, 2024 at 5:17 PM CST, rsbecker wrote:\n>>> On November 29, 2024 6:14 PM, Caleb White writes:\n>>>>On Fri Nov 29, 2024 at 4:54 PM CST, rsbecker wrote:\n>>>>> General comment on this series: Is there a mechanism of preserving\n>>>>> existing functionality for those of us who have existing scripts\n>>>>> that depend on the existing branch and worktree naming?\n>>>>\n>>>>Existing worktrees will continue to work as they do now. The only\n>>>>change is the worktree id for new worktrees. However, there's not an\n>>>>option to preserve the existing behavior for new worktrees (nor do I think there\n>>should be).\n>>>\n>>> I do not agree. Companies that have existing scripts should have some\n>>> way to preserve their investment. Just saying \"No more worktrees for\n>>> you\" is not really considerate.\n>>\n>>How exactly are your scripts depending on the worktree id? There are very few\n>>reasons a script might need to know the worktree id, and I suspect that there's\n>>some confusion here. The worktree name is still used with the `git worktree`\n>>commands, so there no change on that front.\n>\n> The graphic describing this showed the id in addition to the worktree name.\n> During cleanup detection, the directory of the worktree is significant. If that\n> Observation is wrong, I retract all this.\n\nSo here's the graphic again:\n\n    foo/\n    ├── .git/worktrees/develop-5445874156/\n    └── develop/\n\nHere, the `develop` directory is the worktree directory (this can be\nlocated anywhere), and the `develop-5445874156` is the worktree id.\nHowever, the worktree id can already be something like `develop1`\nor something else entirely if the `develop` directory was renamed in the\npast. Again, there are very few things a script should need to know the\nworktree id for.\n\nIf the `develop` directory is deleted, cleanup detection is handled\nby the `git worktree prune` command, which will remove worktrees under\n`.git/worktrees/*` that are no longer valid. This happens automatically\nafter the expiry time or it can be executed manually. Of course,\nexecuting `git worktree remove develop` will also remove the worktree\nand its associated worktree id.\n\nBest,\n\nCaleb\n\n"},{"id":"508367","messageId":"00c901db42c0$38f95520$aaebff60$@nexbridge.com","threadId":"62572","inReplyTo":"D5Z2R71VW1JF.1FZE1Z0V8H6Q7@pm.me","subject":"RE: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2024-11-30T00:38:41Z","receivedAt":"2024-11-30T00:39:07Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On November 29, 2024 7:09 PM, Caleb White wrote:\n>To: rsbecker@nexbridge.com; git@vger.kernel.org\n>Cc: 'shejialuo' <shejialuo@gmail.com>; 'Junio C Hamano' <gitster@pobox.com>\n>Subject: Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories\n>\n>On Fri Nov 29, 2024 at 5:44 PM CST, rsbecker wrote:\n>> On November 29, 2024 6:29 PM, Caleb White wrote:\n>>>On Fri Nov 29, 2024 at 5:17 PM CST, rsbecker wrote:\n>>>> On November 29, 2024 6:14 PM, Caleb White writes:\n>>>>>On Fri Nov 29, 2024 at 4:54 PM CST, rsbecker wrote:\n>>>>>> General comment on this series: Is there a mechanism of preserving\n>>>>>> existing functionality for those of us who have existing scripts\n>>>>>> that depend on the existing branch and worktree naming?\n>>>>>\n>>>>>Existing worktrees will continue to work as they do now. The only\n>>>>>change is the worktree id for new worktrees. However, there's not an\n>>>>>option to preserve the existing behavior for new worktrees (nor do I\n>>>>>think there\n>>>should be).\n>>>>\n>>>> I do not agree. Companies that have existing scripts should have\n>>>> some way to preserve their investment. Just saying \"No more\n>>>> worktrees for you\" is not really considerate.\n>>>\n>>>How exactly are your scripts depending on the worktree id? There are\n>>>very few reasons a script might need to know the worktree id, and I\n>>>suspect that there's some confusion here. The worktree name is still\n>>>used with the `git worktree` commands, so there no change on that front.\n>>\n>> The graphic describing this showed the id in addition to the worktree name.\n>> During cleanup detection, the directory of the worktree is\n>> significant. If that Observation is wrong, I retract all this.\n>\n>So here's the graphic again:\n>\n>    foo/\n>    ├── .git/worktrees/develop-5445874156/\n>    └── develop/\n>\n>Here, the `develop` directory is the worktree directory (this can be located\n>anywhere), and the `develop-5445874156` is the worktree id.\n>However, the worktree id can already be something like `develop1` or something\n>else entirely if the `develop` directory was renamed in the past. Again, there are very\n>few things a script should need to know the worktree id for.\n>\n>If the `develop` directory is deleted, cleanup detection is handled by the `git\n>worktree prune` command, which will remove worktrees under `.git/worktrees/*`\n>that are no longer valid. This happens automatically after the expiry time or it can be\n>executed manually. Of course, executing `git worktree remove develop` will also\n>remove the worktree and its associated worktree id.\n\nThis last bit is an assumption, and not necessarily valid. Scripts that use worktrees\nmay maintain lists or their own pointers. It is important to be able to emulate\ncleanup functions - something I discovered early in the worktree functions\nwhen released. I need to make sure that cleanup will continue to have enough\ninformation - prior to git worktree cleanup - to function correctly. This will\nneed coordination with people who have such scripts in my community. It\nprobably will not impact you, but I would have appreciated more than one\nrelease notice on this capability.\n\n"},{"id":"508378","messageId":"D5ZN60S3JMS8.UXLUSM5IOFCX@pm.me","threadId":"62572","inReplyTo":"00c901db42c0$38f95520$aaebff60$@nexbridge.com","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-11-30T16:08:26Z","receivedAt":"2024-11-30T16:08:33Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Fri Nov 29, 2024 at 6:38 PM CST, rsbecker wrote:\n> On November 29, 2024 7:09 PM, Caleb White wrote:\n>>If the `develop` directory is deleted, cleanup detection is handled by the `git\n>>worktree prune` command, which will remove worktrees under `.git/worktrees/*`\n>>that are no longer valid. This happens automatically after the expiry time or it can be\n>>executed manually. Of course, executing `git worktree remove develop` will also\n>>remove the worktree and its associated worktree id.\n>\n> This last bit is an assumption, and not necessarily valid. Scripts that use worktrees\n> may maintain lists or their own pointers. It is important to be able to emulate\n> cleanup functions - something I discovered early in the worktree functions\n> when released. I need to make sure that cleanup will continue to have enough\n> information - prior to git worktree cleanup - to function correctly. This will\n> need coordination with people who have such scripts in my community. It\n> probably will not impact you, but I would have appreciated more than one\n> release notice on this capability.\n\nI'm not sure I understand the specific use-case you're talking about.\nCould you provide an example?\n\nHowever, I suppose I can add a config / env variable to be able to\ndisable this new functionality.\n\nBest,\n\nCaleb\n\n"},{"id":"508380","messageId":"010801db434b$ac0ec960$042c5c20$@nexbridge.com","threadId":"62572","inReplyTo":"D5ZN60S3JMS8.UXLUSM5IOFCX@pm.me","subject":"RE: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2024-11-30T17:16:56Z","receivedAt":"2024-11-30T17:17:16Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On November 30, 2024 11:08 AM, Caleb White wrote:\n>On Fri Nov 29, 2024 at 6:38 PM CST, rsbecker wrote:\n>> On November 29, 2024 7:09 PM, Caleb White wrote:\n>>>If the `develop` directory is deleted, cleanup detection is handled by\n>>>the `git worktree prune` command, which will remove worktrees under\n>>>`.git/worktrees/*` that are no longer valid. This happens\n>>>automatically after the expiry time or it can be executed manually. Of\n>>>course, executing `git worktree remove develop` will also remove the worktree\n>and its associated worktree id.\n>>\n>> This last bit is an assumption, and not necessarily valid. Scripts\n>> that use worktrees may maintain lists or their own pointers. It is\n>> important to be able to emulate cleanup functions - something I\n>> discovered early in the worktree functions when released. I need to\n>> make sure that cleanup will continue to have enough information -\n>> prior to git worktree cleanup - to function correctly. This will need\n>> coordination with people who have such scripts in my community. It\n>> probably will not impact you, but I would have appreciated more than one release\n>notice on this capability.\n>\n>I'm not sure I understand the specific use-case you're talking about.\n>Could you provide an example?\n\nSpeaking as a professional product manager...\n\nI'm not expressing \"maintaining compatibility for 2 releases\" or something like\nthat is a reasonable use case. There are customers who depend on things\nworking in a particular way. It is fine if you want to change it and improve it,\nand I am supportive. However, when making a change that causes git to\nbehave differently without allowing people to plan for such a change is\nimpolite. People outside this list do not read each patch looking for\ncompatibility breaking changes - they only get told in release notes. A\nstatement like \"this is going to change with 2.49\" for a breaking\nenhancement is what I would expect - unless it is a defect correction.\n\n>However, I suppose I can add a config / env variable to be able to disable this new\n>functionality.\n\nThat would be very helpful although an opt-in is generally better than an\nopt-out.\n\nI think we should have this as a general policy, not just for this series.\n\nThanks,\nRandall\n\n"},{"id":"508408","messageId":"xmqqed2qkfn0.fsf@gitster.g","threadId":"62572","inReplyTo":"20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-12-02T02:00:51Z","receivedAt":"2024-12-02T02:00:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Caleb White <cdwhite3@pm.me> writes:\n\n> - Add the worktree id to `worktree list` output\n\nI have always thought that we deliberately hid the \"ID\" from the end\nuser's view because it is a mere implementation detail, and used the\nfilesystem path of the worktree directory instead to identify each\ninstance of the worktree in the end-user interaction.  It is unclear\nwhy this change is a good idea from that point of view.\n\nThanks.\n"},{"id":"508428","messageId":"Z02eKA8i51QyXgJ-@ArchLinux","threadId":"62572","inReplyTo":"xmqqed2qkfn0.fsf@gitster.g","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"shejialuo","fromEmail":"shejialuo@gmail.com","sentAt":"2024-12-02T11:46:48Z","receivedAt":"2024-12-02T11:46:25Z","isPatch":true,"sender":{"key":"shejialuo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56911263?v=4"},"body":"On Mon, Dec 02, 2024 at 11:00:51AM +0900, Junio C Hamano wrote:\n> Caleb White <cdwhite3@pm.me> writes:\n> \n> > - Add the worktree id to `worktree list` output\n> \n> I have always thought that we deliberately hid the \"ID\" from the end\n> user's view because it is a mere implementation detail, and used the\n> filesystem path of the worktree directory instead to identify each\n> instance of the worktree in the end-user interaction.  It is unclear\n> why this change is a good idea from that point of view.\n> \n\nI have a discussion with Caleb in the first version. Because appending a\nhash / random number will cause the worktree id has more digits, the\nuser cannot easily use the following commands to make a ref in the main\nworktree point to linked worktree ref:\n\n    ```sh\n    git symbolic-ref refs/heads/foo \\\n        worktrees/<worktree id>/refs/worktree/foo\n    ```\n\nAnd I expressed my concern about above situation, the user types the\nextra hash to do above. So, Caleb decides to list the worktree id.\n\nActually, this usage should not be common. But when implementing the\nconsistency check for files backend, you have told me that the above\nsituation could happen. And you have said we _deliberately_ hide the\n\"ID\" from the end user's view.\n\nBut cross-ref operations between worktrees must explicitly specify the\nworktree id, so I am wondering whether we should allow the user do\ncross-ref operations in the first place:\n\n  1. main worktree symref points to linked worktree ref.\n  2. A linked worktree ref points to another linked worktree ref.\n\nThanks,\nJialuo\n"},{"id":"508484","messageId":"xmqqed2pioff.fsf@gitster.g","threadId":"62572","inReplyTo":"Z02eKA8i51QyXgJ-@ArchLinux","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-12-03T00:46:12Z","receivedAt":"2024-12-03T00:46:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"shejialuo <shejialuo@gmail.com> writes:\n\n> But cross-ref operations between worktrees must explicitly specify the\n> worktree id, so I am wondering whether we should allow the user do\n> cross-ref operations in the first place:\n>\n>   1. main worktree symref points to linked worktree ref.\n>   2. A linked worktree ref points to another linked worktree ref.\n\nWhat is a cross-ref operation?  A worktree is either the primary\nworking tree for a (non-bare) repository, or something added with\n\"git add worktree\" (i.e. whose .git is not the repository but a\nlink file into the real repository).  Are you adding another mode\nwhere a worktree points at another worktree and not the repository?\n"},{"id":"508485","messageId":"CAPig+cQHW9=A5ejU5aZ+Wy0uOQsLU_uqUibeYzZs2PXK37Vpbw@mail.gmail.com","threadId":"62572","inReplyTo":"xmqqed2pioff.fsf@gitster.g","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2024-12-03T00:56:01Z","receivedAt":"2024-12-03T00:56:13Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Dec 2, 2024 at 7:46 PM Junio C Hamano <gitster@pobox.com> wrote:\n> shejialuo <shejialuo@gmail.com> writes:\n> > But cross-ref operations between worktrees must explicitly specify the\n> > worktree id, so I am wondering whether we should allow the user do\n> > cross-ref operations in the first place:\n> >\n> >   1. main worktree symref points to linked worktree ref.\n> >   2. A linked worktree ref points to another linked worktree ref.\n>\n> What is a cross-ref operation?  A worktree is either the primary\n> working tree for a (non-bare) repository, or something added with\n> \"git add worktree\" (i.e. whose .git is not the repository but a\n> link file into the real repository).  Are you adding another mode\n> where a worktree points at another worktree and not the repository?\n\nUnfortunately, I haven't had time lately to follow all these\nworktree-related changes or discussions, but perhaps shejialuo is\nreferring to the ability, from within one worktree, to mention a ref\nfrom another worktree (which is a feature Duy added some time after\nthe initial worktree implementation). Specifically, from the\ngit-worktree man page:\n\n    Refs that are per-worktree can still be accessed from another\n    worktree via two special paths, main-worktree and worktrees. The\n    former gives access to per-worktree refs of the main worktree,\n    while the latter to all linked worktrees.\n\n    For example, main-worktree/HEAD or main-worktree/refs/bisect/good\n    resolve to the same value as the main worktree’s HEAD and\n    refs/bisect/good respectively. Similarly, worktrees/foo/HEAD or\n    worktrees/bar/refs/bisect/bad are the same as\n    $GIT_COMMON_DIR/worktrees/foo/HEAD and\n    $GIT_COMMON_DIR/worktrees/bar/refs/bisect/bad.\n"},{"id":"508489","messageId":"Z05d5pjvcIyJsAeG@ArchLinux","threadId":"62572","inReplyTo":"xmqqed2pioff.fsf@gitster.g","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"shejialuo","fromEmail":"shejialuo@gmail.com","sentAt":"2024-12-03T01:24:54Z","receivedAt":"2024-12-03T01:24:32Z","isPatch":true,"sender":{"key":"shejialuo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56911263?v=4"},"body":"On Tue, Dec 03, 2024 at 09:46:12AM +0900, Junio C Hamano wrote:\n> shejialuo <shejialuo@gmail.com> writes:\n> \n> > But cross-ref operations between worktrees must explicitly specify the\n> > worktree id, so I am wondering whether we should allow the user do\n> > cross-ref operations in the first place:\n> >\n> >   1. main worktree symref points to linked worktree ref.\n> >   2. A linked worktree ref points to another linked worktree ref.\n> \n> What is a cross-ref operation?  A worktree is either the primary\n> working tree for a (non-bare) repository, or something added with\n> \"git add worktree\" (i.e. whose .git is not the repository but a\n> link file into the real repository).  Are you adding another mode\n> where a worktree points at another worktree and not the repository?\n\nI am sorry that my words may confuse you here. And the Eric has already\nexplained what I mean here. At current, we have the ability to mention\na ref another worktree within the current worktree. You also have tole\nme that in [1], there is a possibility that the user could create a\nsymbolic link to some worktree-specific ref in another worktree.\n\nSo, if our intention is to deliberately hide the worktree id. Why we\nallow such ability? Let me give an example.\n\nIf we are in the main-worktree, and we want to access the worktree\nspecified refs, we must specify the worktree id like the following\n(also if we are in the linked-worktree, we want to access another\nlinked-worktree refs):\n\n    worktrees/<worktree id>/refs/worktree/foo\n\nWe do not want to the user know the worktree id. However, we allow\nabove. This is something I feel really strange during the review\nprocess. To the front-end user, the worktree path is the interface.\nHowever, for above ability, we need the user to explicitly specify the\nworktree id.\n\nFrom my perspective, this is not a good design which is against our\ndesign.\n\n[1] https://lore.kernel.org/git/xmqq5xqn8w6r.fsf@gitster.g/\n"},{"id":"508493","messageId":"xmqqo71tfsif.fsf@gitster.g","threadId":"62572","inReplyTo":"CAPig+cQHW9=A5ejU5aZ+Wy0uOQsLU_uqUibeYzZs2PXK37Vpbw@mail.gmail.com","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-12-03T01:46:16Z","receivedAt":"2024-12-03T01:46:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Sunshine <sunshine@sunshineco.com> writes:\n\n> Unfortunately, I haven't had time lately to follow all these\n> worktree-related changes or discussions, but perhaps shejialuo is\n> referring to the ability, from within one worktree, to mention a ref\n> from another worktree (which is a feature Duy added some time after\n> the initial worktree implementation).\n\nAh, yes, that exposes (and has to expose) the worktree ID.  It still\ndoes not have to be unique across repositories (only has to unique\namong the worktrees that share the same single repository).\n\nThanks.\n"},{"id":"508494","messageId":"025b01db4526$3b05ef00$b111cd00$@nexbridge.com","threadId":"62572","inReplyTo":"xmqqo71tfsif.fsf@gitster.g","subject":"RE: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"","fromEmail":"rsbecker@nexbridge.com","sentAt":"2024-12-03T01:53:57Z","receivedAt":"2024-12-03T01:54:24Z","isPatch":true,"sender":{"key":"randall.becker@nexbridge.ca","avatar":"https://avatars.githubusercontent.com/u/28956764?v=4"},"body":"On December 2, 2024 8:46 PM, Junio C Hamano wrote:\n>Eric Sunshine <sunshine@sunshineco.com> writes:\n>\n>> Unfortunately, I haven't had time lately to follow all these\n>> worktree-related changes or discussions, but perhaps shejialuo is\n>> referring to the ability, from within one worktree, to mention a ref\n>> from another worktree (which is a feature Duy added some time after\n>> the initial worktree implementation).\n>\n>Ah, yes, that exposes (and has to expose) the worktree ID.  It still does\nnot have to\n>be unique across repositories (only has to unique among the worktrees that\nshare\n>the same single repository).\n\nI might be mistaken, but I think the intent of the worktree series being\ndiscussed\ndeliberately wanted the worktree ID to be globally unique on a specific\nmachine.\nI might be wrong (hoping I am). The original author should comment on this.\n\n"},{"id":"508495","messageId":"xmqqiks1fqgl.fsf@gitster.g","threadId":"62572","inReplyTo":"025b01db4526$3b05ef00$b111cd00$@nexbridge.com","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-12-03T02:30:34Z","receivedAt":"2024-12-03T02:30:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"<rsbecker@nexbridge.com> writes:\n\n>>Ah, yes, that exposes (and has to expose) the worktree ID.  It still does\n> not have to\n>>be unique across repositories (only has to unique among the worktrees that\n> share\n>>the same single repository).\n>\n> I might be mistaken, but I think the intent of the worktree series being\n> discussed\n> deliberately wanted the worktree ID to be globally unique on a specific\n> machine.\n\nThat is my understanding, but I do not understand why such a\nuniqueness is needed.  Repositories are not even aware of other\nrepositories, in any sense to make it matter to know worktree IDs\nother repositories are using.  Until there is an attempt to link a\nworktree that used to belong to a repository to a different\nrepository, that is.  At that time, names must be made unique among\nworktrees that belong to the adopting repository, of course, but the\nnames used in the original repository for its worktrees would not\nmatter at that point, I would think.\n\n> I might be wrong (hoping I am). The original author should comment on this.\n\nSure.  Thanks for commenting.\n"},{"id":"508506","messageId":"D61R68MFWDIU.12PI8AA8S3G86@pm.me","threadId":"62572","inReplyTo":"xmqqiks1fqgl.fsf@gitster.g","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-12-03T03:42:02Z","receivedAt":"2024-12-03T03:42:08Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Mon Dec 2, 2024 at 8:30 PM CST, Junio C Hamano wrote:\n> <rsbecker@nexbridge.com> writes:\n>\n>>>Ah, yes, that exposes (and has to expose) the worktree ID.  It still does\n>> not have to\n>>>be unique across repositories (only has to unique among the worktrees that\n>> share\n>>>the same single repository).\n>>\n>> I might be mistaken, but I think the intent of the worktree series being\n>> discussed\n>> deliberately wanted the worktree ID to be globally unique on a specific\n>> machine.\n>\n> That is my understanding, but I do not understand why such a\n> uniqueness is needed.  Repositories are not even aware of other\n> repositories, in any sense to make it matter to know worktree IDs\n> other repositories are using.  Until there is an attempt to link a\n> worktree that used to belong to a repository to a different\n> repository, that is.  At that time, names must be made unique among\n> worktrees that belong to the adopting repository, of course, but the\n> names used in the original repository for its worktrees would not\n> matter at that point, I would think.\n\nPerhaps I should've have come up with a better series name, I think\nthere's been a lot of hang-up with the term \"unique\". When I refer to\nuniqueness in this context, I'm not advocating for strict, absolute\nuniqueness in the sense of ensuring no collisions under any conceivable\ncircumstance, or requiring that repositories are now aware of other\nrepositories. Instead, I'm discussing uniqueness from a practical\nperspective: the combination of a random 32-bit integer from a CSPRNG\nwith a worktree name should be \"unique\" for all intents and purposes.\nThe theoretical risk of a collision does exist, of course, but the\nprobability is astronomically lower than the current approach, rendering\nit effectively \"unique\" in practice.\n\nYou're correct in that the worktree ids are only relevant within the\ncontext of a single repository. However, I've already demonstrated that\nit's possible for a repository to \"repair\" (i.e., take over) a worktree\nbelonging to another repository if the ids match (inferred backlink).\nIn my experience, there's some pretty common names for worktrees (e.g.,\n\"main\", \"master\", \"develop\", \"hotfix\", etc.), and it's not uncommon for\nmultiple repositories to have worktrees with the same name. This can be\navoided entirely by introducing some randomness into the worktree id and\nsignificantly reducing the probability of a collision (e.g., one\nrepository would have a `develop-54678976` id while another would have\na `develop-987465246` id), which is the primary motivation behind this\nseries.\n\nAs I've mentioned earlier, the concept of a suffix is not new and should\nnot be a breaking change. It's already possible to have worktrees with\na different id from the public worktree directory name, so users and\nscripts should not just assume them to be the same (this is buggy\nbehavior), but instead should be querying the worktree id from the `.git`\nfile or `git rev-parse --git-dir` if they really need it (very rare).\nAs part of this series I did add the worktree id to the `worktree list`\noutput to make it easier for scripts to query this information if they\ndo need it.\n\nPerhaps this \"take-over\" scenario is not that big of a concern in\npractice, I just noted that this behavior was made possible in the\n`es/worktree-repair-copied` topic and I thought it was worth addressing.\nIf it's decided that this is not that big of a concern, then I suppose\nthis series can be dropped (although I've made some other QoL\nimprovements that may be useful).\n\nBest,\n\nCaleb\n\n"},{"id":"508510","messageId":"xmqqiks1e5zs.fsf@gitster.g","threadId":"62572","inReplyTo":"D61R68MFWDIU.12PI8AA8S3G86@pm.me","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2024-12-03T04:37:59Z","receivedAt":"2024-12-03T04:38:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Caleb White <cdwhite3@pm.me> writes:\n\n> You're correct in that the worktree ids are only relevant within the\n> context of a single repository. However, I've already demonstrated that\n> it's possible for a repository to \"repair\" (i.e., take over) a worktree\n> belonging to another repository if the ids match (inferred backlink).\n\nI know.  But isn't that a BUG in the code that \"repair\"s?  If a\nworktree had a name 'develop' that was OK in the context of\nrepository X, and when you \"repair\" things so that it becomes one of\nthe worktrees of a different repository Y, the \"repair\" operation is\nwhat MUST make sure that the worktree that used to be known as\n'develop' to repository X does not interfere any existing worktrees\nthat is attached to the repository Y.  If the repository Y already\nhad a worktree called 'develop', the \"repair\" operation must make\nsure that the newly adopted worktree would get a different name.\n\nBut then, the concern is exactly the same when you try to create a\nnew worktree (no \"repair\" involved) in repository Y and try to give\nit a name 'develop', isn't it?  You have to make sure that there is\nno worktree that is called 'develop' in the repository Y before\ngiving it the name.  Is it broken?  If not, what are we doing to\nmake sure we won't give the name 'develop' to the new worktree?\nCertainly we do not use any hash or random number for that, so why\ndoes this new series need to use a random number?\n\n"},{"id":"508514","messageId":"D61TI8S0M79X.1YEUCB7FI6CC@pm.me","threadId":"62572","inReplyTo":"xmqqiks1e5zs.fsf@gitster.g","subject":"Re: [PATCH v2 0/3] Ensure unique worktree ids across repositories","fromName":"Caleb White","fromEmail":"cdwhite3@pm.me","sentAt":"2024-12-03T05:31:46Z","receivedAt":"2024-12-03T05:31:51Z","isPatch":true,"sender":{"key":"cdwhite3@pm.me","avatar":"https://avatars.githubusercontent.com/u/4176520?v=4"},"body":"On Mon Dec 2, 2024 at 10:37 PM CST, Junio C Hamano wrote:\n> Caleb White <cdwhite3@pm.me> writes:\n>\n>> You're correct in that the worktree ids are only relevant within the\n>> context of a single repository. However, I've already demonstrated that\n>> it's possible for a repository to \"repair\" (i.e., take over) a worktree\n>> belonging to another repository if the ids match (inferred backlink).\n>\n> I know.  But isn't that a BUG in the code that \"repair\"s?  If a\n> worktree had a name 'develop' that was OK in the context of\n> repository X, and when you \"repair\" things so that it becomes one of\n> the worktrees of a different repository Y, the \"repair\" operation is\n> what MUST make sure that the worktree that used to be known as\n> 'develop' to repository X does not interfere any existing worktrees\n> that is attached to the repository Y.  If the repository Y already\n> had a worktree called 'develop', the \"repair\" operation must make\n> sure that the newly adopted worktree would get a different name.\n\nNo, this is incorrect---there should be no reason to \"repair\" a worktree\nfrom another repository in the first place. That would be undefined\nbehavior and is indicative of a user mistake or unintentional repair\n(e.g., it would make no sense for the php-src repository to repair\na worktree from this git repository). The repair operation is only\nintended to be used with worktrees of the same repository.\n\n> But then, the concern is exactly the same when you try to create a\n> new worktree (no \"repair\" involved) in repository Y and try to give\n> it a name 'develop', isn't it?  You have to make sure that there is\n> no worktree that is called 'develop' in the repository Y before\n> giving it the name.  Is it broken?  If not, what are we doing to\n> make sure we won't give the name 'develop' to the new worktree?\n> Certainly we do not use any hash or random number for that, so why\n> does this new series need to use a random number?\n\nWe currently suffix an auto incrementing number in this use case, so \nyou can have two `develop` worktrees (located in different directories\nof course), and one will have an id of `develop` and the other will have\nan id of `develop1`.\n\nBest,\n\n"}]}