From patchwork Fri Nov 29 22:37:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Caleb White X-Patchwork-Id: 13888969 Received: from mail-10630.protonmail.ch (mail-10630.protonmail.ch [79.135.106.30]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BDB9F2C18C for ; Fri, 29 Nov 2024 22:37:53 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.30 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732919877; cv=none; b=QPHqPPN4cFQ5+OtUkZCpEGmeSYUU/F+/nQ5XZ9dS74C6noSH0YtdD0BGz9AqMwPLLUJ9bxvrKX6OqrG72WjKV6Im33wIsf0C17tJvMthyTnyp2cw0SvCEvU2cr8nDym4QTqEiZmM51/tWyLadseIqi7yiIyCs7mp0nVyYcLUa1E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732919877; c=relaxed/simple; bh=zIejrWMe/jlp3mfUpXYL/815hM8TrDXXMwsgNkPMTPY=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=FPCGXFE5azw4InUqP8VwRikF3Gv1xgwThHjQkXc5CF7JQ2WeBnWW5IOev1y9JLoFCQ3hsOu1+V7GlNJbgVT2rkuryfpTcW1N/EL/ETVCNF75o+2qCLygmDbhSt8u7t29ZUHXan0QwJQ8hmyfbCtY3H2qKq03DU8DumQ/yTmpRK4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=V6weiK72; arc=none smtp.client-ip=79.135.106.30 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="V6weiK72" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1732919870; x=1733179070; bh=AIW1kfEVMJVPPc4WyyWnwIJDgM+CgZAFei4c8JMbiPk=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=V6weiK72JgvolwIe3nyQkH2a/vtwkBw6sBK8rnp5pe7JGh8EBEraYekboD9o4pXlM KrRhc0FXK3a6B2YutoRRSmJqUVBjR2P4tXjbo4KXEXzxaTgjaqlDC5MSvGX2wWHO5f C9mZ6jnYgeZVPndXddqe9WkBk6GOUqbhnJX7r9XyKNA8hheSm+QmHXARZ7n1M+mNjJ kPNWtiimevek++6uvGtaBFun2fu2CM5jHW/OHhCdDNyP98DbgPtm9/br5N32aqGy7S 2ZN5hcmrMkpIQuj7ju7LQnC30K6VN6v8+WEhAguJhfnGVJqW0PeyUkiIF/ncNRZWgV 29zn4cpYxsHlQ== Date: Fri, 29 Nov 2024 22:37:44 +0000 To: git@vger.kernel.org From: Caleb White Cc: shejialuo , Junio C Hamano , Caleb White Subject: [PATCH v2 1/3] worktree: add worktree with unique suffix Message-ID: <20241129-wt_unique_ids-v2-1-ff444e9e625a@pm.me> In-Reply-To: <20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me> References: <20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me> Feedback-ID: 31210263:user:proton X-Pm-Message-ID: 949acb401e8a57b4258244f4591a0444762b34b7 Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The `es/worktree-repair-copied` topic added support for repairing a worktree from a copy scenario. However, the topic added the ability for a repository to "take over" a worktree from another repository if the worktree_id matched a worktree inside the current repository which can happen if two repositories use the same worktree name. This teaches Git to create worktrees with a unique suffix so the worktree_id is unique across all repositories even if they have the same name. For example creating a worktree `develop` would look like: foo/ ├── .git/worktrees/develop-5445874156/ └── develop/ bar/ ├── .git/worktrees/develop-1549518426/ └── develop/ The actual worktree directory name is still `develop`, but the worktree_id is unique and prevents the "take over" scenario. The suffix is given by the `git_rand()` function. Worktree ids can already differ from the actual directory name (appended with a number like `develop1`) if the worktree name was already taken, so this should not be a drastic change. Signed-off-by: Caleb White --- Documentation/git-worktree.txt | 5 +- builtin/worktree.c | 6 +++ t/t0035-safe-bare-repository.sh | 4 +- t/t0600-reffiles-backend.sh | 10 ++-- t/t0601-reffiles-pack-refs.sh | 4 +- t/t0610-reftable-basics.sh | 54 +++++++++++----------- t/t1407-worktree-ref-store.sh | 4 +- t/t1410-reflog.sh | 10 ++-- t/t1415-worktree-refs.sh | 26 +++++------ t/t1450-fsck.sh | 14 +++--- t/t1500-rev-parse.sh | 6 +-- t/t2400-worktree-add.sh | 51 +++++++++++---------- t/t2401-worktree-prune.sh | 20 ++++---- t/t2403-worktree-move.sh | 32 ++++++------- t/t2405-worktree-submodule.sh | 10 ++-- t/t2406-worktree-repair.sh | 93 ++++++++++++++++++++++++-------------- t/t2407-worktree-heads.sh | 27 +++++------ t/t3200-branch.sh | 10 ++-- t/t5304-prune.sh | 2 +- t/t7412-submodule-absorbgitdirs.sh | 4 +- 20 files changed, 212 insertions(+), 180 deletions(-) diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index 8340b7f028e6c1c3bae3de0879e9754098466d14..e0604b043361828f94b58f676a5ed4f15b116348 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -352,12 +352,11 @@ DETAILS ------- Each linked worktree has a private sub-directory in the repository's `$GIT_DIR/worktrees` directory. The private sub-directory's name is usually -the base name of the linked worktree's path, possibly appended with a +the base name of the linked worktree's path, appended with a random number to make it unique. For example, when `$GIT_DIR=/path/main/.git` the command `git worktree add /path/other/test-next next` creates the linked worktree in `/path/other/test-next` and also creates a -`$GIT_DIR/worktrees/test-next` directory (or `$GIT_DIR/worktrees/test-next1` -if `test-next` is already taken). +`$GIT_DIR/worktrees/test-next-#######` directory. Within a linked worktree, `$GIT_DIR` is set to point to this private directory (e.g. `/path/main/.git/worktrees/test-next` in the example) and diff --git a/builtin/worktree.c b/builtin/worktree.c index fde9ff4dc9a734c655e95ccd62774282950cbba6..3ad355ca762729401fc0c8625f4fd05b154a84ec 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -421,6 +421,7 @@ static int add_worktree(const char *path, const char *refname, struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; struct strbuf sb = STRBUF_INIT; const char *name; + const char *suffix; struct strvec child_env = STRVEC_INIT; unsigned int counter = 0; int len, ret; @@ -455,6 +456,11 @@ static int add_worktree(const char *path, const char *refname, strbuf_reset(&sb); name = sb_name.buf; git_path_buf(&sb_repo, "worktrees/%s", name); + suffix = getenv("GIT_TEST_WORKTREE_SUFFIX"); + if (suffix) + strbuf_addf(&sb_repo, "-%s", suffix); + else + strbuf_addf(&sb_repo, "-%u", git_rand()); len = sb_repo.len; if (safe_create_leading_directories_const(sb_repo.buf)) die_errno(_("could not create leading directories of '%s'"), diff --git a/t/t0035-safe-bare-repository.sh b/t/t0035-safe-bare-repository.sh index d3cb2a1cb9edb8f9ad7480be6ec3e02b464046bd..30cbf7fd32e2e4afd6d680e0328ee18b791778da 100755 --- a/t/t0035-safe-bare-repository.sh +++ b/t/t0035-safe-bare-repository.sh @@ -41,7 +41,7 @@ test_expect_success 'setup an embedded bare repo, secondary worktree and submodu git -c protocol.file.allow=always \ submodule add --name subn -- ./bare-repo subd ) && - test_path_is_dir outer-repo/.git/worktrees/outer-secondary && + test_path_is_dir outer-repo/.git/worktrees/outer-secondary-* && test_path_is_dir outer-repo/.git/modules/subn ' @@ -97,7 +97,7 @@ test_expect_success 'no trace when "bare repository" is a subdir of .git' ' ' test_expect_success 'no trace in $GIT_DIR of secondary worktree' ' - expect_accepted_implicit -C outer-repo/.git/worktrees/outer-secondary + expect_accepted_implicit -C outer-repo/.git/worktrees/outer-secondary-* ' test_expect_success 'no trace in $GIT_DIR of a submodule' ' diff --git a/t/t0600-reffiles-backend.sh b/t/t0600-reffiles-backend.sh index bef2b70871364931ab8b3ead950f59d11b6fe216..8da81b1ae34f5f095ba9406e8f031fd5e43ac789 100755 --- a/t/t0600-reffiles-backend.sh +++ b/t/t0600-reffiles-backend.sh @@ -256,12 +256,12 @@ test_expect_success 'delete fails cleanly if packed-refs.new write fails' ' test_cmp unchanged actual ' -RWT="test-tool ref-store worktree:wt" +RWT="test-tool ref-store worktree:wt-123" RMAIN="test-tool ref-store worktree:main" test_expect_success 'setup worktree' ' test_commit first && - git worktree add -b wt-main wt && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add -b wt-main wt && ( cd wt && test_commit second @@ -279,9 +279,9 @@ test_expect_success 'for_each_reflog()' ' mkdir -p .git/logs/refs/bisect && echo $ZERO_OID >.git/logs/refs/bisect/random && - echo $ZERO_OID >.git/worktrees/wt/logs/PSEUDO_WT_HEAD && - mkdir -p .git/worktrees/wt/logs/refs/bisect && - echo $ZERO_OID >.git/worktrees/wt/logs/refs/bisect/wt-random && + echo $ZERO_OID >.git/worktrees/wt-123/logs/PSEUDO_WT_HEAD && + mkdir -p .git/worktrees/wt-123/logs/refs/bisect && + echo $ZERO_OID >.git/worktrees/wt-123/logs/refs/bisect/wt-random && $RWT for-each-reflog >actual && cat >expected <<-\EOF && diff --git a/t/t0601-reffiles-pack-refs.sh b/t/t0601-reffiles-pack-refs.sh index d8cbd3f202b5f00c9a94c5a2ea2dced6606b6f4d..d6597938caca5e6c3a6e86b860f3c0d309aa2140 100755 --- a/t/t0601-reffiles-pack-refs.sh +++ b/t/t0601-reffiles-pack-refs.sh @@ -326,8 +326,8 @@ test_expect_success 'refs/worktree must not be packed' ' git pack-refs --all && test_path_is_missing .git/refs/tags/wt1 && test_path_is_file .git/refs/worktree/foo && - test_path_is_file .git/worktrees/wt1/refs/worktree/foo && - test_path_is_file .git/worktrees/wt2/refs/worktree/foo + test_path_is_file .git/worktrees/wt1-*/refs/worktree/foo && + test_path_is_file .git/worktrees/wt2-*/refs/worktree/foo ' # we do not want to count on running pack-refs to diff --git a/t/t0610-reftable-basics.sh b/t/t0610-reftable-basics.sh index eaf6fab6d29f01430abae3c7abf5a750d4271a36..f21fd9dbba2b77636045b297073e340209d61a2d 100755 --- a/t/t0610-reftable-basics.sh +++ b/t/t0610-reftable-basics.sh @@ -965,11 +965,11 @@ test_expect_success 'worktree: adding worktree creates separate stack' ' test_commit -C repo A && git -C repo worktree add ../worktree && - test_path_is_file repo/.git/worktrees/worktree/refs/heads && + test_path_is_file repo/.git/worktrees/worktree-*/refs/heads && echo "ref: refs/heads/.invalid" >expect && - test_cmp expect repo/.git/worktrees/worktree/HEAD && - test_path_is_dir repo/.git/worktrees/worktree/reftable && - test_path_is_file repo/.git/worktrees/worktree/reftable/tables.list + test_cmp expect repo/.git/worktrees/worktree-*/HEAD && + test_path_is_dir repo/.git/worktrees/worktree-*/reftable && + test_path_is_file repo/.git/worktrees/worktree-*/reftable/tables.list ' test_expect_success 'worktree: pack-refs in main repo packs main refs' ' @@ -982,10 +982,10 @@ test_expect_success 'worktree: pack-refs in main repo packs main refs' ' GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ git -C worktree update-ref refs/worktree/per-worktree HEAD && - test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 4 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 3 repo/.git/reftable/tables.list && git -C repo pack-refs && - test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 4 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list ' @@ -999,10 +999,10 @@ test_expect_success 'worktree: pack-refs in worktree packs worktree refs' ' GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ git -C worktree update-ref refs/worktree/per-worktree HEAD && - test_line_count = 4 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 4 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 3 repo/.git/reftable/tables.list && git -C worktree pack-refs && - test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 3 repo/.git/reftable/tables.list ' @@ -1014,12 +1014,12 @@ test_expect_success 'worktree: creating shared ref updates main stack' ' git -C repo worktree add ../worktree && git -C repo pack-refs && git -C worktree pack-refs && - test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list && GIT_TEST_REFTABLE_AUTOCOMPACTION=false \ git -C worktree update-ref refs/heads/shared HEAD && - test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 2 repo/.git/reftable/tables.list ' @@ -1031,11 +1031,11 @@ test_expect_success 'worktree: creating per-worktree ref updates worktree stack' git -C repo worktree add ../worktree && git -C repo pack-refs && git -C worktree pack-refs && - test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list && git -C worktree update-ref refs/bisect/per-worktree HEAD && - test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 2 repo/.git/worktrees/worktree-*/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list ' @@ -1044,14 +1044,14 @@ test_expect_success 'worktree: creating per-worktree ref from main repo' ' git init repo && test_commit -C repo A && - git -C repo worktree add ../worktree && + GIT_TEST_WORKTREE_SUFFIX=456 git -C repo worktree add ../worktree && git -C repo pack-refs && git -C worktree pack-refs && - test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/worktree-456/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list && - git -C repo update-ref worktrees/worktree/refs/bisect/per-worktree HEAD && - test_line_count = 2 repo/.git/worktrees/worktree/reftable/tables.list && + git -C repo update-ref worktrees/worktree-456/refs/bisect/per-worktree HEAD && + test_line_count = 2 repo/.git/worktrees/worktree-456/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list ' @@ -1060,18 +1060,18 @@ test_expect_success 'worktree: creating per-worktree ref from second worktree' ' git init repo && test_commit -C repo A && - git -C repo worktree add ../wt1 && - git -C repo worktree add ../wt2 && + GIT_TEST_WORKTREE_SUFFIX=123 git -C repo worktree add ../wt1 && + GIT_TEST_WORKTREE_SUFFIX=456 git -C repo worktree add ../wt2 && git -C repo pack-refs && git -C wt1 pack-refs && git -C wt2 pack-refs && - test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && - test_line_count = 1 repo/.git/worktrees/wt2/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/wt1-123/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/wt2-456/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list && - git -C wt1 update-ref worktrees/wt2/refs/bisect/per-worktree HEAD && - test_line_count = 1 repo/.git/worktrees/wt1/reftable/tables.list && - test_line_count = 2 repo/.git/worktrees/wt2/reftable/tables.list && + git -C wt1 update-ref worktrees/wt2-456/refs/bisect/per-worktree HEAD && + test_line_count = 1 repo/.git/worktrees/wt1-123/reftable/tables.list && + test_line_count = 2 repo/.git/worktrees/wt2-456/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list ' @@ -1080,18 +1080,18 @@ test_expect_success 'worktree: can create shared and per-worktree ref in one tra git init repo && test_commit -C repo A && - git -C repo worktree add ../worktree && + GIT_TEST_WORKTREE_SUFFIX=123 git -C repo worktree add ../worktree && git -C repo pack-refs && git -C worktree pack-refs && - test_line_count = 1 repo/.git/worktrees/worktree/reftable/tables.list && + test_line_count = 1 repo/.git/worktrees/worktree-123/reftable/tables.list && test_line_count = 1 repo/.git/reftable/tables.list && cat >stdin <<-EOF && - create worktrees/worktree/refs/bisect/per-worktree HEAD + create worktrees/worktree-123/refs/bisect/per-worktree HEAD create refs/branches/shared HEAD EOF git -C repo update-ref --stdin actual && + test-tool ref-store worktree:link-wt-123 for-each-reflog-ent HEAD >actual && test_must_be_empty actual ) ' @@ -418,17 +418,17 @@ test_expect_success 'expire one of multiple worktrees' ' cd main-wt2 && test_tick && test_commit foo && - git worktree add link-wt && + GIT_TEST_WORKTREE_SUFFIX=456 git worktree add link-wt && test_tick && test_commit -C link-wt foobar && test_tick && - test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \ + test-tool ref-store worktree:link-wt-456 for-each-reflog-ent HEAD \ >expect-link-wt && git reflog expire --verbose --all --expire=$test_tick \ --single-worktree && test-tool ref-store worktree:main for-each-reflog-ent HEAD \ >actual-main && - test-tool ref-store worktree:link-wt for-each-reflog-ent HEAD \ + test-tool ref-store worktree:link-wt-456 for-each-reflog-ent HEAD \ >actual-link-wt && test_must_be_empty actual-main && test_cmp expect-link-wt actual-link-wt diff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh index eb4eec8becbfa64efcde4e866334363a866c01a2..c46bf29aa4d9ceac85147d685a1d23144ec23b2b 100755 --- a/t/t1415-worktree-refs.sh +++ b/t/t1415-worktree-refs.sh @@ -9,8 +9,8 @@ test_expect_success 'setup' ' test_commit initial && test_commit wt1 && test_commit wt2 && - git worktree add wt1 wt1 && - git worktree add wt2 wt2 && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add wt1 wt1 && + GIT_TEST_WORKTREE_SUFFIX=456 git worktree add wt2 wt2 && git checkout initial && git update-ref refs/worktree/foo HEAD && git -C wt1 update-ref refs/worktree/foo HEAD && @@ -37,16 +37,16 @@ test_expect_success 'ambiguous main-worktree/HEAD' ' ' test_expect_success 'resolve worktrees/xx/HEAD' ' - test_cmp_rev worktrees/wt1/HEAD wt1 && - ( cd wt1 && test_cmp_rev worktrees/wt1/HEAD wt1 ) && - ( cd wt2 && test_cmp_rev worktrees/wt1/HEAD wt1 ) + test_cmp_rev worktrees/wt1-123/HEAD wt1 && + ( cd wt1 && test_cmp_rev worktrees/wt1-123/HEAD wt1 ) && + ( cd wt2 && test_cmp_rev worktrees/wt1-123/HEAD wt1 ) ' test_expect_success 'ambiguous worktrees/xx/HEAD' ' - git update-ref refs/heads/worktrees/wt1/HEAD $(git rev-parse HEAD) && - test_when_finished git update-ref -d refs/heads/worktrees/wt1/HEAD && - git rev-parse worktrees/wt1/HEAD 2>warn && - grep "worktrees/wt1/HEAD.*ambiguous" warn + git update-ref refs/heads/worktrees/wt1-123/HEAD $(git rev-parse HEAD) && + test_when_finished git update-ref -d refs/heads/worktrees/wt1-123/HEAD && + git rev-parse worktrees/wt1-123/HEAD 2>warn && + grep "worktrees/wt1-123/HEAD.*ambiguous" warn ' test_expect_success 'reflog of main-worktree/HEAD' ' @@ -58,12 +58,12 @@ test_expect_success 'reflog of main-worktree/HEAD' ' ' test_expect_success 'reflog of worktrees/xx/HEAD' ' - git -C wt2 reflog HEAD | sed "s/HEAD/worktrees\/wt2\/HEAD/" >expected && - git reflog worktrees/wt2/HEAD >actual && + git -C wt2 reflog HEAD | sed "s/HEAD/worktrees\/wt2-456\/HEAD/" >expected && + git reflog worktrees/wt2-456/HEAD >actual && test_cmp expected actual && - git -C wt1 reflog worktrees/wt2/HEAD >actual.wt1 && + git -C wt1 reflog worktrees/wt2-456/HEAD >actual.wt1 && test_cmp expected actual.wt1 && - git -C wt2 reflog worktrees/wt2/HEAD >actual.wt2 && + git -C wt2 reflog worktrees/wt2-456/HEAD >actual.wt2 && test_cmp expected actual.wt2 ' diff --git a/t/t1450-fsck.sh b/t/t1450-fsck.sh index 280cbf3e031e1ab67ed28aa2af4c3b105b7d254e..de25ab24fd8924e288969650a658908a5e9afd22 100755 --- a/t/t1450-fsck.sh +++ b/t/t1450-fsck.sh @@ -152,10 +152,10 @@ test_expect_success REFFILES 'HEAD link pointing at a funny object (from differe test_expect_success REFFILES 'other worktree HEAD link pointing at a funny object' ' test_when_finished "git worktree remove -f other" && - git worktree add other && - echo $ZERO_OID >.git/worktrees/other/HEAD && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add other && + echo $ZERO_OID >.git/worktrees/other-123/HEAD && test_must_fail git fsck 2>out && - test_grep "worktrees/other/HEAD: detached HEAD points" out + test_grep "worktrees/other-123/HEAD: detached HEAD points" out ' test_expect_success 'other worktree HEAD link pointing at missing object' ' @@ -164,7 +164,7 @@ test_expect_success 'other worktree HEAD link pointing at missing object' ' object_id=$(echo "Contents missing from repo" | git hash-object --stdin) && test-tool -C other ref-store main update-ref msg HEAD $object_id "" REF_NO_DEREF,REF_SKIP_OID_VERIFICATION && test_must_fail git fsck 2>out && - test_grep "worktrees/other/HEAD: invalid sha1 pointer" out + test_grep "worktrees/other-.*/HEAD: invalid sha1 pointer" out ' test_expect_success 'other worktree HEAD link pointing at a funny place' ' @@ -172,7 +172,7 @@ test_expect_success 'other worktree HEAD link pointing at a funny place' ' git worktree add other && git -C other symbolic-ref HEAD refs/funny/place && test_must_fail git fsck 2>out && - test_grep "worktrees/other/HEAD points to something strange" out + test_grep "worktrees/other-.*/HEAD points to something strange" out ' test_expect_success 'commit with multiple signatures is okay' ' @@ -1033,7 +1033,7 @@ test_expect_success 'fsck error on gitattributes with excessive size' ' test_expect_success 'fsck detects problems in worktree index' ' test_when_finished "git worktree remove -f wt" && - git worktree add wt && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add wt && echo "this will be removed to break the worktree index" >wt/file && git -C wt add file && @@ -1042,7 +1042,7 @@ test_expect_success 'fsck detects problems in worktree index' ' test_must_fail git fsck --name-objects >actual 2>&1 && cat >expect <<-EOF && - missing blob $blob (.git/worktrees/wt/index:file) + missing blob $blob (.git/worktrees/wt-123/index:file) EOF test_cmp expect actual ' diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index 30c31918fde6539d52800e18dfbb3423b5b73491..49e0ac68858d922336a498caaa743f2f4011d28a 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -80,7 +80,7 @@ test_expect_success 'setup' ' git checkout -b side && test_commit def && git checkout main && - git worktree add worktree side + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add worktree side ' test_rev_parse toplevel false false true '' .git "$ROOT/.git" @@ -113,7 +113,7 @@ test_expect_success 'rev-parse --path-format=absolute' ' test_one "." "$ROOT/.git" --path-format=absolute --git-common-dir && test_one "sub/dir" "$ROOT/.git" --path-format=absolute --git-dir && test_one "sub/dir" "$ROOT/.git" --path-format=absolute --git-common-dir && - test_one "worktree" "$ROOT/.git/worktrees/worktree" --path-format=absolute --git-dir && + test_one "worktree" "$ROOT/.git/worktrees/worktree-123" --path-format=absolute --git-dir && test_one "worktree" "$ROOT/.git" --path-format=absolute --git-common-dir && test_one "." "$ROOT" --path-format=absolute --show-toplevel && test_one "." "$ROOT/.git/objects" --path-format=absolute --git-path objects && @@ -125,7 +125,7 @@ test_expect_success 'rev-parse --path-format=relative' ' test_one "." ".git" --path-format=relative --git-common-dir && test_one "sub/dir" "../../.git" --path-format=relative --git-dir && test_one "sub/dir" "../../.git" --path-format=relative --git-common-dir && - test_one "worktree" "../.git/worktrees/worktree" --path-format=relative --git-dir && + test_one "worktree" "../.git/worktrees/worktree-123" --path-format=relative --git-dir && test_one "worktree" "../.git" --path-format=relative --git-common-dir && test_one "." "./" --path-format=relative --show-toplevel && test_one "." ".git/objects" --path-format=relative --git-path objects && diff --git a/t/t2400-worktree-add.sh b/t/t2400-worktree-add.sh index bc4f4e90d6ecfedbde9082bda6f9e4eec3e3575d..33262b49f18521c805f188a10f944dbfa9f285ba 100755 --- a/t/t2400-worktree-add.sh +++ b/t/t2400-worktree-add.sh @@ -71,21 +71,21 @@ test_expect_success '"add" worktree' ' test_expect_success '"add" worktree with lock' ' git worktree add --detach --lock here-with-lock main && test_when_finished "git worktree unlock here-with-lock || :" && - test -f .git/worktrees/here-with-lock/locked + test -f .git/worktrees/here-with-lock-*/locked ' test_expect_success '"add" worktree with lock and reason' ' lock_reason="why not" && git worktree add --detach --lock --reason "$lock_reason" here-with-lock-reason main && test_when_finished "git worktree unlock here-with-lock-reason || :" && - test -f .git/worktrees/here-with-lock-reason/locked && + test -f .git/worktrees/here-with-lock-reason-*/locked && echo "$lock_reason" >expect && - test_cmp expect .git/worktrees/here-with-lock-reason/locked + test_cmp expect .git/worktrees/here-with-lock-reason-*/locked ' test_expect_success '"add" worktree with reason but no lock' ' test_must_fail git worktree add --detach --reason "why not" here-with-reason-only main && - test_path_is_missing .git/worktrees/here-with-reason-only/locked + test_path_is_missing .git/worktrees/here-with-reason-only-*/locked ' test_expect_success '"add" worktree from a subdir' ' @@ -413,16 +413,16 @@ test_expect_success '"add --orphan" with empty repository' ' test_expect_success '"add" worktree with orphan branch and lock' ' git worktree add --lock --orphan -b orphanbr orphan-with-lock && test_when_finished "git worktree unlock orphan-with-lock || :" && - test -f .git/worktrees/orphan-with-lock/locked + test -f .git/worktrees/orphan-with-lock-*/locked ' test_expect_success '"add" worktree with orphan branch, lock, and reason' ' lock_reason="why not" && git worktree add --detach --lock --reason "$lock_reason" orphan-with-lock-reason main && test_when_finished "git worktree unlock orphan-with-lock-reason || :" && - test -f .git/worktrees/orphan-with-lock-reason/locked && + test -f .git/worktrees/orphan-with-lock-reason-*/locked && echo "$lock_reason" >expect && - test_cmp expect .git/worktrees/orphan-with-lock-reason/locked + test_cmp expect .git/worktrees/orphan-with-lock-reason-*/locked ' # Note: Quoted arguments containing spaces are not supported. @@ -1088,10 +1088,10 @@ test_expect_success '"add" invokes post-checkout hook (branch)' ' post_checkout_hook && { echo $ZERO_OID $(git rev-parse HEAD) 1 && - echo $(pwd)/.git/worktrees/gumby && + echo $(pwd)/.git/worktrees/gumby-123 && echo $(pwd)/gumby } >hook.expect && - git worktree add gumby && + GIT_TEST_WORKTREE_SUFFIX="123" git worktree add gumby && test_cmp hook.expect gumby/hook.actual ' @@ -1099,10 +1099,10 @@ test_expect_success '"add" invokes post-checkout hook (detached)' ' post_checkout_hook && { echo $ZERO_OID $(git rev-parse HEAD) 1 && - echo $(pwd)/.git/worktrees/grumpy && + echo $(pwd)/.git/worktrees/grumpy-456 && echo $(pwd)/grumpy } >hook.expect && - git worktree add --detach grumpy && + GIT_TEST_WORKTREE_SUFFIX="456" git worktree add --detach grumpy && test_cmp hook.expect grumpy/hook.actual ' @@ -1117,10 +1117,10 @@ test_expect_success '"add" in other worktree invokes post-checkout hook' ' post_checkout_hook && { echo $ZERO_OID $(git rev-parse HEAD) 1 && - echo $(pwd)/.git/worktrees/guppy && + echo $(pwd)/.git/worktrees/guppy-789 && echo $(pwd)/guppy } >hook.expect && - git -C gloopy worktree add --detach ../guppy && + GIT_TEST_WORKTREE_SUFFIX="789" git -C gloopy worktree add --detach ../guppy && test_cmp hook.expect guppy/hook.actual ' @@ -1129,11 +1129,11 @@ test_expect_success '"add" in bare repo invokes post-checkout hook' ' git clone --bare . bare && { echo $ZERO_OID $(git --git-dir=bare rev-parse HEAD) 1 && - echo $(pwd)/bare/worktrees/goozy && + echo $(pwd)/bare/worktrees/goozy-651 && echo $(pwd)/goozy } >hook.expect && post_checkout_hook bare && - git -C bare worktree add --detach ../goozy && + GIT_TEST_WORKTREE_SUFFIX="651" git -C bare worktree add --detach ../goozy && test_cmp hook.expect goozy/hook.actual ' @@ -1165,8 +1165,9 @@ test_expect_success '"add" not tripped up by magic worktree matching"' ' ' test_expect_success FUNNYNAMES 'sanitize generated worktree name' ' - git worktree add --detach ". weird*..?.lock.lock" && - test -d .git/worktrees/---weird-.- + GIT_TEST_WORKTREE_SUFFIX="1234" \ + git worktree add --detach ". weird*..?.lock.lock" && + test -d .git/worktrees/---weird-.--1234 ' test_expect_success '"add" should not fail because of another bad worktree' ' @@ -1210,23 +1211,23 @@ test_expect_success '"add" with initialized submodule, with submodule.recurse se test_expect_success 'can create worktrees with relative paths' ' test_when_finished "git worktree remove relative" && test_config worktree.useRelativePaths false && - git worktree add --relative-paths ./relative && - echo "gitdir: ../.git/worktrees/relative" >expect && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add --relative-paths ./relative && + echo "gitdir: ../.git/worktrees/relative-123" >expect && test_cmp expect relative/.git && echo "../../../relative/.git" >expect && - test_cmp expect .git/worktrees/relative/gitdir + test_cmp expect .git/worktrees/relative-123/gitdir ' test_expect_success 'can create worktrees with absolute paths' ' test_config worktree.useRelativePaths true && - git worktree add ./relative && - echo "gitdir: ../.git/worktrees/relative" >expect && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add ./relative && + echo "gitdir: ../.git/worktrees/relative-123" >expect && test_cmp expect relative/.git && - git worktree add --no-relative-paths ./absolute && - echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect && + GIT_TEST_WORKTREE_SUFFIX=456 git worktree add --no-relative-paths ./absolute && + echo "gitdir: $(pwd)/.git/worktrees/absolute-456" >expect && test_cmp expect absolute/.git && echo "$(pwd)/absolute/.git" >expect && - test_cmp expect .git/worktrees/absolute/gitdir + test_cmp expect .git/worktrees/absolute-456/gitdir ' test_expect_success 'move repo without breaking relative internal links' ' diff --git a/t/t2401-worktree-prune.sh b/t/t2401-worktree-prune.sh index 5eb52b9abbf29514dc082c260ebb7a5e8e63aae0..856fcdd19d376d3448ee0be46592fe68d44617c4 100755 --- a/t/t2401-worktree-prune.sh +++ b/t/t2401-worktree-prune.sh @@ -83,29 +83,29 @@ test_expect_success 'not prune locked checkout' ' test_expect_success 'not prune recent checkouts' ' test_when_finished rm -r .git/worktrees && git worktree add jlm HEAD && - test -d .git/worktrees/jlm && + test -d .git/worktrees/jlm-* && rm -rf jlm && git worktree prune --verbose --expire=2.days.ago && - test -d .git/worktrees/jlm + test -d .git/worktrees/jlm-* ' test_expect_success 'not prune proper checkouts' ' test_when_finished rm -r .git/worktrees && git worktree add --detach "$PWD/nop" main && git worktree prune && - test -d .git/worktrees/nop + test -d .git/worktrees/nop-* ' test_expect_success 'prune duplicate (linked/linked)' ' test_when_finished rm -fr .git/worktrees w1 w2 && - git worktree add --detach w1 && - git worktree add --detach w2 && - sed "s/w2/w1/" .git/worktrees/w2/gitdir >.git/worktrees/w2/gitdir.new && - mv .git/worktrees/w2/gitdir.new .git/worktrees/w2/gitdir && + GIT_TEST_WORKTREE_SUFFIX=1 git worktree add --detach w1 && + GIT_TEST_WORKTREE_SUFFIX=2 git worktree add --detach w2 && + sed "s/w2/w1/" .git/worktrees/w2-2/gitdir >.git/worktrees/w2-2/gitdir.new && + mv .git/worktrees/w2-2/gitdir.new .git/worktrees/w2-2/gitdir && git worktree prune --verbose 2>actual && test_grep "duplicate entry" actual && - test -d .git/worktrees/w1 && - ! test -d .git/worktrees/w2 + test -d .git/worktrees/w1-1 && + ! test -d .git/worktrees/w2-2 ' test_expect_success 'prune duplicate (main/linked)' ' @@ -117,7 +117,7 @@ test_expect_success 'prune duplicate (main/linked)' ' mv repo wt && git -C wt worktree prune --verbose 2>actual && test_grep "duplicate entry" actual && - ! test -d .git/worktrees/wt + ! test -d .git/worktrees/wt-* ' test_expect_success 'not prune proper worktrees inside linked worktree with relative paths' ' diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh index 422c1a05580057b18ab8bfdfe38da4d723749493..ba3f05c16a4969fb84d98052ae375ef162f3e73a 100755 --- a/t/t2403-worktree-move.sh +++ b/t/t2403-worktree-move.sh @@ -24,27 +24,27 @@ test_expect_success 'lock main worktree' ' test_expect_success 'lock linked worktree' ' git worktree lock --reason hahaha source && echo hahaha >expected && - test_cmp expected .git/worktrees/source/locked + test_cmp expected .git/worktrees/source-*/locked ' test_expect_success 'lock linked worktree from another worktree' ' - rm .git/worktrees/source/locked && + rm .git/worktrees/source-*/locked && git worktree add elsewhere && git -C elsewhere worktree lock --reason hahaha ../source && echo hahaha >expected && - test_cmp expected .git/worktrees/source/locked + test_cmp expected .git/worktrees/source-*/locked ' test_expect_success 'lock worktree twice' ' test_must_fail git worktree lock source && echo hahaha >expected && - test_cmp expected .git/worktrees/source/locked + test_cmp expected .git/worktrees/source-*/locked ' test_expect_success 'lock worktree twice (from the locked worktree)' ' test_must_fail git -C source worktree lock . && echo hahaha >expected && - test_cmp expected .git/worktrees/source/locked + test_cmp expected .git/worktrees/source-*/locked ' test_expect_success 'unlock main worktree' ' @@ -183,19 +183,19 @@ test_expect_success 'force remove worktree with untracked file' ' test_expect_success 'remove missing worktree' ' git worktree add to-be-gone && - test -d .git/worktrees/to-be-gone && + test -d .git/worktrees/to-be-gone-* && mv to-be-gone gone && git worktree remove to-be-gone && - test_path_is_missing .git/worktrees/to-be-gone + test_path_is_missing .git/worktrees/to-be-gone-* ' test_expect_success 'NOT remove missing-but-locked worktree' ' git worktree add gone-but-locked && git worktree lock gone-but-locked && - test -d .git/worktrees/gone-but-locked && + test -d .git/worktrees/gone-but-locked-* && mv gone-but-locked really-gone-now && test_must_fail git worktree remove gone-but-locked && - test_path_is_dir .git/worktrees/gone-but-locked + test_path_is_dir .git/worktrees/gone-but-locked-* ' test_expect_success 'proper error when worktree not found' ' @@ -249,27 +249,27 @@ test_expect_success 'not remove a repo with initialized submodule' ' test_expect_success 'move worktree with absolute path to relative path' ' test_config worktree.useRelativePaths false && - git worktree add ./absolute && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add ./absolute && git worktree move --relative-paths absolute relative && - echo "gitdir: ../.git/worktrees/absolute" >expect && + echo "gitdir: ../.git/worktrees/absolute-123" >expect && test_cmp expect relative/.git && echo "../../../relative/.git" >expect && - test_cmp expect .git/worktrees/absolute/gitdir && + test_cmp expect .git/worktrees/absolute-123/gitdir && test_config worktree.useRelativePaths true && git worktree move relative relative2 && - echo "gitdir: ../.git/worktrees/absolute" >expect && + echo "gitdir: ../.git/worktrees/absolute-123" >expect && test_cmp expect relative2/.git && echo "../../../relative2/.git" >expect && - test_cmp expect .git/worktrees/absolute/gitdir + test_cmp expect .git/worktrees/absolute-123/gitdir ' test_expect_success 'move worktree with relative path to absolute path' ' test_config worktree.useRelativePaths true && git worktree move --no-relative-paths relative2 absolute && - echo "gitdir: $(pwd)/.git/worktrees/absolute" >expect && + echo "gitdir: $(pwd)/.git/worktrees/absolute-123" >expect && test_cmp expect absolute/.git && echo "$(pwd)/absolute/.git" >expect && - test_cmp expect .git/worktrees/absolute/gitdir + test_cmp expect .git/worktrees/absolute-123/gitdir ' test_done diff --git a/t/t2405-worktree-submodule.sh b/t/t2405-worktree-submodule.sh index 1d7f60563387f9c2f53dfc3a79ac0289afe57611..5479b2a74aa0d9b1e8880ed7c038307ffa1d0c54 100755 --- a/t/t2405-worktree-submodule.sh +++ b/t/t2405-worktree-submodule.sh @@ -9,6 +9,7 @@ TEST_PASSES_SANITIZE_LEAK=true . ./test-lib.sh base_path=$(pwd -P) +suffix=4567 test_expect_success 'setup: create origin repos' ' git config --global protocol.file.allow always && @@ -61,9 +62,10 @@ test_expect_success 'submodule is checked out after manually adding submodule wo ' test_expect_success 'checkout --recurse-submodules uses $GIT_DIR for submodules in a linked worktree' ' - git -C main worktree add "$base_path/checkout-recurse" --detach && + GIT_TEST_WORKTREE_SUFFIX=$suffix \ + git -C main worktree add "$base_path/checkout-recurse" --detach && git -C checkout-recurse submodule update --init && - echo "gitdir: ../../main/.git/worktrees/checkout-recurse/modules/sub" >expect-gitfile && + echo "gitdir: ../../main/.git/worktrees/checkout-recurse-$suffix/modules/sub" >expect-gitfile && cat checkout-recurse/sub/.git >actual-gitfile && test_cmp expect-gitfile actual-gitfile && git -C main/sub rev-parse HEAD >expect-head-main && @@ -82,14 +84,14 @@ test_expect_success 'core.worktree is removed in $GIT_DIR/modules//config, git -C checkout-recurse/sub config --get core.worktree >actual-linked && test_cmp expect-linked actual-linked && git -C checkout-recurse checkout --recurse-submodules first && - test_expect_code 1 git -C main/.git/worktrees/checkout-recurse/modules/sub config --get core.worktree >linked-config && + test_expect_code 1 git -C main/.git/worktrees/checkout-recurse-$suffix/modules/sub config --get core.worktree >linked-config && test_must_be_empty linked-config && git -C main/sub config --get core.worktree >actual-main && test_cmp expect-main actual-main ' test_expect_success 'unsetting core.worktree does not prevent running commands directly against the submodule repository' ' - git -C main/.git/worktrees/checkout-recurse/modules/sub log + git -C main/.git/worktrees/checkout-recurse-$suffix/modules/sub log ' test_done diff --git a/t/t2406-worktree-repair.sh b/t/t2406-worktree-repair.sh index 49b70b999518d47e1edd72a61a847b427f4c67a1..49d020f5fe786014ddc428bcb74cb706f8cef3d1 100755 --- a/t/t2406-worktree-repair.sh +++ b/t/t2406-worktree-repair.sh @@ -106,8 +106,8 @@ test_expect_success 'repo not found; .git not file' ' test_expect_success 'repo not found; .git not referencing repo' ' test_when_finished "rm -rf side not-a-repo && git worktree prune" && - git worktree add --detach side && - sed s,\.git/worktrees/side$,not-a-repo, side/.git >side/.newgit && + GIT_TEST_WORKTREE_SUFFIX=1234 git worktree add --detach side && + sed s,\.git/worktrees/side-1234$,not-a-repo, side/.git >side/.newgit && mv side/.newgit side/.git && mkdir not-a-repo && test_must_fail git worktree repair side 2>err && @@ -127,41 +127,41 @@ test_expect_success 'repo not found; .git file broken' ' test_expect_success 'repair broken gitdir' ' test_when_finished "rm -rf orig moved && git worktree prune" && git worktree add --detach orig && - sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect && - rm .git/worktrees/orig/gitdir && + sed s,orig/\.git$,moved/.git, .git/worktrees/orig-*/gitdir >expect && + rm .git/worktrees/orig-*/gitdir && mv orig moved && git worktree repair moved 2>err && - test_cmp expect .git/worktrees/orig/gitdir && + test_cmp expect .git/worktrees/orig-*/gitdir && test_grep "gitdir unreadable" err ' test_expect_success 'repair incorrect gitdir' ' test_when_finished "rm -rf orig moved && git worktree prune" && git worktree add --detach orig && - sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect && + sed s,orig/\.git$,moved/.git, .git/worktrees/orig-*/gitdir >expect && mv orig moved && git worktree repair moved 2>err && - test_cmp expect .git/worktrees/orig/gitdir && + test_cmp expect .git/worktrees/orig-*/gitdir && test_grep "gitdir incorrect" err ' test_expect_success 'repair gitdir (implicit) from linked worktree' ' test_when_finished "rm -rf orig moved && git worktree prune" && git worktree add --detach orig && - sed s,orig/\.git$,moved/.git, .git/worktrees/orig/gitdir >expect && + sed s,orig/\.git$,moved/.git, .git/worktrees/orig-*/gitdir >expect && mv orig moved && git -C moved worktree repair 2>err && - test_cmp expect .git/worktrees/orig/gitdir && + test_cmp expect .git/worktrees/orig-*/gitdir && test_grep "gitdir incorrect" err ' test_expect_success 'unable to repair gitdir (implicit) from main worktree' ' test_when_finished "rm -rf orig moved && git worktree prune" && git worktree add --detach orig && - cat .git/worktrees/orig/gitdir >expect && + cat .git/worktrees/orig-*/gitdir >expect && mv orig moved && git worktree repair 2>err && - test_cmp expect .git/worktrees/orig/gitdir && + test_cmp expect .git/worktrees/orig-*/gitdir && test_must_be_empty err ' @@ -170,15 +170,15 @@ test_expect_success 'repair multiple gitdir files' ' git worktree prune" && git worktree add --detach orig1 && git worktree add --detach orig2 && - sed s,orig1/\.git$,moved1/.git, .git/worktrees/orig1/gitdir >expect1 && - sed s,orig2/\.git$,moved2/.git, .git/worktrees/orig2/gitdir >expect2 && + sed s,orig1/\.git$,moved1/.git, .git/worktrees/orig1-*/gitdir >expect1 && + sed s,orig2/\.git$,moved2/.git, .git/worktrees/orig2-*/gitdir >expect2 && mv orig1 moved1 && mv orig2 moved2 && git worktree repair moved1 moved2 2>err && - test_cmp expect1 .git/worktrees/orig1/gitdir && - test_cmp expect2 .git/worktrees/orig2/gitdir && - test_grep "gitdir incorrect:.*orig1/gitdir$" err && - test_grep "gitdir incorrect:.*orig2/gitdir$" err + test_cmp expect1 .git/worktrees/orig1-*/gitdir && + test_cmp expect2 .git/worktrees/orig2-*/gitdir && + test_grep "gitdir incorrect:.*orig1-.*/gitdir$" err && + test_grep "gitdir incorrect:.*orig2-.*/gitdir$" err ' test_expect_success 'repair moved main and linked worktrees' ' @@ -186,14 +186,12 @@ test_expect_success 'repair moved main and linked worktrees' ' test_create_repo main && test_commit -C main init && git -C main worktree add --detach ../side && - sed "s,side/\.git$,sidemoved/.git," \ - main/.git/worktrees/side/gitdir >expect-gitdir && - sed "s,main/.git/worktrees/side$,mainmoved/.git/worktrees/side," \ - side/.git >expect-gitfile && + sed "s,side,sidemoved," main/.git/worktrees/side-*/gitdir >expect-gitdir && + sed "s,main,mainmoved," side/.git >expect-gitfile && mv main mainmoved && mv side sidemoved && git -C mainmoved worktree repair ../sidemoved && - test_cmp expect-gitdir mainmoved/.git/worktrees/side/gitdir && + test_cmp expect-gitdir mainmoved/.git/worktrees/side-*/gitdir && test_cmp expect-gitfile sidemoved/.git ' @@ -203,16 +201,15 @@ test_expect_success 'repair copied main and linked worktrees' ' git -C orig init main && test_commit -C orig/main nothing && git -C orig/main worktree add ../linked && - cp orig/main/.git/worktrees/linked/gitdir orig/main.expect && + cp orig/main/.git/worktrees/linked-*/gitdir orig/main.expect && cp orig/linked/.git orig/linked.expect && cp -R orig dup && sed "s,orig/linked/\.git$,dup/linked/.git," orig/main.expect >dup/main.expect && - sed "s,orig/main/\.git/worktrees/linked$,dup/main/.git/worktrees/linked," \ - orig/linked.expect >dup/linked.expect && + sed "s,orig,dup," orig/linked.expect >dup/linked.expect && git -C dup/main worktree repair ../linked && - test_cmp orig/main.expect orig/main/.git/worktrees/linked/gitdir && + test_cmp orig/main.expect orig/main/.git/worktrees/linked-*/gitdir && test_cmp orig/linked.expect orig/linked/.git && - test_cmp dup/main.expect dup/main/.git/worktrees/linked/gitdir && + test_cmp dup/main.expect dup/main/.git/worktrees/linked-*/gitdir && test_cmp dup/linked.expect dup/linked/.git ' @@ -221,11 +218,11 @@ test_expect_success 'repair worktree with relative path with missing gitfile' ' test_create_repo main && git -C main config worktree.useRelativePaths true && test_commit -C main init && - git -C main worktree add --detach ../wt && + GIT_TEST_WORKTREE_SUFFIX=123 git -C main worktree add --detach ../wt && rm wt/.git && test_path_is_missing wt/.git && git -C main worktree repair && - echo "gitdir: ../main/.git/worktrees/wt" >expect && + echo "gitdir: ../main/.git/worktrees/wt-123" >expect && test_cmp expect wt/.git ' @@ -233,12 +230,12 @@ test_expect_success 'repair absolute worktree to use relative paths' ' test_when_finished "rm -rf main side sidemoved" && test_create_repo main && test_commit -C main init && - git -C main worktree add --detach ../side && + GIT_TEST_WORKTREE_SUFFIX=456 git -C main worktree add --detach ../side && echo "../../../../sidemoved/.git" >expect-gitdir && - echo "gitdir: ../main/.git/worktrees/side" >expect-gitfile && + echo "gitdir: ../main/.git/worktrees/side-456" >expect-gitfile && mv side sidemoved && git -C main worktree repair --relative-paths ../sidemoved && - test_cmp expect-gitdir main/.git/worktrees/side/gitdir && + test_cmp expect-gitdir main/.git/worktrees/side-456/gitdir && test_cmp expect-gitfile sidemoved/.git ' @@ -246,13 +243,39 @@ test_expect_success 'repair relative worktree to use absolute paths' ' test_when_finished "rm -rf main side sidemoved" && test_create_repo main && test_commit -C main init && - git -C main worktree add --relative-paths --detach ../side && + GIT_TEST_WORKTREE_SUFFIX=789 git -C main worktree add --relative-paths --detach ../side && echo "$(pwd)/sidemoved/.git" >expect-gitdir && - echo "gitdir: $(pwd)/main/.git/worktrees/side" >expect-gitfile && + echo "gitdir: $(pwd)/main/.git/worktrees/side-789" >expect-gitfile && mv side sidemoved && git -C main worktree repair ../sidemoved && - test_cmp expect-gitdir main/.git/worktrees/side/gitdir && + test_cmp expect-gitdir main/.git/worktrees/side-789/gitdir && test_cmp expect-gitfile sidemoved/.git ' +test_expect_success 'does not repair worktrees from another repo' ' + test_when_finished "rm -rf repo1 repo2" && + mkdir -p repo1 && + git -C repo1 init main && + test_commit -C repo1/main nothing && + git -C repo1/main worktree add ../linked && + cp repo1/main/.git/worktrees/linked-*/gitdir repo1/main.expect && + cp repo1/linked/.git repo1/linked.expect && + mkdir -p repo2 && + git -C repo2 init main && + test_commit -C repo2/main nothing && + git -C repo2/main worktree add ../linked && + cp repo2/main/.git/worktrees/linked-*/gitdir repo2/main.expect && + cp repo2/linked/.git repo2/linked.expect && + git -C repo1/main worktree repair ../../repo2/linked && + test_cmp repo1/main.expect repo1/main/.git/worktrees/linked-*/gitdir && + test_cmp repo1/linked.expect repo1/linked/.git && + test_cmp repo2/main.expect repo2/main/.git/worktrees/linked-*/gitdir && + test_cmp repo2/linked.expect repo2/linked/.git && + git -C repo2/main worktree repair ../../repo1/linked && + test_cmp repo1/main.expect repo1/main/.git/worktrees/linked-*/gitdir && + test_cmp repo1/linked.expect repo1/linked/.git && + test_cmp repo2/main.expect repo2/main/.git/worktrees/linked-*/gitdir && + test_cmp repo2/linked.expect repo2/linked/.git +' + test_done diff --git a/t/t2407-worktree-heads.sh b/t/t2407-worktree-heads.sh index f6835c91dcc49cfeb23881fe0ef7a96629bfb2e6..1587dadfd1e1fa122edccc62ffd9aa4c20f0ec80 100755 --- a/t/t2407-worktree-heads.sh +++ b/t/t2407-worktree-heads.sh @@ -19,7 +19,8 @@ test_expect_success 'setup' ' test_commit $i && git branch wt-$i && git branch fake-$i && - git worktree add wt-$i wt-$i || return 1 + GIT_TEST_WORKTREE_SUFFIX=$i \ + git worktree add wt-$i wt-$i || return 1 done && # Create a server that updates each branch by one commit @@ -132,20 +133,20 @@ test_expect_success 'refuse to overwrite when in error states' ' test_when_finished rm -rf .git/worktrees/wt-*/BISECT_* && # Both branches are currently under rebase. - mkdir -p .git/worktrees/wt-3/rebase-merge && - touch .git/worktrees/wt-3/rebase-merge/interactive && - echo refs/heads/fake-1 >.git/worktrees/wt-3/rebase-merge/head-name && - echo refs/heads/fake-2 >.git/worktrees/wt-3/rebase-merge/onto && - mkdir -p .git/worktrees/wt-4/rebase-merge && - touch .git/worktrees/wt-4/rebase-merge/interactive && - echo refs/heads/fake-2 >.git/worktrees/wt-4/rebase-merge/head-name && - echo refs/heads/fake-1 >.git/worktrees/wt-4/rebase-merge/onto && + mkdir -p .git/worktrees/wt-3-3/rebase-merge && + touch .git/worktrees/wt-3-3/rebase-merge/interactive && + echo refs/heads/fake-1 >.git/worktrees/wt-3-3/rebase-merge/head-name && + echo refs/heads/fake-2 >.git/worktrees/wt-3-3/rebase-merge/onto && + mkdir -p .git/worktrees/wt-4-4/rebase-merge && + touch .git/worktrees/wt-4-4/rebase-merge/interactive && + echo refs/heads/fake-2 >.git/worktrees/wt-4-4/rebase-merge/head-name && + echo refs/heads/fake-1 >.git/worktrees/wt-4-4/rebase-merge/onto && # Both branches are currently under bisect. - touch .git/worktrees/wt-4/BISECT_LOG && - echo refs/heads/fake-2 >.git/worktrees/wt-4/BISECT_START && - touch .git/worktrees/wt-1/BISECT_LOG && - echo refs/heads/fake-1 >.git/worktrees/wt-1/BISECT_START && + touch .git/worktrees/wt-4-4/BISECT_LOG && + echo refs/heads/fake-2 >.git/worktrees/wt-4-4/BISECT_START && + touch .git/worktrees/wt-1-1/BISECT_LOG && + echo refs/heads/fake-1 >.git/worktrees/wt-1-1/BISECT_START && for i in 1 2 do diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index ccfa6a720d090c2f7f2a085f60065bdcfaf8d1d9..e44497ac94394119662115b1f6aa035c7f0565d2 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -246,14 +246,14 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou ' test_expect_success REFFILES 'git branch -M fails if updating any linked working tree fails' ' - git worktree add -b baz bazdir1 && - git worktree add -f bazdir2 baz && - touch .git/worktrees/bazdir1/HEAD.lock && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add -b baz bazdir1 && + GIT_TEST_WORKTREE_SUFFIX=456 git worktree add -f bazdir2 baz && + touch .git/worktrees/bazdir1-123/HEAD.lock && test_must_fail git branch -M baz bam && test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam && git branch -M bam baz && - rm .git/worktrees/bazdir1/HEAD.lock && - touch .git/worktrees/bazdir2/HEAD.lock && + rm .git/worktrees/bazdir1-123/HEAD.lock && + touch .git/worktrees/bazdir2-456/HEAD.lock && test_must_fail git branch -M baz bam && test $(git -C bazdir1 rev-parse --abbrev-ref HEAD) = bam && rm -rf bazdir1 bazdir2 && diff --git a/t/t5304-prune.sh b/t/t5304-prune.sh index e641df0116c24404e4892a0e30af4ef4bf8db493..0e98c6627a98ed197d7ab1ff41e8dd41eeaff3ac 100755 --- a/t/t5304-prune.sh +++ b/t/t5304-prune.sh @@ -293,7 +293,7 @@ test_expect_success 'prune: handle HEAD in multiple worktrees' ' echo "new blob for third-worktree" >third-worktree/blob && git -C third-worktree add blob && git -C third-worktree commit -m "third" && - rm .git/worktrees/third-worktree/index && + rm .git/worktrees/third-worktree-*/index && test_must_fail git -C third-worktree show :blob && git prune --expire=now && git -C third-worktree show HEAD:blob >actual && diff --git a/t/t7412-submodule-absorbgitdirs.sh b/t/t7412-submodule-absorbgitdirs.sh index f77832185765585e2bda1677f8cbbe13841127f7..acf9544e35966f054cbc90c37e84377c9f461f2b 100755 --- a/t/t7412-submodule-absorbgitdirs.sh +++ b/t/t7412-submodule-absorbgitdirs.sh @@ -123,7 +123,7 @@ test_expect_success 'absorb the git dir outside of primary worktree' ' test_when_finished "rm -rf repo-bare.git" && git clone --bare . repo-bare.git && test_when_finished "rm -rf repo-wt" && - git -C repo-bare.git worktree add ../repo-wt && + GIT_TEST_WORKTREE_SUFFIX=123 git -C repo-bare.git worktree add ../repo-wt && test_when_finished "rm -f .gitconfig" && test_config_global protocol.file.allow always && @@ -134,7 +134,7 @@ test_expect_success 'absorb the git dir outside of primary worktree' ' cat >expect <<-EOF && Migrating git directory of '\''sub2'\'' from '\''$cwd/repo-wt/sub2/.git'\'' to - '\''$cwd/repo-bare.git/worktrees/repo-wt/modules/sub2'\'' + '\''$cwd/repo-bare.git/worktrees/repo-wt-123/modules/sub2'\'' EOF git -C repo-wt submodule absorbgitdirs 2>actual && test_cmp expect actual From patchwork Fri Nov 29 22:37:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Caleb White X-Patchwork-Id: 13888970 Received: from mail-10631.protonmail.ch (mail-10631.protonmail.ch [79.135.106.31]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AF0682C18C for ; Fri, 29 Nov 2024 22:37:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=79.135.106.31 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732919881; cv=none; b=nlHSpIeZ0W7piVzePgakKVIfXfEBilSAyAh5PcQ++tWIYJ81yX2L3sJH4r/vM2RR8FlIWhkmBLRDVWa+NptutCfRK2M3HQShMmDlKi6WW69p7v2xxnk6xwx2n+mlwi08D/ge920DlxA73ilB9njm94USVKKahGLJNqGJL2gQy2U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732919881; c=relaxed/simple; bh=XosmYGWpRFTfxFVhYW/BvHcV9VWZYdiGax4AQq/3gEM=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=gKU1uJpPeWY0rElNzN320se4sfdW24LYbBmf+hFOebGsnDXIrI7Kl2ORMxMfJ69ew96M2maj/FzVrj55Am1uWeC+Fsy4UbX/vKo06WWxCMwLc2GM1IMnUz4l1/fxdJrU3Y2CsVjJ267uQICmo+fR2wA84yc6gUKOBDmvaPr5p6c= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=VnvLUc40; arc=none smtp.client-ip=79.135.106.31 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="VnvLUc40" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1732919877; x=1733179077; bh=8QUv9cFqo87UgTka1v+K4DTZdyX6hHsXOyESzd7rQa4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=VnvLUc40nceRKBR9x/+FmM0yfUo5tOgXR1Q81Ed/+47dAgXwyTAODida+xclOEnFm 2soPRfS95MuHt0xC26NQVE2X8WSdz59EtPXuSPx7ek2dqN0fJXh5Pu57++oPbxSiS0 6TT32BtOsGBcplrzfNNZa5+OMfyyccMJn3W8VqoNO+2TnXjO21kjkYAAaoBUniVNQ5 5SOTg9vTcyr6Z/4vSeoOpSwMeSv032ozBbdJrgG3aNvRJY0sTjPOxgw2waJbtahISG 2w1MBDMX9E1Q0+6PkEdooAu3plY/XRbBiSyKVa1UAVS2pa3JD05Hp6K513J3Ssg2ky WmDlPCeDg2PGA== Date: Fri, 29 Nov 2024 22:37:51 +0000 To: git@vger.kernel.org From: Caleb White Cc: shejialuo , Junio C Hamano , Caleb White Subject: [PATCH v2 2/3] worktree: rename worktree id during worktree move Message-ID: <20241129-wt_unique_ids-v2-2-ff444e9e625a@pm.me> In-Reply-To: <20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me> References: <20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me> Feedback-ID: 31210263:user:proton X-Pm-Message-ID: c0a7c69c3568c063768a2952233dd1d6703bac12 Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 During a `worktree move` the worktree directory is moved/renamed but the repository under `worktrees/` is not updated. For example, given the following structure: foo/ ├── .git/worktrees/develop-5445874156/ └── develop/ moving `develop` to `master` results in foo/ ├── .git/worktrees/develop-5445874156/ └── master/ This works because the linking files still point to the correct repository, but this is a little weird. This teaches Git to also move/rename the repository / worktree id during a `move` so that the structure now looks like: foo/ ├── .git/worktrees/master-1565465986/ └── master/ Note that a new unique suffix is assigned to reduce the complexity of trying to parse and reuse the existing suffix. Signed-off-by: Caleb White --- builtin/worktree.c | 24 ++++++++++++++++++++++++ t/t2403-worktree-move.sh | 18 +++++++++--------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/builtin/worktree.c b/builtin/worktree.c index 3ad355ca762729401fc0c8625f4fd05b154a84ec..36235546b492803707707ff208b13fe777bff1b4 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -1202,9 +1202,14 @@ static int move_worktree(int ac, const char **av, const char *prefix) }; struct worktree **worktrees, *wt; struct strbuf dst = STRBUF_INIT; + struct strbuf repo = STRBUF_INIT; + struct strbuf repo_dst = STRBUF_INIT; struct strbuf errmsg = STRBUF_INIT; const char *reason = NULL; + const char *new_id; + const char *suffix; char *path; + int len; ac = parse_options(ac, av, prefix, options, git_worktree_move_usage, 0); @@ -1250,9 +1255,28 @@ static int move_worktree(int ac, const char **av, const char *prefix) if (rename(wt->path, dst.buf) == -1) die_errno(_("failed to move '%s' to '%s'"), wt->path, dst.buf); + strbuf_realpath(&repo, git_common_path("worktrees/%s", wt->id), 1); + new_id = worktree_basename(dst.buf, &len); + strbuf_add(&repo_dst, new_id, dst.buf + len - new_id); + strbuf_realpath(&repo_dst, git_common_path("worktrees/%s", repo_dst.buf), 1); + suffix = getenv("GIT_TEST_WORKTREE_SUFFIX"); + if (suffix) + strbuf_addf(&repo_dst, "-%s", suffix); + else + strbuf_addf(&repo_dst, "-%u", git_rand()); + new_id = strrchr(repo_dst.buf, '/') + 1; + if (rename(repo.buf, repo_dst.buf) == -1) + die_errno(_("failed to move '%s' to '%s'"), repo.buf, repo_dst.buf); + else { + free(wt->id); + wt->id = xstrdup(new_id); + } + update_worktree_location(wt, dst.buf, use_relative_paths); strbuf_release(&dst); + strbuf_release(&repo); + strbuf_release(&repo_dst); free_worktrees(worktrees); return 0; } diff --git a/t/t2403-worktree-move.sh b/t/t2403-worktree-move.sh index ba3f05c16a4969fb84d98052ae375ef162f3e73a..703aa58d10643e99ffaf803aa38dabfd4af68a10 100755 --- a/t/t2403-worktree-move.sh +++ b/t/t2403-worktree-move.sh @@ -250,26 +250,26 @@ test_expect_success 'not remove a repo with initialized submodule' ' test_expect_success 'move worktree with absolute path to relative path' ' test_config worktree.useRelativePaths false && GIT_TEST_WORKTREE_SUFFIX=123 git worktree add ./absolute && - git worktree move --relative-paths absolute relative && - echo "gitdir: ../.git/worktrees/absolute-123" >expect && + GIT_TEST_WORKTREE_SUFFIX=456 git worktree move --relative-paths absolute relative && + echo "gitdir: ../.git/worktrees/relative-456" >expect && test_cmp expect relative/.git && echo "../../../relative/.git" >expect && - test_cmp expect .git/worktrees/absolute-123/gitdir && + test_cmp expect .git/worktrees/relative-456/gitdir && test_config worktree.useRelativePaths true && - git worktree move relative relative2 && - echo "gitdir: ../.git/worktrees/absolute-123" >expect && + GIT_TEST_WORKTREE_SUFFIX=789 git worktree move relative relative2 && + echo "gitdir: ../.git/worktrees/relative2-789" >expect && test_cmp expect relative2/.git && echo "../../../relative2/.git" >expect && - test_cmp expect .git/worktrees/absolute-123/gitdir + test_cmp expect .git/worktrees/relative2-789/gitdir ' test_expect_success 'move worktree with relative path to absolute path' ' test_config worktree.useRelativePaths true && - git worktree move --no-relative-paths relative2 absolute && - echo "gitdir: $(pwd)/.git/worktrees/absolute-123" >expect && + GIT_TEST_WORKTREE_SUFFIX=851 git worktree move --no-relative-paths relative2 absolute && + echo "gitdir: $(pwd)/.git/worktrees/absolute-851" >expect && test_cmp expect absolute/.git && echo "$(pwd)/absolute/.git" >expect && - test_cmp expect .git/worktrees/absolute-123/gitdir + test_cmp expect .git/worktrees/absolute-851/gitdir ' test_done From patchwork Fri Nov 29 22:37:58 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Caleb White X-Patchwork-Id: 13888971 Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ED7992C18C for ; Fri, 29 Nov 2024 22:38:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=185.70.40.134 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732919886; cv=none; b=JyD0styweLH97NQfViq0MpZF29ByoZN6kBSMvz0sULVYt8E8b5W1yQHAlAV6LxkxWHi88u8r9GIlGLgF3Nh2+rGiTYcXAu6nJSHLxT2BV4Jpgy49fZVZyTVoOz7TI88c4LficRfUqLCJZ2zi+AWjgNh/GPQ2cfHRAPR+JSRjvZ8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732919886; c=relaxed/simple; bh=B7yvsjPNXNoywY1zU+QmwNFbdu92ulkFLxCE6vynUC0=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=PSaLL0JscOJzXzA4GG+TROx4qO06uXMWyj/zdtFsZy5SIHK+4QQ7L5Zcivp8PZ9+b0fgEBs/ODMF2zFh3bAirP6Yox8ljGt55g5zNvPwYVPp8BszvUdCsGEFUaz0l7iFJtl3VnaPkz3qV+xh4xeO8+EI16TsXm+df7X7SBYCxgg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me; spf=pass smtp.mailfrom=pm.me; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b=r1rJdNxB; arc=none smtp.client-ip=185.70.40.134 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=pm.me Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pm.me Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=pm.me header.i=@pm.me header.b="r1rJdNxB" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pm.me; s=protonmail3; t=1732919882; x=1733179082; bh=zWeNkm7Zp2ZvlD6HD/Bhwwm7R8pxWL267YdcOUQZSnU=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector:List-Unsubscribe:List-Unsubscribe-Post; b=r1rJdNxB71fWXWQmIrYgsG+dDbdv74/0D59g6n5KUwRpd11SRfRb5o4oG9Ln//KqE NQFNrvjanPrRbr0ANqF1rTMA8Sb+89ltWMVhB0ZUvdMOci7/iiqnfagheU/VKwMV2G XSgyO22fjSRL0ci4USFuwgZTaOQmIoKsi/WUKkYgDpErzZfHUMzpBe1WPaFYdSb0e2 NR4ng2EKGiEJ3sCsYpXlQtfxPkpRyxlr2SBR6RbxaFyH3egxh307sVDL5b4ptEBjat LZzhWFmCruSnEvESPAxpy4n8EsR06s8rVB9yRWIn5PEvtr2Mit8PSoKt2MKaOWUrsR HHo5+B1RO0qlg== Date: Fri, 29 Nov 2024 22:37:58 +0000 To: git@vger.kernel.org From: Caleb White Cc: shejialuo , Junio C Hamano , Caleb White Subject: [PATCH v2 3/3] worktree: add id to `worktree list` output Message-ID: <20241129-wt_unique_ids-v2-3-ff444e9e625a@pm.me> In-Reply-To: <20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me> References: <20241129-wt_unique_ids-v2-0-ff444e9e625a@pm.me> Feedback-ID: 31210263:user:proton X-Pm-Message-ID: 7234c624f9f512ed7427214b01fbcfa99afa271e Precedence: bulk X-Mailing-List: git@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The worktree id is relatively hidden from the user, however, there may be times where a user or script needs to determine the worktree id for a linked worktree (e.g., to manually operate on some refs). While the id is stored in the worktree `.git` file, it would be nice if there was an easier method of obtaining it. This teaches Git to output the worktree id (for linked worktrees) in the `worktree list` verbose and porcelain modes. Signed-off-by: Caleb White --- Documentation/git-worktree.txt | 12 +++++++++++- builtin/worktree.c | 5 +++++ t/t2402-worktree-list.sh | 16 ++++++++++------ 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/Documentation/git-worktree.txt b/Documentation/git-worktree.txt index e0604b043361828f94b58f676a5ed4f15b116348..2bd8118852a97251fc1081d19ea9756428d190f4 100644 --- a/Documentation/git-worktree.txt +++ b/Documentation/git-worktree.txt @@ -428,16 +428,21 @@ $ git worktree list For these annotations, a reason might also be available and this can be seen using the verbose mode. The annotation is then moved to the next line -indented followed by the additional information. +indented followed by the additional information. In verbose mode, the worktree +id is also shown on the next line if available. ------------ $ git worktree list --verbose /path/to/linked-worktree abcd1234 [master] + id: linked-worktree-12345678 /path/to/locked-worktree-no-reason abcd5678 (detached HEAD) locked + id: locked-worktree-no-reason-89765464 /path/to/locked-worktree-with-reason 1234abcd (brancha) locked: worktree path is mounted on a portable device + id: locked-worktree-with-reason-41564654 /path/to/prunable-worktree 5678abc1 (detached HEAD) prunable: gitdir file points to non-existent location + id: prunable-worktree-98454651 ------------ Note that the annotation is moved to the next line if the additional @@ -461,24 +466,29 @@ worktree /path/to/bare-source bare worktree /path/to/linked-worktree +id linked-worktree-12345678 HEAD abcd1234abcd1234abcd1234abcd1234abcd1234 branch refs/heads/master worktree /path/to/other-linked-worktree +id other-linked-worktree-879456466 HEAD 1234abc1234abc1234abc1234abc1234abc1234a detached worktree /path/to/linked-worktree-locked-no-reason +id locked-worktree-no-reason-89765464 HEAD 5678abc5678abc5678abc5678abc5678abc5678c branch refs/heads/locked-no-reason locked worktree /path/to/linked-worktree-locked-with-reason +id locked-worktree-with-reason-41564654 HEAD 3456def3456def3456def3456def3456def3456b branch refs/heads/locked-with-reason locked reason why is locked worktree /path/to/linked-worktree-prunable +id prunable-worktree-98454651 HEAD 1233def1234def1234def1234def1234def1234b detached prunable gitdir file points to non-existent location diff --git a/builtin/worktree.c b/builtin/worktree.c index 36235546b492803707707ff208b13fe777bff1b4..fca8a9cda51643e434b5f8905e32e537c6b4418b 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -944,6 +944,8 @@ static void show_worktree_porcelain(struct worktree *wt, int line_terminator) const char *reason; printf("worktree %s%c", wt->path, line_terminator); + if (!is_main_worktree(wt)) + printf("id %s%c", wt->id, line_terminator); if (wt->is_bare) printf("bare%c", line_terminator); else { @@ -1009,6 +1011,9 @@ static void show_worktree(struct worktree *wt, int path_maxlen, int abbrev_len) else if (reason) strbuf_addstr(&sb, " prunable"); + if (verbose && !is_main_worktree(wt)) + strbuf_addf(&sb, "\n\tid: %s", wt->id); + printf("%s\n", sb.buf); strbuf_release(&sb); } diff --git a/t/t2402-worktree-list.sh b/t/t2402-worktree-list.sh index 780daa6cd6351f8fa9434619cc212aade8f01420..502d35cabb837121d178937673b580cd767d17aa 100755 --- a/t/t2402-worktree-list.sh +++ b/t/t2402-worktree-list.sh @@ -56,8 +56,9 @@ test_expect_success '"list" all worktrees --porcelain' ' echo "branch $(git symbolic-ref HEAD)" >>expect && echo >>expect && test_when_finished "rm -rf here actual expect && git worktree prune" && - git worktree add --detach here main && + GIT_TEST_WORKTREE_SUFFIX=123 git worktree add --detach here main && echo "worktree $(git -C here rev-parse --show-toplevel)" >>expect && + echo "id here-123" >>expect && echo "HEAD $(git rev-parse HEAD)" >>expect && echo "detached" >>expect && echo >>expect && @@ -71,9 +72,10 @@ test_expect_success '"list" all worktrees --porcelain -z' ' printf "worktree %sQHEAD %sQbranch %sQQ" \ "$(git rev-parse --show-toplevel)" \ $(git rev-parse HEAD --symbolic-full-name HEAD) >expect && - git worktree add --detach here main && - printf "worktree %sQHEAD %sQdetachedQQ" \ + GIT_TEST_WORKTREE_SUFFIX=456 git worktree add --detach here main && + printf "worktree %sQid %sQHEAD %sQdetachedQQ" \ "$(git -C here rev-parse --show-toplevel)" \ + "here-456" \ "$(git rev-parse HEAD)" >>expect && git worktree list --porcelain -z >_actual && nul_to_q <_actual >actual && @@ -166,16 +168,17 @@ test_expect_success '"list" --verbose and --porcelain mutually exclusive' ' test_expect_success '"list" all worktrees --verbose with locked' ' test_when_finished "rm -rf locked1 locked2 out actual expect && git worktree prune" && git worktree add locked1 --detach && - git worktree add locked2 --detach && + GIT_TEST_WORKTREE_SUFFIX=456 git worktree add locked2 --detach && git worktree lock locked1 && test_when_finished "git worktree unlock locked1" && git worktree lock locked2 --reason "with reason" && test_when_finished "git worktree unlock locked2" && echo "$(git -C locked2 rev-parse --show-toplevel) $(git rev-parse --short HEAD) (detached HEAD)" >expect && printf "\tlocked: with reason\n" >>expect && + printf "\tid: locked2-456\n" >>expect && git worktree list --verbose >out && grep "/locked1 *[0-9a-f].* locked$" out && - sed -n "s/ */ /g;/\/locked2 *[0-9a-f].*$/,/locked: .*$/p" actual && + sed -n "s/ */ /g;/\/locked2 *[0-9a-f].*$/,/id: .*$/p" actual && test_cmp actual expect ' @@ -211,11 +214,12 @@ test_expect_success '"list" all worktrees from bare main' ' test_expect_success '"list" all worktrees --porcelain from bare main' ' test_when_finished "rm -rf there actual expect && git -C bare1 worktree prune" && - git -C bare1 worktree add --detach ../there main && + GIT_TEST_WORKTREE_SUFFIX=456 git -C bare1 worktree add --detach ../there main && echo "worktree $(pwd)/bare1" >expect && echo "bare" >>expect && echo >>expect && echo "worktree $(git -C there rev-parse --show-toplevel)" >>expect && + echo "id there-456" >>expect && echo "HEAD $(git -C there rev-parse HEAD)" >>expect && echo "detached" >>expect && echo >>expect &&