{"thread":{"id":"50672","subject":"[BUG] worktree local refs weirdness","startedAt":"2019-03-06T15:57:25Z","lastAt":"2019-03-07T14:51:39Z","messageCount":11,"participants":["Phillip Wood","Duy Nguyen","Nguyễn Thái Ngọc Duy"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"370816","messageId":"f6e197f2-886a-5e82-7fc4-c53737dd66cc@gmail.com","threadId":"50672","inReplyTo":null,"subject":"[BUG] worktree local refs weirdness","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-06T15:57:18Z","receivedAt":"2019-03-06T15:57:25Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"When it is run in a worktree 'git for-each-ref' only seems to show refs \nunder refs/rewritten if that directory also exists under $GIT_COMMON_DIR \neven though they are local to the worktree.\n\nInitially I thought this was due to $GIT_COMMON_DIR pointing to a bare \nrepo, but that is not the case. However while writing a test case which \ncloned to a bare repo I noticed it was listing a ref for the HEAD of a \nworktree in the repo I had cloned from, not the clone itself.\n\nThe script below reproduces both issues, I've copied the output below \nit. I'm not sure what's going on or the best way to debug it.\n\nBest Wishes\n\nPhillip\n\n# setup initial repo\nmkdir repo &&\ncd repo &&\ngit init &&\necho a>a &&\ngit add a &&\ngit commit -ma &&\n#add a worktree and set a ref under refs/rewritten\ngit worktree add ../worktree-1 &&\ncd ../worktree-1 &&\necho 'worktree-1 adding refs/rewritten/a' &&\ngit update-ref refs/rewritten/a HEAD &&\ngit rev-parse --verify refs/rewritten/a &&\necho 'refs/rewritten/a exists but is not shown' &&\ngit for-each-ref &&\n# add a ref under refs/rewritten to the main repo\ncd ../repo &&\necho 'repo adding refs/rewritten/z' &&\ngit update-ref refs/rewritten/z HEAD &&\ngit for-each-ref &&\ncd ../worktree-1 &&\necho 'worktree-1 now shows refs/rewritten/a' &&\ngit for-each-ref &&\ncd .. &&\n# create a bare clone with a worktree\ngit clone --bare --no-local repo bare &&\ncd bare &&\ngit worktree add ../worktree-2 &&\ncd ../worktree-2 &&\necho 'worktree-2 adding refs/rewritten/b' &&\necho 'why does this show refs/worktree-1/head' &&\necho 'but not refs/rewritten/b?' &&\ngit worktree list &&\ngit update-ref refs/rewritten/b HEAD &&\ngit rev-parse --verify refs/rewritten/b &&\ngit for-each-ref\n\n\nOutput\nInitialized empty Git repository in \n/home/phil/src/git-utils/dev/git-rewrite/repo/.git/\n[master (root-commit) dc2045a] a\n  1 file changed, 1 insertion(+)\n  create mode 100644 a\nPreparing worktree (new branch 'worktree-1')\nHEAD is now at dc2045a a\nworktree-1 adding refs/rewritten/a\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656\nrefs/rewritten/a exists but is not shown\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/master\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/worktree-1\nrepo adding refs/rewritten/z\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/master\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/worktree-1\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/rewritten/z\nworktree-1 now shows refs/rewritten/a\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/master\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/worktree-1\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/rewritten/a\nCloning into bare repository 'bare'...\nremote: Enumerating objects: 3, done.\nremote: Counting objects: 100% (3/3), done.\nremote: Total 3 (delta 0), reused 0 (delta 0)\nReceiving objects: 100% (3/3), done.\nPreparing worktree (new branch 'worktree-2')\nHEAD is now at dc2045a a\nworktree-2 adding refs/rewritten/b\nwhy does this show refs/worktree-1/head\nbut not refs/rewritten/b?\n/home/phil/src/git-utils/dev/git-rewrite/bare        (bare)\n/home/phil/src/git-utils/dev/git-rewrite/worktree-2  dc2045a [worktree-2]\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/master\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/worktree-1\ndc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit\trefs/heads/worktree-2\n\n"},{"id":"370886","messageId":"ec707cbb-96e8-f26f-3d69-b69d29b31737@gmail.com","threadId":"50672","inReplyTo":"f6e197f2-886a-5e82-7fc4-c53737dd66cc@gmail.com","subject":"Re: [BUG] worktree local refs weirdness","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-07T09:38:16Z","receivedAt":"2019-03-07T09:38:22Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 06/03/2019 15:57, Phillip Wood wrote:\n> When it is run in a worktree 'git for-each-ref' only seems to show refs \n> under refs/rewritten if that directory also exists under $GIT_COMMON_DIR \n> even though they are local to the worktree.\n> \n> Initially I thought this was due to $GIT_COMMON_DIR pointing to a bare \n> repo, but that is not the case. However while writing a test case which \n> cloned to a bare repo I noticed it was listing a ref for the HEAD of a \n> worktree in the repo I had cloned from, not the clone itself.\n\nIgnore that last paragraph, it's just showing the branch that got \ncreated when the worktree was created. The last part of the script is \nredundant, I've updated it below\n\n\n# setup initial repo\nmkdir repo &&\ncd repo &&\ngit init &&\necho a>a &&\ngit add a &&\ngit commit -ma &&\n#add a worktree and set a ref under refs/rewritten\ngit worktree add ../worktree-1 &&\ncd ../worktree-1 &&\necho 'worktree-1 adding refs/rewritten/a' &&\ngit update-ref refs/rewritten/a HEAD &&\ngit rev-parse --verify refs/rewritten/a &&\necho 'refs/rewritten/a exists but is not shown' &&\ngit for-each-ref &&\n# add a ref under refs/rewritten to the main repo\ncd ../repo &&\necho 'repo adding refs/rewritten/z' &&\ngit update-ref refs/rewritten/z HEAD &&\ngit for-each-ref &&\ncd ../worktree-1 &&\necho 'worktree-1 now shows refs/rewritten/a' &&\ngit for-each-ref\n\nOutput\nInitialized empty Git repository in /tmp/x/repo/.git/\n[master (root-commit) d60b5d6] a\n  1 file changed, 1 insertion(+)\n  create mode 100644 a\nPreparing worktree (new branch 'worktree-1')\nHEAD is now at d60b5d6 a\nworktree-1 adding refs/rewritten/a\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13\nrefs/rewritten/a exists but is not shown\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/heads/master\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/heads/worktree-1\nrepo adding refs/rewritten/z\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/heads/master\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/heads/worktree-1\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/rewritten/z\nworktree-1 now shows refs/rewritten/a\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/heads/master\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/heads/worktree-1\nd60b5d6532fe5ed6e3bc3a0233c6de9d86092d13 commit\trefs/rewritten/a\n\nBest Wishes\n\nPhillip\n\n\n> \n> The script below reproduces both issues, I've copied the output below \n> it. I'm not sure what's going on or the best way to debug it.\n> \n> Best Wishes\n> \n> Phillip\n> \n> # setup initial repo\n> mkdir repo &&\n> cd repo &&\n> git init &&\n> echo a>a &&\n> git add a &&\n> git commit -ma &&\n> #add a worktree and set a ref under refs/rewritten\n> git worktree add ../worktree-1 &&\n> cd ../worktree-1 &&\n> echo 'worktree-1 adding refs/rewritten/a' &&\n> git update-ref refs/rewritten/a HEAD &&\n> git rev-parse --verify refs/rewritten/a &&\n> echo 'refs/rewritten/a exists but is not shown' &&\n> git for-each-ref &&\n> # add a ref under refs/rewritten to the main repo\n> cd ../repo &&\n> echo 'repo adding refs/rewritten/z' &&\n> git update-ref refs/rewritten/z HEAD &&\n> git for-each-ref &&\n> cd ../worktree-1 &&\n> echo 'worktree-1 now shows refs/rewritten/a' &&\n> git for-each-ref &&\n> cd .. &&\n> # create a bare clone with a worktree\n> git clone --bare --no-local repo bare &&\n> cd bare &&\n> git worktree add ../worktree-2 &&\n> cd ../worktree-2 &&\n> echo 'worktree-2 adding refs/rewritten/b' &&\n> echo 'why does this show refs/worktree-1/head' &&\n> echo 'but not refs/rewritten/b?' &&\n> git worktree list &&\n> git update-ref refs/rewritten/b HEAD &&\n> git rev-parse --verify refs/rewritten/b &&\n> git for-each-ref\n> \n> \n> Output\n> Initialized empty Git repository in \n> /home/phil/src/git-utils/dev/git-rewrite/repo/.git/\n> [master (root-commit) dc2045a] a\n>   1 file changed, 1 insertion(+)\n>   create mode 100644 a\n> Preparing worktree (new branch 'worktree-1')\n> HEAD is now at dc2045a a\n> worktree-1 adding refs/rewritten/a\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656\n> refs/rewritten/a exists but is not shown\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/master\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/worktree-1\n> repo adding refs/rewritten/z\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/master\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/worktree-1\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/rewritten/z\n> worktree-1 now shows refs/rewritten/a\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/master\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/worktree-1\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/rewritten/a\n> Cloning into bare repository 'bare'...\n> remote: Enumerating objects: 3, done.\n> remote: Counting objects: 100% (3/3), done.\n> remote: Total 3 (delta 0), reused 0 (delta 0)\n> Receiving objects: 100% (3/3), done.\n> Preparing worktree (new branch 'worktree-2')\n> HEAD is now at dc2045a a\n> worktree-2 adding refs/rewritten/b\n> why does this show refs/worktree-1/head\n> but not refs/rewritten/b?\n> /home/phil/src/git-utils/dev/git-rewrite/bare        (bare)\n> /home/phil/src/git-utils/dev/git-rewrite/worktree-2  dc2045a [worktree-2]\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/master\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/worktree-1\n> dc2045a36f38ba4e9bacd8cd86ba74f58a1d4656 commit    refs/heads/worktree-2\n> \n"},{"id":"370887","messageId":"CACsJy8CrSGQt=_RK8cwc3AW_+gfGLf_M5UKAmjMZrm43Qu3Z8Q@mail.gmail.com","threadId":"50672","inReplyTo":"ec707cbb-96e8-f26f-3d69-b69d29b31737@gmail.com","subject":"Re: [BUG] worktree local refs weirdness","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-07T09:46:13Z","receivedAt":"2019-03-07T09:46:42Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 7, 2019 at 4:38 PM Phillip Wood <phillip.wood123@gmail.com> wrote:\n>\n> On 06/03/2019 15:57, Phillip Wood wrote:\n> > When it is run in a worktree 'git for-each-ref' only seems to show refs\n> > under refs/rewritten if that directory also exists under $GIT_COMMON_DIR\n> > even though they are local to the worktree.\n> >\n> > Initially I thought this was due to $GIT_COMMON_DIR pointing to a bare\n> > repo, but that is not the case. However while writing a test case which\n> > cloned to a bare repo I noticed it was listing a ref for the HEAD of a\n> > worktree in the repo I had cloned from, not the clone itself.\n>\n> Ignore that last paragraph, it's just showing the branch that got\n> created when the worktree was created. The last part of the script is\n> redundant, I've updated it below\n\nThanks for the test script. I could reproduce it and I think I see the\nproblem (update-ref creates per-worktree refs even though\nrefs/rewritten should be per-repo). Working on it...\n-- \nDuy\n"},{"id":"370896","messageId":"CACsJy8Dt9eky51g_hrakGdMHks2mwCEn9uGFNkPO249H-s0+2A@mail.gmail.com","threadId":"50672","inReplyTo":"CACsJy8CrSGQt=_RK8cwc3AW_+gfGLf_M5UKAmjMZrm43Qu3Z8Q@mail.gmail.com","subject":"Re: [BUG] worktree local refs weirdness","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-07T10:20:40Z","receivedAt":"2019-03-07T10:21:09Z","isPatch":false,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 7, 2019 at 4:46 PM Duy Nguyen <pclouds@gmail.com> wrote:\n>\n> On Thu, Mar 7, 2019 at 4:38 PM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> >\n> > On 06/03/2019 15:57, Phillip Wood wrote:\n> > > When it is run in a worktree 'git for-each-ref' only seems to show refs\n> > > under refs/rewritten if that directory also exists under $GIT_COMMON_DIR\n> > > even though they are local to the worktree.\n> > >\n> > > Initially I thought this was due to $GIT_COMMON_DIR pointing to a bare\n> > > repo, but that is not the case. However while writing a test case which\n> > > cloned to a bare repo I noticed it was listing a ref for the HEAD of a\n> > > worktree in the repo I had cloned from, not the clone itself.\n> >\n> > Ignore that last paragraph, it's just showing the branch that got\n> > created when the worktree was created. The last part of the script is\n> > redundant, I've updated it below\n>\n> Thanks for the test script. I could reproduce it and I think I see the\n> problem (update-ref creates per-worktree refs even though\n> refs/rewritten should be per-repo). Working on it...\n\nMy mistake. refs/rewritten is per-worktree, but the ref iteration code\nhas a bug. The fix should come soon.\n-- \nDuy\n"},{"id":"370898","messageId":"20190307122917.12811-1-pclouds@gmail.com","threadId":"50672","inReplyTo":"ec707cbb-96e8-f26f-3d69-b69d29b31737@gmail.com","subject":"[PATCH 0/3] Fix refs/rewritten not show up in for-each-ref","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-07T12:29:14Z","receivedAt":"2019-03-07T12:29:27Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Apparently there is one corner case where refs/rewritten/* may not show\nup in for-each-ref in multiple worktree setup. This is because the\nper-worktree classification has to be done in three places (my bad!)\nand Johannes only updated one.\n\nThis should fix it (and it also fixes refs/worktree/ not showing up\nunder the same condition because I'm an idiot who does not know how to\ntest).\n\nNguyễn Thái Ngọc Duy (3):\n  files-backend.c: factor out per-worktree code in loose_fill_ref_dir()\n  files-backend.c: reduce duplication in\n    add_per_worktree_entries_to_dir()\n  Make sure refs/rewritten/ is per-worktree\n\n path.c                   |  3 +++\n refs/files-backend.c     | 50 ++++++++++++++++++++++------------------\n t/t1415-worktree-refs.sh | 35 ++++++++++++++++++++++++++++\n 3 files changed, 66 insertions(+), 22 deletions(-)\n\n-- \n2.21.0.rc1.337.gdf7f8d0522\n\n"},{"id":"370899","messageId":"20190307122917.12811-2-pclouds@gmail.com","threadId":"50672","inReplyTo":"20190307122917.12811-1-pclouds@gmail.com","subject":"[PATCH 1/3] files-backend.c: factor out per-worktree code in loose_fill_ref_dir()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-07T12:29:15Z","receivedAt":"2019-03-07T12:29:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is the first step for further cleaning up and extending this\nfunction.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs/files-backend.c | 50 +++++++++++++++++++++++++-------------------\n 1 file changed, 28 insertions(+), 22 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex ef053f716c..26417893c8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -214,6 +214,33 @@ static void files_ref_path(struct files_ref_store *refs,\n \t}\n }\n \n+/*\n+ * Manually add refs/bisect and refs/worktree, which, being\n+ * per-worktree, might not appear in the directory listing for\n+ * refs/ in the main repo.\n+ */\n+static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dirname)\n+{\n+\tint pos;\n+\n+\tif (strcmp(dirname, \"refs/\"))\n+\t\treturn;\n+\n+\tpos = search_ref_dir(dir, \"refs/bisect/\", 12);\n+\tif (pos < 0) {\n+\t\tstruct ref_entry *child_entry =\n+\t\t\tcreate_dir_entry(dir->cache, \"refs/bisect/\", 12, 1);\n+\t\tadd_entry_to_dir(dir, child_entry);\n+\t}\n+\n+\tpos = search_ref_dir(dir, \"refs/worktree/\", 11);\n+\tif (pos < 0) {\n+\t\tstruct ref_entry *child_entry =\n+\t\t\tcreate_dir_entry(dir->cache, \"refs/worktree/\", 11, 1);\n+\t\tadd_entry_to_dir(dir, child_entry);\n+\t}\n+}\n+\n /*\n  * Read the loose references from the namespace dirname into dir\n  * (without recursing).  dirname must end with '/'.  dir must be the\n@@ -297,28 +324,7 @@ static void loose_fill_ref_dir(struct ref_store *ref_store,\n \tstrbuf_release(&path);\n \tclosedir(d);\n \n-\t/*\n-\t * Manually add refs/bisect and refs/worktree, which, being\n-\t * per-worktree, might not appear in the directory listing for\n-\t * refs/ in the main repo.\n-\t */\n-\tif (!strcmp(dirname, \"refs/\")) {\n-\t\tint pos = search_ref_dir(dir, \"refs/bisect/\", 12);\n-\n-\t\tif (pos < 0) {\n-\t\t\tstruct ref_entry *child_entry = create_dir_entry(\n-\t\t\t\t\tdir->cache, \"refs/bisect/\", 12, 1);\n-\t\t\tadd_entry_to_dir(dir, child_entry);\n-\t\t}\n-\n-\t\tpos = search_ref_dir(dir, \"refs/worktree/\", 11);\n-\n-\t\tif (pos < 0) {\n-\t\t\tstruct ref_entry *child_entry = create_dir_entry(\n-\t\t\t\t\tdir->cache, \"refs/worktree/\", 11, 1);\n-\t\t\tadd_entry_to_dir(dir, child_entry);\n-\t\t}\n-\t}\n+\tadd_per_worktree_entries_to_dir(dir, dirname);\n }\n \n static struct ref_cache *get_loose_ref_cache(struct files_ref_store *refs)\n-- \n2.21.0.rc1.337.gdf7f8d0522\n\n"},{"id":"370900","messageId":"20190307122917.12811-3-pclouds@gmail.com","threadId":"50672","inReplyTo":"20190307122917.12811-1-pclouds@gmail.com","subject":"[PATCH 2/3] files-backend.c: reduce duplication in add_per_worktree_entries_to_dir()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-07T12:29:16Z","receivedAt":"2019-03-07T12:29:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function is duplicated to handle refs/bisect/ and refs/worktree/\nand a third prefix is coming. Time to clean up.\n\nThis also fixes incorrect \"refs/worktrees/\" length in this code. The\ncorrect length is 14 not 11. The test in the next patch will also cover\nthis.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n refs/files-backend.c | 22 +++++++++++-----------\n 1 file changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 26417893c8..3d0e06edcd 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -221,22 +221,22 @@ static void files_ref_path(struct files_ref_store *refs,\n  */\n static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dirname)\n {\n-\tint pos;\n+\tconst char *prefixes[] = { \"refs/bisect/\", \"refs/worktree/\" };\n+\tint ip;\n \n \tif (strcmp(dirname, \"refs/\"))\n \t\treturn;\n \n-\tpos = search_ref_dir(dir, \"refs/bisect/\", 12);\n-\tif (pos < 0) {\n-\t\tstruct ref_entry *child_entry =\n-\t\t\tcreate_dir_entry(dir->cache, \"refs/bisect/\", 12, 1);\n-\t\tadd_entry_to_dir(dir, child_entry);\n-\t}\n+\tfor (ip = 0; ip < ARRAY_SIZE(prefixes); ip++) {\n+\t\tconst char *prefix = prefixes[ip];\n+\t\tint prefix_len = strlen(prefix);\n+\t\tstruct ref_entry *child_entry;\n+\t\tint pos;\n \n-\tpos = search_ref_dir(dir, \"refs/worktree/\", 11);\n-\tif (pos < 0) {\n-\t\tstruct ref_entry *child_entry =\n-\t\t\tcreate_dir_entry(dir->cache, \"refs/worktree/\", 11, 1);\n+\t\tpos = search_ref_dir(dir, prefix, prefix_len);\n+\t\tif (pos >= 0)\n+\t\t\tcontinue;\n+\t\tchild_entry = create_dir_entry(dir->cache, prefix, prefix_len, 1);\n \t\tadd_entry_to_dir(dir, child_entry);\n \t}\n }\n-- \n2.21.0.rc1.337.gdf7f8d0522\n\n"},{"id":"370901","messageId":"20190307122917.12811-4-pclouds@gmail.com","threadId":"50672","inReplyTo":"20190307122917.12811-1-pclouds@gmail.com","subject":"[PATCH 3/3] Make sure refs/rewritten/ is per-worktree","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-07T12:29:17Z","receivedAt":"2019-03-07T12:29:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"a9be29c981 (sequencer: make refs generated by the `label` command\nworktree-local, 2018-04-25) adds refs/rewritten/ as per-worktree\nreference space. Unfortunately (my bad) there are a couple places that\nneed update to make sure it's really per-worktree.\n\n - add_per_worktree_entries_to_dir() is updated to make sure ref listing\n   look at per-worktree refs/rewritten/ instead of per-repo one [1]\n\n - common_list[] is updated so that git_path() returns the correct\n   location. This includes \"rev-parse --git-path\".\n\nThis mess is created by me. I started trying to fix it with the\nintroduction of refs/worktree, where all refs will be per-worktree\nwithout special treatments. Unfortunate refs/rewritten came before\nrefs/worktree so this is all we can do.\n\nThis also fixes logs/refs/worktree not being per-worktree.\n\n[1] note that ref listing still works sometimes. For example, if you\n    have .git/worktrees/foo/refs/rewritten/bar AND the directory\n    .git/worktrees/refs/rewritten, refs/rewritten/bar will show up.\n    add_per_worktree_entries_to_dir() is only needed when the directory\n    .git/worktrees/refs/rewritten is missing.\n\nReported-by: Phillip Wood <phillip.wood123@gmail.com>\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n path.c                   |  3 +++\n refs/files-backend.c     |  4 ++--\n t/t1415-worktree-refs.sh | 35 +++++++++++++++++++++++++++++++++++\n 3 files changed, 40 insertions(+), 2 deletions(-)\n\ndiff --git a/path.c b/path.c\nindex 03ab712839..25e97b8c3f 100644\n--- a/path.c\n+++ b/path.c\n@@ -115,10 +115,13 @@ static struct common_dir common_list[] = {\n \t{ 1, 1, 0, \"logs\" },\n \t{ 1, 1, 1, \"logs/HEAD\" },\n \t{ 0, 1, 1, \"logs/refs/bisect\" },\n+\t{ 0, 1, 1, \"logs/refs/rewritten\" },\n+\t{ 0, 1, 1, \"logs/refs/worktree\" },\n \t{ 0, 1, 0, \"lost-found\" },\n \t{ 0, 1, 0, \"objects\" },\n \t{ 0, 1, 0, \"refs\" },\n \t{ 0, 1, 1, \"refs/bisect\" },\n+\t{ 0, 1, 1, \"refs/rewritten\" },\n \t{ 0, 1, 1, \"refs/worktree\" },\n \t{ 0, 1, 0, \"remotes\" },\n \t{ 0, 1, 0, \"worktrees\" },\ndiff --git a/refs/files-backend.c b/refs/files-backend.c\nindex 3d0e06edcd..5848f32ef8 100644\n--- a/refs/files-backend.c\n+++ b/refs/files-backend.c\n@@ -215,13 +215,13 @@ static void files_ref_path(struct files_ref_store *refs,\n }\n \n /*\n- * Manually add refs/bisect and refs/worktree, which, being\n+ * Manually add refs/bisect, refs/rewritten and refs/worktree, which, being\n  * per-worktree, might not appear in the directory listing for\n  * refs/ in the main repo.\n  */\n static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dirname)\n {\n-\tconst char *prefixes[] = { \"refs/bisect/\", \"refs/worktree/\" };\n+\tconst char *prefixes[] = { \"refs/bisect/\", \"refs/worktree/\", \"refs/rewritten/\" };\n \tint ip;\n \n \tif (strcmp(dirname, \"refs/\"))\ndiff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh\nindex b664e51250..bb2c7572a3 100755\n--- a/t/t1415-worktree-refs.sh\n+++ b/t/t1415-worktree-refs.sh\n@@ -76,4 +76,39 @@ test_expect_success 'reflog of worktrees/xx/HEAD' '\n \ttest_cmp expected actual.wt2\n '\n \n+test_expect_success 'for-each-ref from main repo' '\n+\tmkdir fer1 &&\n+\tgit -C fer1 init repo &&\n+\ttest_commit -C fer1/repo initial &&\n+\tgit -C fer1/repo worktree add ../second &&\n+\tgit -C fer1/repo update-ref refs/bisect/main HEAD &&\n+\tgit -C fer1/repo update-ref refs/rewritten/main HEAD &&\n+\tgit -C fer1/repo update-ref refs/worktree/main HEAD &&\n+\tgit -C fer1/repo for-each-ref --format=\"%(refname)\" | grep main >actual &&\n+\tcat >expected <<-\\EOF &&\n+\trefs/bisect/main\n+\trefs/rewritten/main\n+\trefs/worktree/main\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'for-each-ref from linked repo' '\n+\tmkdir fer2 &&\n+\tgit -C fer2 init repo &&\n+\ttest_commit -C fer2/repo initial &&\n+\tgit -C fer2/repo worktree add ../second &&\n+\tgit -C fer2/second update-ref refs/bisect/second HEAD &&\n+\tgit -C fer2/second update-ref refs/rewritten/second HEAD &&\n+\tgit -C fer2/second update-ref refs/worktree/second HEAD &&\n+\tgit -C fer2/second for-each-ref --format=\"%(refname)\" | grep second >actual &&\n+\tcat >expected <<-\\EOF &&\n+\trefs/bisect/second\n+\trefs/heads/second\n+\trefs/rewritten/second\n+\trefs/worktree/second\n+\tEOF\n+\ttest_cmp expected actual\n+'\n+\n test_done\n-- \n2.21.0.rc1.337.gdf7f8d0522\n\n"},{"id":"370905","messageId":"3c50aa4f-127a-1be8-2d3e-1941f01d2fa0@gmail.com","threadId":"50672","inReplyTo":"20190307122917.12811-3-pclouds@gmail.com","subject":"Re: [PATCH 2/3] files-backend.c: reduce duplication in add_per_worktree_entries_to_dir()","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-07T14:44:44Z","receivedAt":"2019-03-07T14:44:49Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Duy\n\nOn 07/03/2019 12:29, Nguyễn Thái Ngọc Duy wrote:\n> This function is duplicated to handle refs/bisect/ and refs/worktree/\n> and a third prefix is coming. Time to clean up.\n> \n> This also fixes incorrect \"refs/worktrees/\" length in this code. The\n> correct length is 14 not 11. The test in the next patch will also cover\n> this.\n\nI ran strace this morning and saw\n\nopenat(AT_FDCWD, \"/tmp/x/repo/.git/refs/worktr\", \nO_RDONLY|O_NONBLOCK|O_CLOEXEC|O_DIRECTORY) = -1 ENOENT (No such file or \ndirectory)\n\nI was just about to email you about it but you've already fixed it!\n\nBest Wishes\n\nPhillip\n\n> \n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>   refs/files-backend.c | 22 +++++++++++-----------\n>   1 file changed, 11 insertions(+), 11 deletions(-)\n> \n> diff --git a/refs/files-backend.c b/refs/files-backend.c\n> index 26417893c8..3d0e06edcd 100644\n> --- a/refs/files-backend.c\n> +++ b/refs/files-backend.c\n> @@ -221,22 +221,22 @@ static void files_ref_path(struct files_ref_store *refs,\n>    */\n>   static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dirname)\n>   {\n> -\tint pos;\n> +\tconst char *prefixes[] = { \"refs/bisect/\", \"refs/worktree/\" };\n> +\tint ip;\n>   \n>   \tif (strcmp(dirname, \"refs/\"))\n>   \t\treturn;\n>   \n> -\tpos = search_ref_dir(dir, \"refs/bisect/\", 12);\n> -\tif (pos < 0) {\n> -\t\tstruct ref_entry *child_entry =\n> -\t\t\tcreate_dir_entry(dir->cache, \"refs/bisect/\", 12, 1);\n> -\t\tadd_entry_to_dir(dir, child_entry);\n> -\t}\n> +\tfor (ip = 0; ip < ARRAY_SIZE(prefixes); ip++) {\n> +\t\tconst char *prefix = prefixes[ip];\n> +\t\tint prefix_len = strlen(prefix);\n> +\t\tstruct ref_entry *child_entry;\n> +\t\tint pos;\n>   \n> -\tpos = search_ref_dir(dir, \"refs/worktree/\", 11);\n> -\tif (pos < 0) {\n> -\t\tstruct ref_entry *child_entry =\n> -\t\t\tcreate_dir_entry(dir->cache, \"refs/worktree/\", 11, 1);\n> +\t\tpos = search_ref_dir(dir, prefix, prefix_len);\n> +\t\tif (pos >= 0)\n> +\t\t\tcontinue;\n> +\t\tchild_entry = create_dir_entry(dir->cache, prefix, prefix_len, 1);\n>   \t\tadd_entry_to_dir(dir, child_entry);\n>   \t}\n>   }\n> \n"},{"id":"370906","messageId":"1e0fe5a0-decb-ccd3-19ee-5fe2e5148fb1@gmail.com","threadId":"50672","inReplyTo":"20190307122917.12811-4-pclouds@gmail.com","subject":"Re: [PATCH 3/3] Make sure refs/rewritten/ is per-worktree","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2019-03-07T14:45:01Z","receivedAt":"2019-03-07T14:45:08Z","isPatch":true,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Duy\n\nThanks for working on this I've had a quick look through and they seem \nto make sense to me although I've not really looked at the refs code before.\n\nOn 07/03/2019 12:29, Nguyễn Thái Ngọc Duy wrote:\n> a9be29c981 (sequencer: make refs generated by the `label` command\n> worktree-local, 2018-04-25) adds refs/rewritten/ as per-worktree\n> reference space. Unfortunately (my bad) there are a couple places that\n> need update to make sure it's really per-worktree.\n> \n>   - add_per_worktree_entries_to_dir() is updated to make sure ref listing\n>     look at per-worktree refs/rewritten/ instead of per-repo one [1]\n> \n>   - common_list[] is updated so that git_path() returns the correct\n>     location. This includes \"rev-parse --git-path\".\n> \n> This mess is created by me. I started trying to fix it with the\n> introduction of refs/worktree, where all refs will be per-worktree\n> without special treatments. Unfortunate refs/rewritten came before\n> refs/worktree so this is all we can do.\n> \n> This also fixes logs/refs/worktree not being per-worktree.\n> \n> [1] note that ref listing still works sometimes. For example, if you\n>      have .git/worktrees/foo/refs/rewritten/bar AND the directory\n>      .git/worktrees/refs/rewritten, \n\nshould that be .git/refs/rewritten? (and below)\n\nBest Wishes\n\nPhillip\n\nrefs/rewritten/bar will show up.\n>      add_per_worktree_entries_to_dir() is only needed when the directory\n>      .git/worktrees/refs/rewritten is missing.\n> \n> Reported-by: Phillip Wood <phillip.wood123@gmail.com>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>   path.c                   |  3 +++\n>   refs/files-backend.c     |  4 ++--\n>   t/t1415-worktree-refs.sh | 35 +++++++++++++++++++++++++++++++++++\n>   3 files changed, 40 insertions(+), 2 deletions(-)\n> \n> diff --git a/path.c b/path.c\n> index 03ab712839..25e97b8c3f 100644\n> --- a/path.c\n> +++ b/path.c\n> @@ -115,10 +115,13 @@ static struct common_dir common_list[] = {\n>   \t{ 1, 1, 0, \"logs\" },\n>   \t{ 1, 1, 1, \"logs/HEAD\" },\n>   \t{ 0, 1, 1, \"logs/refs/bisect\" },\n> +\t{ 0, 1, 1, \"logs/refs/rewritten\" },\n> +\t{ 0, 1, 1, \"logs/refs/worktree\" },\n>   \t{ 0, 1, 0, \"lost-found\" },\n>   \t{ 0, 1, 0, \"objects\" },\n>   \t{ 0, 1, 0, \"refs\" },\n>   \t{ 0, 1, 1, \"refs/bisect\" },\n> +\t{ 0, 1, 1, \"refs/rewritten\" },\n>   \t{ 0, 1, 1, \"refs/worktree\" },\n>   \t{ 0, 1, 0, \"remotes\" },\n>   \t{ 0, 1, 0, \"worktrees\" },\n> diff --git a/refs/files-backend.c b/refs/files-backend.c\n> index 3d0e06edcd..5848f32ef8 100644\n> --- a/refs/files-backend.c\n> +++ b/refs/files-backend.c\n> @@ -215,13 +215,13 @@ static void files_ref_path(struct files_ref_store *refs,\n>   }\n>   \n>   /*\n> - * Manually add refs/bisect and refs/worktree, which, being\n> + * Manually add refs/bisect, refs/rewritten and refs/worktree, which, being\n>    * per-worktree, might not appear in the directory listing for\n>    * refs/ in the main repo.\n>    */\n>   static void add_per_worktree_entries_to_dir(struct ref_dir *dir, const char *dirname)\n>   {\n> -\tconst char *prefixes[] = { \"refs/bisect/\", \"refs/worktree/\" };\n> +\tconst char *prefixes[] = { \"refs/bisect/\", \"refs/worktree/\", \"refs/rewritten/\" };\n>   \tint ip;\n>   \n>   \tif (strcmp(dirname, \"refs/\"))\n> diff --git a/t/t1415-worktree-refs.sh b/t/t1415-worktree-refs.sh\n> index b664e51250..bb2c7572a3 100755\n> --- a/t/t1415-worktree-refs.sh\n> +++ b/t/t1415-worktree-refs.sh\n> @@ -76,4 +76,39 @@ test_expect_success 'reflog of worktrees/xx/HEAD' '\n>   \ttest_cmp expected actual.wt2\n>   '\n>   \n> +test_expect_success 'for-each-ref from main repo' '\n> +\tmkdir fer1 &&\n> +\tgit -C fer1 init repo &&\n> +\ttest_commit -C fer1/repo initial &&\n> +\tgit -C fer1/repo worktree add ../second &&\n> +\tgit -C fer1/repo update-ref refs/bisect/main HEAD &&\n> +\tgit -C fer1/repo update-ref refs/rewritten/main HEAD &&\n> +\tgit -C fer1/repo update-ref refs/worktree/main HEAD &&\n> +\tgit -C fer1/repo for-each-ref --format=\"%(refname)\" | grep main >actual &&\n> +\tcat >expected <<-\\EOF &&\n> +\trefs/bisect/main\n> +\trefs/rewritten/main\n> +\trefs/worktree/main\n> +\tEOF\n> +\ttest_cmp expected actual\n> +'\n> +\n> +test_expect_success 'for-each-ref from linked repo' '\n> +\tmkdir fer2 &&\n> +\tgit -C fer2 init repo &&\n> +\ttest_commit -C fer2/repo initial &&\n> +\tgit -C fer2/repo worktree add ../second &&\n> +\tgit -C fer2/second update-ref refs/bisect/second HEAD &&\n> +\tgit -C fer2/second update-ref refs/rewritten/second HEAD &&\n> +\tgit -C fer2/second update-ref refs/worktree/second HEAD &&\n> +\tgit -C fer2/second for-each-ref --format=\"%(refname)\" | grep second >actual &&\n> +\tcat >expected <<-\\EOF &&\n> +\trefs/bisect/second\n> +\trefs/heads/second\n> +\trefs/rewritten/second\n> +\trefs/worktree/second\n> +\tEOF\n> +\ttest_cmp expected actual\n> +'\n> +\n>   test_done\n> \n"},{"id":"370907","messageId":"CACsJy8CeBRbdKoHZ0z0f3pqHJpNJDHSCcwxDrM+p9jzYZSBpTQ@mail.gmail.com","threadId":"50672","inReplyTo":"1e0fe5a0-decb-ccd3-19ee-5fe2e5148fb1@gmail.com","subject":"Re: [PATCH 3/3] Make sure refs/rewritten/ is per-worktree","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-03-07T14:51:10Z","receivedAt":"2019-03-07T14:51:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Mar 7, 2019 at 9:45 PM Phillip Wood <phillip.wood123@gmail.com> wrote:\n> > [1] note that ref listing still works sometimes. For example, if you\n> >      have .git/worktrees/foo/refs/rewritten/bar AND the directory\n> >      .git/worktrees/refs/rewritten,\n>\n> should that be .git/refs/rewritten? (and below)\n\nYes.\n-- \nDuy\n"}]}