{"thread":{"id":"49438","subject":"[PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","startedAt":"2018-09-27T15:13:43Z","lastAt":"2019-04-30T21:46:40Z","messageCount":125,"participants":["Nickolai Belakovski","Ævar Arnfjörð Bjarmason","Duy Nguyen","Jeff King","Rafael Ascensão","Junio C Hamano","Johannes Schindelin","nbelakovski@gmail.com","Eric Sunshine","Philip Oakley","SZEDER Gábor"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"359053","messageId":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","threadId":"49438","inReplyTo":null,"subject":"[PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-09-27T15:13:13Z","receivedAt":"2018-09-27T15:13:43Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"In order to more clearly display which branches are active, the output\nof git branch is modified to colorize branches checked out in any linked\nworktrees with the same color as the current branch.\n\nThis is meant to simplify workflows related to worktree, particularly\ndue to the limitations of not being able to check out the same branch in\ntwo worktrees and the inability to delete a branch checked out in a\nworktree. When performing branch operations like checkout and delete, it\nwould be useful to know more readily if the branches in which the user\nis interested are already checked out in a worktree.\n\nThe git worktree list command contains the relevant information, however\nthis is a much less frquently used command than git branch.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n\nNotes:\n    Travis CI results: https://travis-ci.org/nbelakovski/git/builds/432320949\n\n builtin/branch.c         | 35 ++++++++++++++++++++++++++++++-----\n t/t3203-branch-output.sh | 21 +++++++++++++++++++++\n 2 files changed, 51 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 4fc55c350..65b58ff7c 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -334,11 +334,36 @@ static char *build_format(struct ref_filter\n*filter, int maxwidth, const char *r\n        struct strbuf local = STRBUF_INIT;\n        struct strbuf remote = STRBUF_INIT;\n\n-       strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-                   branch_get_color(BRANCH_COLOR_CURRENT),\n-                   branch_get_color(BRANCH_COLOR_LOCAL));\n-       strbuf_addf(&remote, \"  %s\",\n-                   branch_get_color(BRANCH_COLOR_REMOTE));\n+       // Prepend the current branch of this worktree with \"* \" and\nall other branches with \"  \"\n+       strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %%(else)  %%(end)\");\n+       // Prepend remote branches with two spaces\n+       strbuf_addstr(&remote, \"  \");\n+       if(want_color(branch_use_color)) {\n+               // Create a nested if statement to evaluate if the\ncurrent ref is equal to a HEAD ref from either\n+               // the main or any linked worktrees. If so, color it\nCURRENT, otherwise color it LOCAL\n+               struct strbuf color = STRBUF_INIT;\n+               struct worktree **worktrees = get_worktrees(0);\n+               int i;\n+               for (i = 0; worktrees[i]; ++i) {\n+                       strbuf_addf(&color,\n\"%%(if:equals=%s)%%(refname)%%(then)%s%%(else)\",\n+                                   worktrees[i]->head_ref,\n+                                   branch_get_color(BRANCH_COLOR_CURRENT));\n+               }\n+               // add one more check in the nested if-else to cover\nthe detached HEAD state\n+               strbuf_addf(&color, \"%%(if)%%(HEAD)%%(then)%s%%(else)%s%%(end)\",\n+                           branch_get_color(BRANCH_COLOR_CURRENT),\n+                           branch_get_color(BRANCH_COLOR_LOCAL));\n+               // close up the nested if-else\n+               for (; i > 0; --i) {\n+                       strbuf_addf(&color, \"%%(end)\");\n+               }\n+               free_worktrees(worktrees);\n+               strbuf_addbuf(&local, &color);\n+               strbuf_release(&color);\n+\n+               strbuf_addf(&remote, \"%s\",\n+                           branch_get_color(BRANCH_COLOR_REMOTE));\n+    }\n\n        if (filter->verbose) {\n                struct strbuf obname = STRBUF_INIT;\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614..369a156c0 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n        test_i18ncmp expect actual\n '\n\n+test_expect_success '\"add\" a worktree' '\n+       mkdir worktree_dir &&\n+       git worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n+  <GREEN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+       test_terminal git branch >actual.raw &&\n+       test_decode_color <actual.raw >actual &&\n+       test_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n        echo \"<RED>master<RESET>\" >expect.color &&\n        echo \"master\" >expect.bare &&\n\n-- \n2.14.2\n"},{"id":"359060","messageId":"87y3bnhs5a.fsf@evledraar.gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-09-27T15:33:21Z","receivedAt":"2018-09-27T15:33:27Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Sep 27 2018, Nickolai Belakovski wrote:\n\n> In order to more clearly display which branches are active, the output\n> of git branch is modified to colorize branches checked out in any linked\n> worktrees with the same color as the current branch.\n>\n> This is meant to simplify workflows related to worktree, particularly\n> due to the limitations of not being able to check out the same branch in\n> two worktrees and the inability to delete a branch checked out in a\n> worktree. When performing branch operations like checkout and delete, it\n> would be useful to know more readily if the branches in which the user\n> is interested are already checked out in a worktree.\n>\n> The git worktree list command contains the relevant information, however\n> this is a much less frquently used command than git branch.\n>\n> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n\nSounds cool, b.t.w. would be neat-o to have some screenshot uploaded to\nimgur or whatever just to skim what it looks like before/after.\n\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index 4fc55c350..65b58ff7c 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter\n> *filter, int maxwidth, const char *r\n>         struct strbuf local = STRBUF_INIT;\n>         struct strbuf remote = STRBUF_INIT;\n>\n> -       strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n> -                   branch_get_color(BRANCH_COLOR_CURRENT),\n> -                   branch_get_color(BRANCH_COLOR_LOCAL));\n> -       strbuf_addf(&remote, \"  %s\",\n> -                   branch_get_color(BRANCH_COLOR_REMOTE));\n> +       // Prepend the current branch of this worktree with \"* \" and\n> all other branches with \"  \"\n\n\nWe use /* ... */ C comments, not C++-style // (well, it's in C now, but\nnot the ancient versions we need to support).\n\nIt also seems all of this patch was copy/pasted into GMail or something,\nit has wrapping and doesn't apply with \"git am\".\n\nAlso most/all of these comments I'd say we could better do without,\ni.e. the ones explaining basic code flow that's easy to see from the\ncode itself.\n"},{"id":"359075","messageId":"CAC05387jxW-LKk8Qk6Tt50PHi62YpBGQpDFyx_W4m+ROZbej0g@mail.gmail.com","threadId":"49438","inReplyTo":"87y3bnhs5a.fsf@evledraar.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-09-27T17:46:39Z","receivedAt":"2018-09-27T17:47:24Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"Will do re: screenshot when I get home, although it's pretty easy to\nimagine, the git branch output will have one other branch colored in\ngreen, bit without the asterisk (for one linked worktree) :)\n\nAlso will do re: changing comments to /**/ (didn't know // was from\nC++, TIL) and I'll clean up the comments to remove some of the more\nobvious ones, but I'll try to keep a comment explaining the basic flow\nof creating a nest if statement to evaluate worktree refs for color.\n\nAnd yes, I copy/pasted into gmail. I was having trouble setting up\nsend-email, but I think I may have it figured out now. Should I create\na new thread with send-email? Or maybe reply to this one (I can do\nthat by specifying the Message-ID to reply to right? This is my first\ntime using this workflow, so I appreciate your patience :) )?\n\nThanks for the feedback!\n\nOn Thu, Sep 27, 2018 at 8:33 AM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n>\n> On Thu, Sep 27 2018, Nickolai Belakovski wrote:\n>\n> > In order to more clearly display which branches are active, the output\n> > of git branch is modified to colorize branches checked out in any linked\n> > worktrees with the same color as the current branch.\n> >\n> > This is meant to simplify workflows related to worktree, particularly\n> > due to the limitations of not being able to check out the same branch in\n> > two worktrees and the inability to delete a branch checked out in a\n> > worktree. When performing branch operations like checkout and delete, it\n> > would be useful to know more readily if the branches in which the user\n> > is interested are already checked out in a worktree.\n> >\n> > The git worktree list command contains the relevant information, however\n> > this is a much less frquently used command than git branch.\n> >\n> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n>\n> Sounds cool, b.t.w. would be neat-o to have some screenshot uploaded to\n> imgur or whatever just to skim what it looks like before/after.\n>\n> > diff --git a/builtin/branch.c b/builtin/branch.c\n> > index 4fc55c350..65b58ff7c 100644\n> > --- a/builtin/branch.c\n> > +++ b/builtin/branch.c\n> > @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter\n> > *filter, int maxwidth, const char *r\n> >         struct strbuf local = STRBUF_INIT;\n> >         struct strbuf remote = STRBUF_INIT;\n> >\n> > -       strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n> > -                   branch_get_color(BRANCH_COLOR_CURRENT),\n> > -                   branch_get_color(BRANCH_COLOR_LOCAL));\n> > -       strbuf_addf(&remote, \"  %s\",\n> > -                   branch_get_color(BRANCH_COLOR_REMOTE));\n> > +       // Prepend the current branch of this worktree with \"* \" and\n> > all other branches with \"  \"\n>\n>\n> We use /* ... */ C comments, not C++-style // (well, it's in C now, but\n> not the ancient versions we need to support).\n>\n> It also seems all of this patch was copy/pasted into GMail or something,\n> it has wrapping and doesn't apply with \"git am\".\n>\n> Also most/all of these comments I'd say we could better do without,\n> i.e. the ones explaining basic code flow that's easy to see from the\n> code itself.\n"},{"id":"359077","messageId":"CACsJy8AQ9uGoJUvDo8+9n7HbvsHsNRSyntxRZ5tUFRVxFGAS0w@mail.gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-09-27T17:58:00Z","receivedAt":"2018-09-27T17:58:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, Sep 27, 2018 at 5:15 PM Nickolai Belakovski\n<nbelakovski@gmail.com> wrote:\n>\n> In order to more clearly display which branches are active, the output\n> of git branch is modified to colorize branches checked out in any linked\n> worktrees with the same color as the current branch.\n\nMy first thought was \"how do I know which branch I'm on then if they\nare all green?\" but then the current worktree's branch would have a\n\"*\" in front while other worktree's do not. Perhaps worth mentioning\nin the commit message.\n\nIt may be better though to have a different color code for other\nworktree's branch, we can still default the color to green, but people\nwho rely on colors rather than \"*\" can choose a different color.\n-- \nDuy\n"},{"id":"359078","messageId":"87sh1uizxp.fsf@evledraar.gmail.com","threadId":"49438","inReplyTo":"CAC05387S9P+w8yqqcjkQDnURYSgQmqtukxS4KvqJu-kDA+_o0g@mail.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-09-27T17:59:46Z","receivedAt":"2018-09-27T17:59:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Sep 27 2018, Nickolai Belakovski wrote:\n\n> Will do re: screenshot when I get home, although it's pretty easy to\n> imagine, the git branch output will have one other branch colored in green,\n> bit without the asterisk (for one linked worktree) :)\n>\n> Also will do re: changing comments to /**/ (didn't know // was from C++,\n> TIL) and I'll clean up the comments to remove some of the more obvious\n> ones, but I'll try to keep a comment explaining the basic flow of creating\n> a nest if statement to evaluate worktree refs for color.\n>\n> And yes, I copy/pasted into gmail. I was having trouble setting up\n> send-email, but I think I may have it figured out now. Should I create a\n> new thread with send-email? Or maybe reply to this one (I can do that by\n> specifying the Message-ID to reply to right?\n\nYou'd run git format-patch master..your-topic with\n--subject-prefix=\"PATCH v2\" and\n--in-reply-to=\"<CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com>\". Then\nit'll show up in reply to your v1.\n\nYou can also for an easier experience do this via GitGitGadget, see\nhttps://github.com/gitgitgadget/gitgitgadget looking at its code it\nseems to have some way to reference a Message-ID, but I don't know how\nto trigger that.\n\n> This is my first time using this workflow, so I appreciate your\n> patience :) )?\n\nNo worries, happy to help.\n\n> On Thu, Sep 27, 2018 at 8:33 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> wrote:\n>\n>>\n>> On Thu, Sep 27 2018, Nickolai Belakovski wrote:\n>>\n>> > In order to more clearly display which branches are active, the output\n>> > of git branch is modified to colorize branches checked out in any linked\n>> > worktrees with the same color as the current branch.\n>> >\n>> > This is meant to simplify workflows related to worktree, particularly\n>> > due to the limitations of not being able to check out the same branch in\n>> > two worktrees and the inability to delete a branch checked out in a\n>> > worktree. When performing branch operations like checkout and delete, it\n>> > would be useful to know more readily if the branches in which the user\n>> > is interested are already checked out in a worktree.\n>> >\n>> > The git worktree list command contains the relevant information, however\n>> > this is a much less frquently used command than git branch.\n>> >\n>> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n>>\n>> Sounds cool, b.t.w. would be neat-o to have some screenshot uploaded to\n>> imgur or whatever just to skim what it looks like before/after.\n>>\n>> > diff --git a/builtin/branch.c b/builtin/branch.c\n>> > index 4fc55c350..65b58ff7c 100644\n>> > --- a/builtin/branch.c\n>> > +++ b/builtin/branch.c\n>> > @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter\n>> > *filter, int maxwidth, const char *r\n>> >         struct strbuf local = STRBUF_INIT;\n>> >         struct strbuf remote = STRBUF_INIT;\n>> >\n>> > -       strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)\n>> %s%%(end)\",\n>> > -                   branch_get_color(BRANCH_COLOR_CURRENT),\n>> > -                   branch_get_color(BRANCH_COLOR_LOCAL));\n>> > -       strbuf_addf(&remote, \"  %s\",\n>> > -                   branch_get_color(BRANCH_COLOR_REMOTE));\n>> > +       // Prepend the current branch of this worktree with \"* \" and\n>> > all other branches with \"  \"\n>>\n>>\n>> We use /* ... */ C comments, not C++-style // (well, it's in C now, but\n>> not the ancient versions we need to support).\n>>\n>> It also seems all of this patch was copy/pasted into GMail or something,\n>> it has wrapping and doesn't apply with \"git am\".\n>>\n>> Also most/all of these comments I'd say we could better do without,\n>> i.e. the ones explaining basic code flow that's easy to see from the\n>> code itself.\n>>\n"},{"id":"359081","messageId":"20180927181708.GA2468@sigill.intra.peff.net","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-09-27T18:17:08Z","receivedAt":"2018-09-27T18:17:12Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 27, 2018 at 08:13:13AM -0700, Nickolai Belakovski wrote:\n\n> In order to more clearly display which branches are active, the output\n> of git branch is modified to colorize branches checked out in any linked\n> worktrees with the same color as the current branch.\n\nI think the goal makes sense.\n\nDo we want to limit this to git-branch, though? Ideally any output you\nget from git-branch could be replicated with for-each-ref (or with\na custom \"branch --format\").\n\nI.e., could we have a format in ref-filter that matches HEAD, but\nreturns a distinct symbol for a worktree HEAD? That would allow a few\nthings:\n\n  - custom --formats for for-each-ref and branch could reuse the logic\n\n  - we could show the symbol (in place of \"*\") even when color is not\n    enabled\n\n  - it should be much faster if there are a lot of worktrees; your patch\n    does a linear if/else chain to look at each worktree, and it does it\n    in the format-language, which is much slower than actual C. :)\n\nSomething like the patch below. I just picked \"+\" arbitrarily, but any\ncharacter would do (I avoided \"*\" just to make it visually distinct from\nthe current-worktree HEAD). I've left plugging this into git-branch's\ndefault format as an exercise for the reader. ;)\n\n---\ndiff --git a/ref-filter.c b/ref-filter.c\nindex e1bcb4ca8a..b17eefed0d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,7 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -114,6 +115,7 @@ static struct used_atom {\n \t\t} objectname;\n \t\tstruct refname_atom refname;\n \t\tchar *head;\n+\t\tstruct string_list worktree_heads;\n \t} u;\n } *used_atom;\n static int used_atom_cnt, need_tagged, need_symref;\n@@ -420,6 +422,29 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n \treturn 0;\n }\n \n+static int worktree_head_atom_parser(const struct ref_format *format,\n+\t\t\t\t     struct used_atom *atom,\n+\t\t\t\t     const char *arg,\n+\t\t\t\t     struct strbuf *unused_err)\n+{\n+\tstruct worktree **worktrees = get_worktrees(0);\n+\tint i;\n+\n+\tstring_list_init(&atom->u.worktree_heads, 1);\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref)\n+\t\t\tstring_list_append(&atom->u.worktree_heads,\n+\t\t\t\t\t   worktrees[i]->head_ref);\n+\t}\n+\n+\tstring_list_sort(&atom->u.worktree_heads);\n+\n+\tfree_worktrees(worktrees);\n+\treturn 0;\n+\n+}\n+\n static struct {\n \tconst char *name;\n \tinfo_source source;\n@@ -460,6 +485,7 @@ static struct {\n \t{ \"symref\", SOURCE_NONE, FIELD_STR, refname_atom_parser },\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n+\t{ \"worktree\", SOURCE_NONE, FIELD_STR, worktree_head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n@@ -1588,6 +1614,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t\t\telse\n \t\t\t\tv->s = \" \";\n \t\t\tcontinue;\n+\t\t} else if (!strcmp(name, \"worktree\")) {\n+\t\t\tif (string_list_has_string(&atom->u.worktree_heads,\n+\t\t\t\t\t\t   ref->refname))\n+\t\t\t\tv->s = \"+\";\n+\t\t\telse\n+\t\t\t\tv->s = \" \";\n+\t\t\tcontinue;\n \t\t} else if (starts_with(name, \"align\")) {\n \t\t\tv->handler = align_atom_handler;\n \t\t\tv->s = \"\";\n"},{"id":"359089","messageId":"CAC053843M-dXgRXziibLET+r+0adNaefnMBjED8bTwXrvvgrzg@mail.gmail.com","threadId":"49438","inReplyTo":"20180927181708.GA2468@sigill.intra.peff.net","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-09-27T18:39:26Z","receivedAt":"2018-09-27T18:39:56Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"Thanks for the feedback Peff. I actually agree with all your points.\nI'd considered an approach like what you proposed, but rejected it for\nthe first iteration in an effort to keep scope limited and see what\nkind of feedback I'd get overall (like would people even want this?).\nThis is a much better approach, and also gives a path for listing the\nworktree path in the verbose output.\n\n@Duy yea we can use a different color, maybe a darker shade of green.\nI saw plenty to choose from in the color list so I'll play around with\nit. It would definitely make it easier to distinguish at a glance\nwhich branch is checked out in the current worktree vs others.\nOn Thu, Sep 27, 2018 at 11:17 AM Jeff King <peff@peff.net> wrote:\n>\n> On Thu, Sep 27, 2018 at 08:13:13AM -0700, Nickolai Belakovski wrote:\n>\n> > In order to more clearly display which branches are active, the output\n> > of git branch is modified to colorize branches checked out in any linked\n> > worktrees with the same color as the current branch.\n>\n> I think the goal makes sense.\n>\n> Do we want to limit this to git-branch, though? Ideally any output you\n> get from git-branch could be replicated with for-each-ref (or with\n> a custom \"branch --format\").\n>\n> I.e., could we have a format in ref-filter that matches HEAD, but\n> returns a distinct symbol for a worktree HEAD? That would allow a few\n> things:\n>\n>   - custom --formats for for-each-ref and branch could reuse the logic\n>\n>   - we could show the symbol (in place of \"*\") even when color is not\n>     enabled\n>\n>   - it should be much faster if there are a lot of worktrees; your patch\n>     does a linear if/else chain to look at each worktree, and it does it\n>     in the format-language, which is much slower than actual C. :)\n>\n> Something like the patch below. I just picked \"+\" arbitrarily, but any\n> character would do (I avoided \"*\" just to make it visually distinct from\n> the current-worktree HEAD). I've left plugging this into git-branch's\n> default format as an exercise for the reader. ;)\n>\n> ---\n> diff --git a/ref-filter.c b/ref-filter.c\n> index e1bcb4ca8a..b17eefed0d 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -20,6 +20,7 @@\n>  #include \"commit-slab.h\"\n>  #include \"commit-graph.h\"\n>  #include \"commit-reach.h\"\n> +#include \"worktree.h\"\n>\n>  static struct ref_msg {\n>         const char *gone;\n> @@ -114,6 +115,7 @@ static struct used_atom {\n>                 } objectname;\n>                 struct refname_atom refname;\n>                 char *head;\n> +               struct string_list worktree_heads;\n>         } u;\n>  } *used_atom;\n>  static int used_atom_cnt, need_tagged, need_symref;\n> @@ -420,6 +422,29 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n>         return 0;\n>  }\n>\n> +static int worktree_head_atom_parser(const struct ref_format *format,\n> +                                    struct used_atom *atom,\n> +                                    const char *arg,\n> +                                    struct strbuf *unused_err)\n> +{\n> +       struct worktree **worktrees = get_worktrees(0);\n> +       int i;\n> +\n> +       string_list_init(&atom->u.worktree_heads, 1);\n> +\n> +       for (i = 0; worktrees[i]; i++) {\n> +               if (worktrees[i]->head_ref)\n> +                       string_list_append(&atom->u.worktree_heads,\n> +                                          worktrees[i]->head_ref);\n> +       }\n> +\n> +       string_list_sort(&atom->u.worktree_heads);\n> +\n> +       free_worktrees(worktrees);\n> +       return 0;\n> +\n> +}\n> +\n>  static struct {\n>         const char *name;\n>         info_source source;\n> @@ -460,6 +485,7 @@ static struct {\n>         { \"symref\", SOURCE_NONE, FIELD_STR, refname_atom_parser },\n>         { \"flag\", SOURCE_NONE },\n>         { \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n> +       { \"worktree\", SOURCE_NONE, FIELD_STR, worktree_head_atom_parser },\n>         { \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n>         { \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n>         { \"end\", SOURCE_NONE },\n> @@ -1588,6 +1614,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>                         else\n>                                 v->s = \" \";\n>                         continue;\n> +               } else if (!strcmp(name, \"worktree\")) {\n> +                       if (string_list_has_string(&atom->u.worktree_heads,\n> +                                                  ref->refname))\n> +                               v->s = \"+\";\n> +                       else\n> +                               v->s = \" \";\n> +                       continue;\n>                 } else if (starts_with(name, \"align\")) {\n>                         v->handler = align_atom_handler;\n>                         v->s = \"\";\n"},{"id":"359092","messageId":"20180927185128.GA4612@sigill.intra.peff.net","threadId":"49438","inReplyTo":"CAC053843M-dXgRXziibLET+r+0adNaefnMBjED8bTwXrvvgrzg@mail.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-09-27T18:51:28Z","receivedAt":"2018-09-27T18:51:32Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 27, 2018 at 11:39:26AM -0700, Nickolai Belakovski wrote:\n\n> Thanks for the feedback Peff. I actually agree with all your points.\n> I'd considered an approach like what you proposed, but rejected it for\n> the first iteration in an effort to keep scope limited and see what\n> kind of feedback I'd get overall (like would people even want this?).\n> This is a much better approach, and also gives a path for listing the\n> worktree path in the verbose output.\n\nGreat. If you go that route, feel free to use whatever bits of my patch\nare useful. I tested it only by running \"for-each-ref\" once, so it might\nneed some more help. Definitely tests and documentation at the least. :)\n\n-Peff\n"},{"id":"359105","messageId":"20180927192804.GA27163@rigel","threadId":"49438","inReplyTo":"20180927181708.GA2468@sigill.intra.peff.net","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Rafael Ascensão","fromEmail":"rafa.almas@gmail.com","sentAt":"2018-09-27T19:28:04Z","receivedAt":"2018-09-27T19:28:24Z","isPatch":true,"sender":{"key":"rafa.almas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923789?v=4"},"body":"On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:\n> Do we want to limit this to git-branch, though? Ideally any output you\n> get from git-branch could be replicated with for-each-ref (or with\n> a custom \"branch --format\").\n> \n> I.e., could we have a format in ref-filter that matches HEAD, but\n> returns a distinct symbol for a worktree HEAD? That would allow a few\n> things:\n\nI was going to suggest using dim green and green for elsewhere and here\nrespectively, in a similar way how range-diff uses it to show different\nversions of the same diff.\n\nBut if we're open to change how branches are displayed maybe a config\noption like branch.format (probably not the best name choice) that can\nbe set to the 'for-each-ref --format' syntax would be way more flexible.\n\ne.g.\n    branch.format='%(if:equals=+)...'\n\nI think the different symbol and dimmed color would be a nice addition,\nbut I am leaning towards giving the user the ultimate choice on how they\nwant to format their output. (Maybe with dimmed plus symbol as default).\n\n--\nCheers,\nRafael Ascensão\n"},{"id":"359106","messageId":"20180927193559.GB6950@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20180927192804.GA27163@rigel","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-09-27T19:35:59Z","receivedAt":"2018-09-27T19:36:03Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 27, 2018 at 08:28:04PM +0100, Rafael Ascensão wrote:\n\n> On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:\n> > Do we want to limit this to git-branch, though? Ideally any output you\n> > get from git-branch could be replicated with for-each-ref (or with\n> > a custom \"branch --format\").\n> > \n> > I.e., could we have a format in ref-filter that matches HEAD, but\n> > returns a distinct symbol for a worktree HEAD? That would allow a few\n> > things:\n> \n> I was going to suggest using dim green and green for elsewhere and here\n> respectively, in a similar way how range-diff uses it to show different\n> versions of the same diff.\n\nYeah, I think that's reasonable, and would be enabled by the %(worktree)\nplaceholder I showed. Just like we do something like:\n\n  %(if)%(HEAD)%(then)* %(color:green)%(else)  %(end)\n\nnow, we could do:\n\n  %(if)%(HEAD)%(then)* %(color:bold green)\n  %(else)%(if)%(worktree)%(then)+ %(color:green)\n  %(else)  %(end)%(end)\n\n(respecting the user's color config, of course, rather than hard-coded\ncolors).\n\nTrying that out, though, I'm not sure if we properly support nested\nif's. That might be a bug we have to fix first.\n\n> But if we're open to change how branches are displayed maybe a config\n> option like branch.format (probably not the best name choice) that can\n> be set to the 'for-each-ref --format' syntax would be way more flexible.\n\nWe have that already, don't we?\n\n> I think the different symbol and dimmed color would be a nice addition,\n> but I am leaning towards giving the user the ultimate choice on how they\n> want to format their output. (Maybe with dimmed plus symbol as default).\n\nDefinitely.\n\n-Peff\n"},{"id":"359108","messageId":"20180927194150.GA7452@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20180927193559.GB6950@sigill.intra.peff.net","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-09-27T19:41:50Z","receivedAt":"2018-09-27T19:41:53Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 27, 2018 at 03:35:59PM -0400, Jeff King wrote:\n\n> now, we could do:\n> \n>   %(if)%(HEAD)%(then)* %(color:bold green)\n>   %(else)%(if)%(worktree)%(then)+ %(color:green)\n>   %(else)  %(end)%(end)\n> \n> (respecting the user's color config, of course, rather than hard-coded\n> colors).\n> \n> Trying that out, though, I'm not sure if we properly support nested\n> if's. That might be a bug we have to fix first.\n\nSorry, false alarm. I just had a typo in my format.\n\nThis seems to work with the patch I posted earlier:\n\n  git for-each-ref \\\n    --format='%(if)%(HEAD)%(then)* %(color:bold green)%(else)%(if)%(worktree)%(then)+ %(color:green)%(else) %(end)%(end)%(refname)' \\\n  refs/heads\n\nIt sure would be nice if there was a way to insert line breaks without\nimpacting the output. ;)\n\n-Peff\n"},{"id":"359110","messageId":"87pnwyiu8k.fsf@evledraar.gmail.com","threadId":"49438","inReplyTo":"20180927192804.GA27163@rigel","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-09-27T20:02:51Z","receivedAt":"2018-09-27T20:02:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Sep 27 2018, Rafael Ascensão wrote:\n\n> On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:\n>> Do we want to limit this to git-branch, though? Ideally any output you\n>> get from git-branch could be replicated with for-each-ref (or with\n>> a custom \"branch --format\").\n>>\n>> I.e., could we have a format in ref-filter that matches HEAD, but\n>> returns a distinct symbol for a worktree HEAD? That would allow a few\n>> things:\n>\n> I was going to suggest using dim green and green for elsewhere and here\n> respectively, in a similar way how range-diff uses it to show different\n> versions of the same diff.\n\nIt would be really useful to (just via E-Mail to start) itemize the\ncolors we use in various places and what they mean.\n\nE.g. I thought green here made sense because in \"diff\" we show the\nold/new as red/green, so the branch you're on is \"new\" in the same\nsense, i.e. it's what your current state is.\n\nBut maybe there's cases where that doesn't \"rhyme\" as it were.\n"},{"id":"359112","messageId":"CAC05385d=1s_qidC4uLdRAqUNaP7jwYTjfxHtGrmBDJ54F8pRA@mail.gmail.com","threadId":"49438","inReplyTo":"87pnwyiu8k.fsf@evledraar.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-09-27T20:16:19Z","receivedAt":"2018-09-27T20:16:48Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"Not to hijack my own thread, but FWIW git branch -r shows remote\nbranches in red, but old/new status of a remote branch is ambiguous\n(could have new stuff, could be out of date). Also, git branch -vv\nshows remote tracking branches in blue. One could argue it should be\nred since git branch -r is in red.\n\nBut yea, probably best to take this topic to its own thread.\nOn Thu, Sep 27, 2018 at 1:02 PM Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n>\n> On Thu, Sep 27 2018, Rafael Ascensão wrote:\n>\n> > On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:\n> >> Do we want to limit this to git-branch, though? Ideally any output you\n> >> get from git-branch could be replicated with for-each-ref (or with\n> >> a custom \"branch --format\").\n> >>\n> >> I.e., could we have a format in ref-filter that matches HEAD, but\n> >> returns a distinct symbol for a worktree HEAD? That would allow a few\n> >> things:\n> >\n> > I was going to suggest using dim green and green for elsewhere and here\n> > respectively, in a similar way how range-diff uses it to show different\n> > versions of the same diff.\n>\n> It would be really useful to (just via E-Mail to start) itemize the\n> colors we use in various places and what they mean.\n>\n> E.g. I thought green here made sense because in \"diff\" we show the\n> old/new as red/green, so the branch you're on is \"new\" in the same\n> sense, i.e. it's what your current state is.\n>\n> But maybe there's cases where that doesn't \"rhyme\" as it were.\n"},{"id":"359116","messageId":"20180927204049.GA2628@rigel","threadId":"49438","inReplyTo":"CAC05385d=1s_qidC4uLdRAqUNaP7jwYTjfxHtGrmBDJ54F8pRA@mail.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Rafael Ascensão","fromEmail":"rafa.almas@gmail.com","sentAt":"2018-09-27T20:40:49Z","receivedAt":"2018-09-27T20:41:05Z","isPatch":true,"sender":{"key":"rafa.almas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923789?v=4"},"body":"On Thu, Sep 27, 2018 at 01:16:19PM -0700, Nickolai Belakovski wrote:\n>\n> Not to hijack my own thread, but FWIW git branch -r shows remote\n> branches in red, but old/new status of a remote branch is ambiguous\n> (could have new stuff, could be out of date). Also, git branch -vv\n> shows remote tracking branches in blue. One could argue it should be\n> red since git branch -r is in red.\n>\n\nFor me remote branches being red means: they're here but you cannot\nwrite to them. They are like 'read-only/disabled' branches. Under this\ninterpretation red makes sense.\n\n\nOn Thu, Sep 27, 2018 at 9:02 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>\n> E.g. I thought green here made sense because in \"diff\" we show the\n> old/new as red/green, so the branch you're on is \"new\" in the same\n> sense, i.e. it's what your current state is.\n>\n\nI still defend using green and dim green for this case. Because all\nthese worktrees are in a sense active. They're checked out in some\nplace. It's just the case that the particular one that we are in is\nprobably more relevant than the others.\n\n--\nCheers\nRafael Ascensão\n"},{"id":"359121","messageId":"xmqqo9cifxee.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20180927194150.GA7452@sigill.intra.peff.net","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-27T21:22:49Z","receivedAt":"2018-09-27T21:22:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Sep 27, 2018 at 03:35:59PM -0400, Jeff King wrote:\n>\n>> now, we could do:\n>> \n>>   %(if)%(HEAD)%(then)* %(color:bold green)\n>>   %(else)%(if)%(worktree)%(then)+ %(color:green)\n>>   %(else)  %(end)%(end)\n>> \n>> (respecting the user's color config, of course, rather than hard-coded\n>> colors).\n>> \n>> Trying that out, though, I'm not sure if we properly support nested\n>> if's. That might be a bug we have to fix first.\n>\n> Sorry, false alarm. I just had a typo in my format.\n>\n> This seems to work with the patch I posted earlier:\n>\n>   git for-each-ref \\\n>     --format='%(if)%(HEAD)%(then)* %(color:bold green)%(else)%(if)%(worktree)%(then)+ %(color:green)%(else) %(end)%(end)%(refname)' \\\n>   refs/heads\n>\n> It sure would be nice if there was a way to insert line breaks without\n> impacting the output. ;)\n>\n> -Peff\n\nI envy all of you who seem to have had a lot of fun while I was\ndoing something else (which were rather boring but still needed\nprecision--my least favorite kind of task X-<).\n\nThe only comment I have is that I strongly suspect we will regret if\nwe used an overly bland \"worktree\" to a rather narrrow \"is this ref\nchecked out in any worktree?\" when we notice we want to learn other\nthings that are related to \"worktree\".  Other than that, very nicely\ndone.\n"},{"id":"359123","messageId":"20180927213511.GB2628@rigel","threadId":"49438","inReplyTo":"20180927193559.GB6950@sigill.intra.peff.net","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Rafael Ascensão","fromEmail":"rafa.almas@gmail.com","sentAt":"2018-09-27T21:35:11Z","receivedAt":"2018-09-27T21:35:18Z","isPatch":true,"sender":{"key":"rafa.almas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923789?v=4"},"body":"On Thu, Sep 27, 2018 at 03:35:59PM -0400, Jeff King wrote:\n> On Thu, Sep 27, 2018 at 08:28:04PM +0100, Rafael Ascensão wrote:\n> > But if we're open to change how branches are displayed maybe a config\n> > option like branch.format (probably not the best name choice) that can\n> > be set to the 'for-each-ref --format' syntax would be way more flexible.\n> \n> We have that already, don't we?\n>\n\ngit branch has --format, but there's no way (at least to my knowledge)\nto define a value in gitconfig to be used by $git branch.\n\nHaving branch --format available, making an alias is a possible route.\n(Either by wrapping branch --format or for-each-ref itself). But I was\nreferring to changing the output of the default $git branch;\n\n"},{"id":"359168","messageId":"20180928010514.GB11281@sigill.intra.peff.net","threadId":"49438","inReplyTo":"xmqqo9cifxee.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-09-28T01:05:14Z","receivedAt":"2018-09-28T01:05:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 27, 2018 at 02:22:49PM -0700, Junio C Hamano wrote:\n\n> The only comment I have is that I strongly suspect we will regret if\n> we used an overly bland \"worktree\" to a rather narrrow \"is this ref\n> checked out in any worktree?\" when we notice we want to learn other\n> things that are related to \"worktree\".  Other than that, very nicely\n> done.\n\nYeah, I should have mentioned that. %(worktree) was just a placeholder.\nPerhaps something like %(worktree-HEAD) would make more sense (the idea\nis that it is an extension of the existing %(HEAD) placeholder).\n\nAlternatively, %(HEAD) could return \"*\" or \"+\" depending on whether it's\nthe current worktree head. That would mildly break an existing format\nlike:\n\n  %(if)%(HEAD)%(then) *%(color:green)%(end)%(refname)\n\nsince it would start coloring worktree HEADs the same way. It would be\nrewritten as:\n\n  %(if:equals=*)%(HEAD)%(then)...real HEAD...\n  %(else)%(if:equals=+)%(HEAD)%(then)...worktree HEAD...\n  %(else)...regular ref...\n  %(end)%(end)\n\nI think that's perhaps nicer, but I'm not sure we want even such a minor\nregression.\n\n-Peff\n"},{"id":"359169","messageId":"20180928010759.GC11281@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20180927213511.GB2628@rigel","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-09-28T01:07:59Z","receivedAt":"2018-09-28T01:08:03Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Sep 27, 2018 at 10:35:11PM +0100, Rafael Ascensão wrote:\n\n> git branch has --format, but there's no way (at least to my knowledge)\n> to define a value in gitconfig to be used by $git branch.\n\nOh, you're right. I was thinking of the branch.sort we just added in\nv2.19.\n\nI agree that having branch.format (and a matching tag.format) would be\nuseful.\n\n-Peff\n"},{"id":"359173","messageId":"xmqqsh1ue7gl.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20180928010514.GB11281@sigill.intra.peff.net","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-09-28T01:28:26Z","receivedAt":"2018-09-28T01:28:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Alternatively, %(HEAD) could return \"*\" or \"+\" depending on whether it's\n> the current worktree head. That would mildly break an existing format\n> like:\n>\n>   %(if)%(HEAD)%(then) *%(color:green)%(end)%(refname)\n>\n> since it would start coloring worktree HEADs the same way. It would be\n> rewritten as:\n>\n>   %(if:equals=*)%(HEAD)%(then)...real HEAD...\n>   %(else)%(if:equals=+)%(HEAD)%(then)...worktree HEAD...\n>   %(else)...regular ref...\n>   %(end)%(end)\n>\n> I think that's perhaps nicer, but I'm not sure we want even such a minor\n> regression.\n\nI tend to think it is not worth having to worry about it by changing\nthe meaning of %(HEAD) marking to save the effort to find a new\ntoken to fill that placeholder.  Your %(worktreeHEAD) is good\nenough, I would think.\n"},{"id":"359466","messageId":"nycvar.QRO.7.76.6.1810022234350.2034@tvgsbejvaqbjf.bet","threadId":"49438","inReplyTo":"87sh1uizxp.fsf@evledraar.gmail.com","subject":"Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2018-10-02T20:41:39Z","receivedAt":"2018-10-02T20:41:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Ævar,\n\nOn Thu, 27 Sep 2018, Ævar Arnfjörð Bjarmason wrote:\n\n> On Thu, Sep 27 2018, Nickolai Belakovski wrote:\n> \n> > Will do re: screenshot when I get home, although it's pretty easy to\n> > imagine, the git branch output will have one other branch colored in green,\n> > bit without the asterisk (for one linked worktree) :)\n> >\n> > Also will do re: changing comments to /**/ (didn't know // was from C++,\n> > TIL) and I'll clean up the comments to remove some of the more obvious\n> > ones, but I'll try to keep a comment explaining the basic flow of creating\n> > a nest if statement to evaluate worktree refs for color.\n> >\n> > And yes, I copy/pasted into gmail. I was having trouble setting up\n> > send-email, but I think I may have it figured out now. Should I create a\n> > new thread with send-email? Or maybe reply to this one (I can do that by\n> > specifying the Message-ID to reply to right?\n> \n> You'd run git format-patch master..your-topic with\n> --subject-prefix=\"PATCH v2\" and\n> --in-reply-to=\"<CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com>\". Then\n> it'll show up in reply to your v1.\n\nThere is also a nice tutorial in\nhttps://github.com/git-for-windows/git/blob/master/CONTRIBUTING.md#submit-your-patch\n(which, contrary to the location, is useful for non-Windows developers,\ntoo.)\n\n> You can also for an easier experience do this via GitGitGadget, see\n> https://github.com/gitgitgadget/gitgitgadget looking at its code it\n> seems to have some way to reference a Message-ID, but I don't know how\n> to trigger that.\n\nIIRC GitGitGadget has no facility yet to reply to any mail it did not\ngenerate itself (i.e. if you did not generate v1 using GitGitGadget, then\nit cannot generate a v2 that replies to the previous iteration).\n\nThis might change at some stage, but I have other priorities for now.\n(Which should not stop any contributor from opening a PR to scratch their\nown favorite itch.)\n\nCiao,\nJohannes\n\n> \n> > This is my first time using this workflow, so I appreciate your\n> > patience :) )?\n> \n> No worries, happy to help.\n> \n> > On Thu, Sep 27, 2018 at 8:33 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> > wrote:\n> >\n> >>\n> >> On Thu, Sep 27 2018, Nickolai Belakovski wrote:\n> >>\n> >> > In order to more clearly display which branches are active, the output\n> >> > of git branch is modified to colorize branches checked out in any linked\n> >> > worktrees with the same color as the current branch.\n> >> >\n> >> > This is meant to simplify workflows related to worktree, particularly\n> >> > due to the limitations of not being able to check out the same branch in\n> >> > two worktrees and the inability to delete a branch checked out in a\n> >> > worktree. When performing branch operations like checkout and delete, it\n> >> > would be useful to know more readily if the branches in which the user\n> >> > is interested are already checked out in a worktree.\n> >> >\n> >> > The git worktree list command contains the relevant information, however\n> >> > this is a much less frquently used command than git branch.\n> >> >\n> >> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n> >>\n> >> Sounds cool, b.t.w. would be neat-o to have some screenshot uploaded to\n> >> imgur or whatever just to skim what it looks like before/after.\n> >>\n> >> > diff --git a/builtin/branch.c b/builtin/branch.c\n> >> > index 4fc55c350..65b58ff7c 100644\n> >> > --- a/builtin/branch.c\n> >> > +++ b/builtin/branch.c\n> >> > @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter\n> >> > *filter, int maxwidth, const char *r\n> >> >         struct strbuf local = STRBUF_INIT;\n> >> >         struct strbuf remote = STRBUF_INIT;\n> >> >\n> >> > -       strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)\n> >> %s%%(end)\",\n> >> > -                   branch_get_color(BRANCH_COLOR_CURRENT),\n> >> > -                   branch_get_color(BRANCH_COLOR_LOCAL));\n> >> > -       strbuf_addf(&remote, \"  %s\",\n> >> > -                   branch_get_color(BRANCH_COLOR_REMOTE));\n> >> > +       // Prepend the current branch of this worktree with \"* \" and\n> >> > all other branches with \"  \"\n> >>\n> >>\n> >> We use /* ... */ C comments, not C++-style // (well, it's in C now, but\n> >> not the ancient versions we need to support).\n> >>\n> >> It also seems all of this patch was copy/pasted into GMail or something,\n> >> it has wrapping and doesn't apply with \"git am\".\n> >>\n> >> Also most/all of these comments I'd say we could better do without,\n> >> i.e. the ones explaining basic code flow that's easy to see from the\n> >> code itself.\n> >>\n> "},{"id":"362951","messageId":"20181111235831.44824-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20180927204049.GA2628@rigel","subject":"[PATCH v2 0/2] refactoring branch colorization to ref-filter","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-11-11T23:58:29Z","receivedAt":"2018-11-11T23:58:40Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nFinally found some time to follow up on this :)\n\nI decided to take the approach suggested by Peff for simplicity. I have\nanother version which uses a hash map to store *all* of the information\nreturned by get_worktrees, information which can then be accessed in\nthe fashion %(workree:path) or %(worktree:is_detached), but it seemed\nlike a lot of code to add and there was no use case to justify the\naddition of a hash map at this time. If there's interest though, I can\nmake a separate patch after this one to introduce those changes. They\nbuild directly off of the changes introduced here.\n\nI've split this work into two commits since the items are logically\nseparate.\n\nCI results: https://travis-ci.org/nbelakovski/git/builds/453723727\n\nNickolai Belakovski (2):\n  ref-filter: add worktree atom\n  branch: Mark and colorize a branch differently if it is checked out in\n    a linked worktree\n\n builtin/branch.c               | 22 +++++++++++++---------\n color.h                        | 18 ++++++++++++++++++\n ref-filter.c                   | 31 +++++++++++++++++++++++++++++++\n t/t3200-branch.sh              |  8 ++++----\n t/t3203-branch-output.sh       | 21 +++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh | 15 +++++++++++++++\n t/test-lib-functions.sh        |  6 ++++++\n 7 files changed, 108 insertions(+), 13 deletions(-)\n\n-- \n2.14.2\n\n"},{"id":"362952","messageId":"20181111235831.44824-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181111235831.44824-1-nbelakovski@gmail.com","subject":"[PATCH v2 1/2] ref-filter: add worktree atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-11-11T23:58:30Z","receivedAt":"2018-11-11T23:58:45Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom expressing whether the particular ref is checked out in a\nlinked worktree.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n ref-filter.c                   | 31 +++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh | 15 +++++++++++++++\n 2 files changed, 46 insertions(+)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 0c45ed9d94..53e2504f5d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,7 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -114,6 +115,7 @@ static struct used_atom {\n \t\t} objectname;\n \t\tstruct refname_atom refname;\n \t\tchar *head;\n+\t\tstruct string_list worktree_heads;\n \t} u;\n } *used_atom;\n static int used_atom_cnt, need_tagged, need_symref;\n@@ -420,6 +422,28 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n \treturn 0;\n }\n \n+static int worktree_head_atom_parser(const struct ref_format *format,\n+\t\t\t\t\t\t\t\t\t struct used_atom *atom,\n+\t\t\t\t\t\t\t\t\t const char *arg,\n+\t\t\t\t\t\t\t\t\t struct strbuf *unused_err)\n+{\n+\tstruct worktree **worktrees = get_worktrees(0);\n+\tint i;\n+\n+\tstring_list_init(&atom->u.worktree_heads, 1);\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref)\n+\t\t\tstring_list_append(&atom->u.worktree_heads,\n+\t\t\t\t\t\t\t   worktrees[i]->head_ref);\n+\t}\n+\n+\tstring_list_sort(&atom->u.worktree_heads);\n+\n+\tfree_worktrees(worktrees);\n+\treturn 0;\n+}\n+\n static struct {\n \tconst char *name;\n \tinfo_source source;\n@@ -461,6 +485,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktree\", SOURCE_NONE, FIELD_STR, worktree_head_atom_parser },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1594,6 +1619,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \t\t\telse\n \t\t\t\tv->s = xstrdup(\" \");\n \t\t\tcontinue;\n+\t\t} else if (!strcmp(name, \"worktree\")) {\n+\t\t\tif (string_list_has_string(&atom->u.worktree_heads, ref->refname))\n+\t\t\t\tv->s = xstrdup(\"+\");\n+\t\t\telse\n+\t\t\t\tv->s = xstrdup(\" \");\n+\t\t\tcontinue;\n \t\t} else if (starts_with(name, \"align\")) {\n \t\t\tv->handler = align_atom_handler;\n \t\t\tv->s = xstrdup(\"\");\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..5e6d249d4c 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-\\EOF &&\n+\tmaster: checked out in a worktree\n+\tmaster_worktree: checked out in a worktree\n+\tside: not checked out in a worktree\n+EOF\n+    git for-each-ref --format=\"%(refname:short): %(if)%(worktree)%(then)checked out in a worktree%(else)not checked out in a worktree%(end)\" refs/heads/ >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"362953","messageId":"20181111235831.44824-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181111235831.44824-1-nbelakovski@gmail.com","subject":"[PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-11-11T23:58:31Z","receivedAt":"2018-11-11T23:58:47Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nIn order to more clearly display which branches are active, the output\nof git branch is modified to mark branches checkout out in a linked\nworktree with a \"+\" and color them in a faint light green (in contrast\nto the current branch, which will still be denoted with a \"*\" and\ncolored in green)\n\nThis is meant to simplify workflows related to worktree, particularly\ndue to the limitations of not being able to check out the same branch in\ntwo worktrees and the inability to delete a branch checked out in a\nworktree. When performing branch operations like checkout and delete, it\nwould be useful to know more readily if the branches in which the user\nis interested are already checked out in a worktree.\n\nThe git worktree list command contains the relevant information, however\nthis is a much less frquently used command than git branch.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n builtin/branch.c         | 22 +++++++++++++---------\n color.h                  | 18 ++++++++++++++++++\n t/t3200-branch.sh        |  8 ++++----\n t/t3203-branch-output.sh | 21 +++++++++++++++++++++\n t/test-lib-functions.sh  |  6 ++++++\n 5 files changed, 62 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0c55f7f065..34f44c82d7 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -42,11 +42,12 @@ static struct object_id head_oid;\n static int branch_use_color = -1;\n static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_RESET,\n-\tGIT_COLOR_NORMAL,       /* PLAIN */\n-\tGIT_COLOR_RED,          /* REMOTE */\n-\tGIT_COLOR_NORMAL,       /* LOCAL */\n-\tGIT_COLOR_GREEN,        /* CURRENT */\n-\tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_NORMAL,             /* PLAIN */\n+\tGIT_COLOR_RED,                /* REMOTE */\n+\tGIT_COLOR_NORMAL,             /* LOCAL */\n+\tGIT_COLOR_GREEN,              /* CURRENT */\n+\tGIT_COLOR_BLUE,               /* UPSTREAM */\n+\tGIT_COLOR_FAINT_LIGHT_GREEN,  /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktree)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/color.h b/color.h\nindex 98894d6a17..857653df73 100644\n--- a/color.h\n+++ b/color.h\n@@ -42,6 +42,24 @@ struct strbuf;\n #define GIT_COLOR_FAINT_BLUE\t\"\\033[2;34m\"\n #define GIT_COLOR_FAINT_MAGENTA\t\"\\033[2;35m\"\n #define GIT_COLOR_FAINT_CYAN\t\"\\033[2;36m\"\n+#define GIT_COLOR_LIGHT_RED\t\"\\033[91m\"\n+#define GIT_COLOR_LIGHT_GREEN\t\"\\033[92m\"\n+#define GIT_COLOR_LIGHT_YELLOW\t\"\\033[93m\"\n+#define GIT_COLOR_LIGHT_BLUE\t\"\\033[94m\"\n+#define GIT_COLOR_LIGHT_MAGENTA\t\"\\033[95m\"\n+#define GIT_COLOR_LIGHT_CYAN\t\"\\033[96m\"\n+#define GIT_COLOR_BOLD_LIGHT_RED\t\"\\033[1;91m\"\n+#define GIT_COLOR_BOLD_LIGHT_GREEN\t\"\\033[1;92m\"\n+#define GIT_COLOR_BOLD_LIGHT_YELLOW\t\"\\033[1;93m\"\n+#define GIT_COLOR_BOLD_LIGHT_BLUE\t\"\\033[1;94m\"\n+#define GIT_COLOR_BOLD_LIGHT_MAGENTA\t\"\\033[1;95m\"\n+#define GIT_COLOR_BOLD_LIGHT_CYAN\t\"\\033[1;96m\"\n+#define GIT_COLOR_FAINT_LIGHT_RED\t\"\\033[2;91m\"\n+#define GIT_COLOR_FAINT_LIGHT_GREEN\t\"\\033[2;92m\"\n+#define GIT_COLOR_FAINT_LIGHT_YELLOW\t\"\\033[2;93m\"\n+#define GIT_COLOR_FAINT_LIGHT_BLUE\t\"\\033[2;94m\"\n+#define GIT_COLOR_FAINT_LIGHT_MAGENTA\t\"\\033[2;95m\"\n+#define GIT_COLOR_FAINT_LIGHT_CYAN\t\"\\033[2;96m\"\n #define GIT_COLOR_BG_RED\t\"\\033[41m\"\n #define GIT_COLOR_BG_GREEN\t\"\\033[42m\"\n #define GIT_COLOR_BG_YELLOW\t\"\\033[43m\"\ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..e404f6e23c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '\n test_expect_success 'git branch --column' '\n \tCOLUMNS=81 git branch --column=column >actual &&\n \tcat >expected <<\\EOF &&\n-  a/b/c     bam       foo       l       * master    n         o/p       r\n+  a/b/c   + bam       foo       l       * master    n         o/p       r\n   abc       bar       j/k       m/m       master2   o/o       q\n EOF\n \ttest_cmp expected actual\n@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '\n \tcat >expected <<EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\n@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '\n \tgit config --unset column.branch &&\n \tgit config --unset column.ui &&\n \tcat >expected <<\\EOF &&\n-  a/b/c   bam   foo   l   * master    n     o/p   r\n+  a/b/c + bam   foo   l   * master    n     o/p   r\n   abc     bar   j/k   m/m   master2   o/o   q\n EOF\n \ttest_cmp expected actual\n@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '\n \tcat >expected <<\\EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614c..06771fac64 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n++ <FAINT;LGREEN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+\ttest_terminal git branch >actual.raw &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\ndiff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh\nindex 78d8c3783b..2831a42a88 100644\n--- a/t/test-lib-functions.sh\n+++ b/t/test-lib-functions.sh\n@@ -61,6 +61,12 @@ test_decode_color () {\n \t\t\tif (n == 45) return \"BMAGENTA\";\n \t\t\tif (n == 46) return \"BCYAN\";\n \t\t\tif (n == 47) return \"BWHITE\";\n+\t\t\tif (n == 91) return \"LRED\";\n+\t\t\tif (n == 92) return \"LGREEN\";\n+\t\t\tif (n == 93) return \"LYELLOW\";\n+\t\t\tif (n == 94) return \"LBLUE\";\n+\t\t\tif (n == 95) return \"LMAGENTA\";\n+\t\t\tif (n == 96) return \"LCYAN\";\n \t\t}\n \t\t{\n \t\t\twhile (match($0, /\\033\\[[0-9;]*m/) != 0) {\n-- \n2.14.2\n\n"},{"id":"362982","messageId":"xmqqsh061u7o.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20181111235831.44824-2-nbelakovski@gmail.com","subject":"Re: [PATCH v2 1/2] ref-filter: add worktree atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-12T10:11:23Z","receivedAt":"2018-11-12T10:11:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n>  \n> +static int worktree_head_atom_parser(const struct ref_format *format,\n> +\t\t\t\t\t\t\t\t\t struct used_atom *atom,\n> +\t\t\t\t\t\t\t\t\t const char *arg,\n> +\t\t\t\t\t\t\t\t\t struct strbuf *unused_err)\n\nThis and ...\n\n> +{\n> +\tstruct worktree **worktrees = get_worktrees(0);\n> +\tint i;\n> +\n> +\tstring_list_init(&atom->u.worktree_heads, 1);\n> +\n> +\tfor (i = 0; worktrees[i]; i++) {\n> +\t\tif (worktrees[i]->head_ref)\n> +\t\t\tstring_list_append(&atom->u.worktree_heads,\n> +\t\t\t\t\t\t\t   worktrees[i]->head_ref);\n\n... this makes me suspect that you are using tabstop != 8 and that\nis causing you to indent these lines overly deeply.\n\nPlease don't, while working on this codebase.\n\n\n> +\t}\n> +\n> +\tstring_list_sort(&atom->u.worktree_heads);\n> +\n> +\tfree_worktrees(worktrees);\n> +\treturn 0;\n> +}\n\nSo..., this function collects any and all branches that are checked\nout in some worktree, and sort them _without_ dedup.  The user of\nthe resulting information (i.e. atom->u.worktree_heads) cannot tell\nwhere each of the listed branches is checked out.\n\nI wonder if \"The worktree at /local/src/wt1 has this branch checked\nout\" is something the user of %(worktree) atom, or a variant thereof\ne.g. \"%(worktree:detailed)\", may want to learn, but because that\ninformation is lost when this function returns, such an enhancement\ncannot be done without fixing this funciton.\n\nAlso, I am not sure if this \"list of some info on worktrees\" really\nbelongs to an individual atom.  For one thing, if a format includes\nmore than one instance of %(worktree) atoms, you'd iterate over the\nworktrees as many times as the number of these atoms you have.  Is\nthere another existing atom that \"caches\" expensive piece of\ninformation per used_atom[] element like this one?  Essentially I am\ntrying to convince myself that the approach taken by the patch is a\nsane one by finding a precedent.\n\n> +\t\t} else if (!strcmp(name, \"worktree\")) {\n> +\t\t\tif (string_list_has_string(&atom->u.worktree_heads, ref->refname))\n\nI thought we were moving towards killing the use of string_list as a\nlook-up table, as we do not want to see thoughtless copy&paste such\na code from parts of the code that are not performance critical to a\npart.  Not very satisfying.\n\n\tI think we can let this pass, and later add a wrapper around\n\thashmap that is meant to only be used to replace string-list\n\tused for this exact purpose, i.e. key is a string, and there\n\tis no need to iterate over the existing elements in any\n\tsorted order.  Optionally, we can limit the look up to only\n\tchecking for existence, if it makes the code for the wrapper\n\tsimpler.\n\n> +\t\t\t\tv->s = xstrdup(\"+\");\n> +\t\t\telse\n> +\t\t\t\tv->s = xstrdup(\" \");\n> +\t\t\tcontinue;\n>  \t\t} else if (starts_with(name, \"align\")) {\n>  \t\t\tv->handler = align_atom_handler;\n>  \t\t\tv->s = xstrdup(\"\");\n> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\n> index fc067ed672..5e6d249d4c 100755\n> --- a/t/t6302-for-each-ref-filter.sh\n> +++ b/t/t6302-for-each-ref-filter.sh\n> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n>  \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n>  '\n>  \n> +test_expect_success '\"add\" a worktree' '\n> +\tmkdir worktree_dir &&\n> +\tgit worktree add -b master_worktree worktree_dir master\n> +'\n> +\n> +test_expect_success 'validate worktree atom' '\n> +\tcat >expect <<-\\EOF &&\n> +\tmaster: checked out in a worktree\n> +\tmaster_worktree: checked out in a worktree\n> +\tside: not checked out in a worktree\n\nAs you started the here-doc with <<-, the next line EOF does not\nhave to be flushed to the left.  Indent it just the same way with a\ntab.\n\n> +EOF\n\nThe following line begins with a broken indentation, it seems.\n\n> +    git for-each-ref --format=\"%(refname:short): %(if)%(worktree)%(then)checked out in a worktree%(else)not checked out in a worktree%(end)\" refs/heads/ >actual &&\n> +\ttest_cmp expect actual\n> +'\n> +\n>  test_done\n"},{"id":"362983","messageId":"xmqqo9au1tsj.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20181111235831.44824-3-nbelakovski@gmail.com","subject":"Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-12T10:20:28Z","receivedAt":"2018-11-12T10:20:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> diff --git a/color.h b/color.h\n> index 98894d6a17..857653df73 100644\n> --- a/color.h\n> +++ b/color.h\n> @@ -42,6 +42,24 @@ struct strbuf;\n>  #define GIT_COLOR_FAINT_BLUE\t\"\\033[2;34m\"\n>  #define GIT_COLOR_FAINT_MAGENTA\t\"\\033[2;35m\"\n>  #define GIT_COLOR_FAINT_CYAN\t\"\\033[2;36m\"\n> +#define GIT_COLOR_LIGHT_RED\t\"\\033[91m\"\n> +#define GIT_COLOR_LIGHT_GREEN\t\"\\033[92m\"\n> +#define GIT_COLOR_LIGHT_YELLOW\t\"\\033[93m\"\n> +#define GIT_COLOR_LIGHT_BLUE\t\"\\033[94m\"\n> +#define GIT_COLOR_LIGHT_MAGENTA\t\"\\033[95m\"\n> +#define GIT_COLOR_LIGHT_CYAN\t\"\\033[96m\"\n> +#define GIT_COLOR_BOLD_LIGHT_RED\t\"\\033[1;91m\"\n> +#define GIT_COLOR_BOLD_LIGHT_GREEN\t\"\\033[1;92m\"\n> +#define GIT_COLOR_BOLD_LIGHT_YELLOW\t\"\\033[1;93m\"\n> +#define GIT_COLOR_BOLD_LIGHT_BLUE\t\"\\033[1;94m\"\n> +#define GIT_COLOR_BOLD_LIGHT_MAGENTA\t\"\\033[1;95m\"\n> +#define GIT_COLOR_BOLD_LIGHT_CYAN\t\"\\033[1;96m\"\n> +#define GIT_COLOR_FAINT_LIGHT_RED\t\"\\033[2;91m\"\n> +#define GIT_COLOR_FAINT_LIGHT_GREEN\t\"\\033[2;92m\"\n> +#define GIT_COLOR_FAINT_LIGHT_YELLOW\t\"\\033[2;93m\"\n> +#define GIT_COLOR_FAINT_LIGHT_BLUE\t\"\\033[2;94m\"\n> +#define GIT_COLOR_FAINT_LIGHT_MAGENTA\t\"\\033[2;95m\"\n> +#define GIT_COLOR_FAINT_LIGHT_CYAN\t\"\\033[2;96m\"\n\nHopefully you made sure that there is no other topic in-flight that\ntouch this area before doing this change?  Otherwise you'd be\ncreating pointless merge conflict by futzing with spaces.\n\nDitto for an earlier hunk of this patch.\n\nThanks.\n"},{"id":"362996","messageId":"20181112121423.GA3956@sigill.intra.peff.net","threadId":"49438","inReplyTo":"xmqqo9au1tsj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-12T12:14:23Z","receivedAt":"2018-11-12T12:14:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 12, 2018 at 07:20:28PM +0900, Junio C Hamano wrote:\n\n> nbelakovski@gmail.com writes:\n> \n> > diff --git a/color.h b/color.h\n> > index 98894d6a17..857653df73 100644\n> > --- a/color.h\n> > +++ b/color.h\n> > @@ -42,6 +42,24 @@ struct strbuf;\n> >  #define GIT_COLOR_FAINT_BLUE\t\"\\033[2;34m\"\n> >  #define GIT_COLOR_FAINT_MAGENTA\t\"\\033[2;35m\"\n> >  #define GIT_COLOR_FAINT_CYAN\t\"\\033[2;36m\"\n> > +#define GIT_COLOR_LIGHT_RED\t\"\\033[91m\"\n> > +#define GIT_COLOR_LIGHT_GREEN\t\"\\033[92m\"\n> > +#define GIT_COLOR_LIGHT_YELLOW\t\"\\033[93m\"\n> > +#define GIT_COLOR_LIGHT_BLUE\t\"\\033[94m\"\n> > +#define GIT_COLOR_LIGHT_MAGENTA\t\"\\033[95m\"\n> > +#define GIT_COLOR_LIGHT_CYAN\t\"\\033[96m\"\n> > +#define GIT_COLOR_BOLD_LIGHT_RED\t\"\\033[1;91m\"\n> > +#define GIT_COLOR_BOLD_LIGHT_GREEN\t\"\\033[1;92m\"\n> > +#define GIT_COLOR_BOLD_LIGHT_YELLOW\t\"\\033[1;93m\"\n> > +#define GIT_COLOR_BOLD_LIGHT_BLUE\t\"\\033[1;94m\"\n> > +#define GIT_COLOR_BOLD_LIGHT_MAGENTA\t\"\\033[1;95m\"\n> > +#define GIT_COLOR_BOLD_LIGHT_CYAN\t\"\\033[1;96m\"\n> > +#define GIT_COLOR_FAINT_LIGHT_RED\t\"\\033[2;91m\"\n> > +#define GIT_COLOR_FAINT_LIGHT_GREEN\t\"\\033[2;92m\"\n> > +#define GIT_COLOR_FAINT_LIGHT_YELLOW\t\"\\033[2;93m\"\n> > +#define GIT_COLOR_FAINT_LIGHT_BLUE\t\"\\033[2;94m\"\n> > +#define GIT_COLOR_FAINT_LIGHT_MAGENTA\t\"\\033[2;95m\"\n> > +#define GIT_COLOR_FAINT_LIGHT_CYAN\t\"\\033[2;96m\"\n> \n> Hopefully you made sure that there is no other topic in-flight that\n> touch this area before doing this change?  Otherwise you'd be\n> creating pointless merge conflict by futzing with spaces.\n\nThis hunk confused me for a minute, too. It's not changing spaces, but\njust adding a bunch of color variants. It would be nice if we could just\ndo this with a run-time parse_color(\"bold red\") or whatever, but we use\nthese as static initializers.\n\nWe don't strictly need anything more than FAINT_LIGHT_GREEN here. I\ndon't have a strong opinion on adding just what we need versus\nbeing more complete.\n\n> Ditto for an earlier hunk of this patch.\n\nYeah, I think this does apply to the earlier hunk that defines\nbranch_colors[].\n\n-Peff\n"},{"id":"362997","messageId":"20181112122245.GB3956@sigill.intra.peff.net","threadId":"49438","inReplyTo":"xmqqsh061u7o.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 1/2] ref-filter: add worktree atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-12T12:22:45Z","receivedAt":"2018-11-12T12:22:49Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 12, 2018 at 07:11:23PM +0900, Junio C Hamano wrote:\n\n> > +\t}\n> > +\n> > +\tstring_list_sort(&atom->u.worktree_heads);\n> > +\n> > +\tfree_worktrees(worktrees);\n> > +\treturn 0;\n> > +}\n> \n> So..., this function collects any and all branches that are checked\n> out in some worktree, and sort them _without_ dedup.  The user of\n> the resulting information (i.e. atom->u.worktree_heads) cannot tell\n> where each of the listed branches is checked out.\n> \n> I wonder if \"The worktree at /local/src/wt1 has this branch checked\n> out\" is something the user of %(worktree) atom, or a variant thereof\n> e.g. \"%(worktree:detailed)\", may want to learn, but because that\n> information is lost when this function returns, such an enhancement\n> cannot be done without fixing this funciton.\n\nHmm. I think for the purposes of this series we could jump straight to\nconverting %(worktree) to mean \"the path of the worktree for which this\nbranch is HEAD, or the empty string otherwise\".\n\nThen the caller from git-branch (or anybody wanting to emulate it) could\nstill do:\n\n  %(if)%(worktree)%(then)+ %(refname)%(end)\n\nAs a bonus, the decision to use \"+\" becomes a lot easier. It is no\nlonger a part of the format language that we must promise forever, but\nsimply a porcelain decision by git-branch.\n\n> Also, I am not sure if this \"list of some info on worktrees\" really\n> belongs to an individual atom.  For one thing, if a format includes\n> more than one instance of %(worktree) atoms, you'd iterate over the\n> worktrees as many times as the number of these atoms you have.  Is\n> there another existing atom that \"caches\" expensive piece of\n> information per used_atom[] element like this one?  Essentially I am\n> trying to convince myself that the approach taken by the patch is a\n> sane one by finding a precedent.\n\nYes, we faced this a bit with Olga's cat-file conversion patches (where\nwe had a shared struct object_info). There probably should just be a\nfile-global data-structure storing the worktree info once (in an ideal\nworld, it would be part of a \"struct ref_format\" that uses no global\nvariables, but that is not how the code is structured today).\n\n> > +\t\t} else if (!strcmp(name, \"worktree\")) {\n> > +\t\t\tif (string_list_has_string(&atom->u.worktree_heads, ref->refname))\n> \n> I thought we were moving towards killing the use of string_list as a\n> look-up table, as we do not want to see thoughtless copy&paste such\n> a code from parts of the code that are not performance critical to a\n> part.  Not very satisfying.\n> \n> \tI think we can let this pass, and later add a wrapper around\n> \thashmap that is meant to only be used to replace string-list\n> \tused for this exact purpose, i.e. key is a string, and there\n> \tis no need to iterate over the existing elements in any\n> \tsorted order.  Optionally, we can limit the look up to only\n> \tchecking for existence, if it makes the code for the wrapper\n> \tsimpler.\n\nThis came up over in another thread yesterday, too. So yeah, perhaps we\nshould move on that (I am OK punting on it for this series and\nconverting it later, though).\n\n-Peff\n"},{"id":"362998","messageId":"20181112122337.GC3956@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20181111235831.44824-2-nbelakovski@gmail.com","subject":"Re: [PATCH v2 1/2] ref-filter: add worktree atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-12T12:23:38Z","receivedAt":"2018-11-12T12:23:41Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Nov 11, 2018 at 03:58:30PM -0800, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> Add an atom expressing whether the particular ref is checked out in a\n> linked worktree.\n> \n> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n> ---\n>  ref-filter.c                   | 31 +++++++++++++++++++++++++++++++\n>  t/t6302-for-each-ref-filter.sh | 15 +++++++++++++++\n>  2 files changed, 46 insertions(+)\n\nI left some more comments elsewhere in the thread, but one more thing to\nnote: this probably needs to touch Documentation/git-for-each-ref.txt to\ndescribe the new placeholder.\n\n-Peff\n"},{"id":"363064","messageId":"20181112180549.ojt3twhsfm5xkako@rigel","threadId":"49438","inReplyTo":"20181112121423.GA3956@sigill.intra.peff.net","subject":"Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree","fromName":"Rafael Ascensão","fromEmail":"rafa.almas@gmail.com","sentAt":"2018-11-12T18:07:18Z","receivedAt":"2018-11-12T18:07:26Z","isPatch":true,"sender":{"key":"rafa.almas@gmail.com","avatar":"https://avatars.githubusercontent.com/u/1923789?v=4"},"body":"On Mon, Nov 12, 2018 at 07:14:23AM -0500, Jeff King wrote:\n> just adding a bunch of color variants. It would be nice if we could just\n> do this with a run-time parse_color(\"bold red\") or whatever, but we use\n> these as static initializers.\n\nI suggested those colors, but now, I think this needs to be\nconfigurable.\n\nI suggested using green and dim green as the obvious theoretical choice\nbut after using it for a while I found out that both shades are way too\nsimilar, making it really hard to tell by glancing at the output,\nespecially when they're not side by side.\n\nIf we continue with two dual green approach, current branch needs to be\nat least bold. But I'm not sure if it's enough.\n\nI've been trying some other colors, and cyan feels neutral-ish.\n\nI think:\n\n    GIT_COLOR_BOLD_GREEN  /* CURRENT */\n    GIT_COLOR_CYAN        /* WORKTREE */\n\nmakes an ok combination.\n\nBut I can see where personal preference starts to play a role here, as\nthe logical solution isn't good enough. Which makes the case for being\nable to configure a bit stronger.\n\nCheers,\nRafael Ascensão\n"},{"id":"363117","messageId":"xmqqd0r9zri6.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20181112122245.GB3956@sigill.intra.peff.net","subject":"Re: [PATCH v2 1/2] ref-filter: add worktree atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-13T01:38:09Z","receivedAt":"2018-11-13T01:38:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>> I wonder if \"The worktree at /local/src/wt1 has this branch checked\n>> out\" is something the user of %(worktree) atom, or a variant thereof\n>> e.g. \"%(worktree:detailed)\", may want to learn, but because that\n>> information is lost when this function returns, such an enhancement\n>> cannot be done without fixing this funciton.\n>\n> Hmm. I think for the purposes of this series we could jump straight to\n> converting %(worktree) to mean \"the path of the worktree for which this\n> branch is HEAD, or the empty string otherwise\".\n>\n> Then the caller from git-branch (or anybody wanting to emulate it) could\n> still do:\n>\n>   %(if)%(worktree)%(then)+ %(refname)%(end)\n>\n> As a bonus, the decision to use \"+\" becomes a lot easier. It is no\n> longer a part of the format language that we must promise forever, but\n> simply a porcelain decision by git-branch.\n\nYeah, thanks for following through the thought process to the\nlogical conclusion.  If a branch is multply checked out, which is a\ncondition \"git worktree\" and \"git checkout\" ought to prevent from\nhappening, we could leave the result unspecified but a non-empty\nstring, or something like that.\n\n> file-global data-structure storing the worktree info once (in an ideal\n> world, it would be part of a \"struct ref_format\" that uses no global\n> variables, but that is not how the code is structured today).\n\nYes, I agree that would be the ideal longer-term direction to move\nthis code in.\n\n>> > +\t\t} else if (!strcmp(name, \"worktree\")) {\n>> > +\t\t\tif (string_list_has_string(&atom->u.worktree_heads, ref->refname))\n>> \n>> I thought we were moving towards killing the use of string_list as a\n>> look-up table, as we do not want to see thoughtless copy&paste such\n>> a code from parts of the code that are not performance critical to a\n>> part.  Not very satisfying.\n>> \n>> \tI think we can let this pass, and later add a wrapper around\n>> \thashmap that is meant to only be used to replace string-list\n>> \tused for this exact purpose, i.e. key is a string, and there\n>> \tis no need to iterate over the existing elements in any\n>> \tsorted order.  Optionally, we can limit the look up to only\n>> \tchecking for existence, if it makes the code for the wrapper\n>> \tsimpler.\n>\n> This came up over in another thread yesterday, too. So yeah, perhaps we\n> should move on that (I am OK punting on it for this series and\n> converting it later, though).\n\nFWIW, I am OK punting and leaving, too.\n"},{"id":"363118","messageId":"xmqq5zx1zr5g.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20181112180549.ojt3twhsfm5xkako@rigel","subject":"Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-11-13T01:45:47Z","receivedAt":"2018-11-13T01:45:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Rafael Ascensão <rafa.almas@gmail.com> writes:\n\n> But I can see where personal preference starts to play a role here, as\n> the logical solution isn't good enough. Which makes the case for being\n> able to configure a bit stronger.\n\nYeah, our preference over time has always been \"do not add to our\ndefault color palette to make the default output too colourful;\ninstead allow the user to specify their choice\".  If this feature\ncan be added like that, that would be preferrable, and if cyan\n(which usuallly is used to present \"less interesting\" piece of\ninformation and in our default palette) works well enough, maybe we\nshould use that?\n"},{"id":"363159","messageId":"20181113144931.GC17454@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20181112180549.ojt3twhsfm5xkako@rigel","subject":"Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-13T14:49:31Z","receivedAt":"2018-11-13T14:49:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Nov 12, 2018 at 06:07:18PM +0000, Rafael Ascensão wrote:\n\n> On Mon, Nov 12, 2018 at 07:14:23AM -0500, Jeff King wrote:\n> > just adding a bunch of color variants. It would be nice if we could just\n> > do this with a run-time parse_color(\"bold red\") or whatever, but we use\n> > these as static initializers.\n> \n> I suggested those colors, but now, I think this needs to be\n> configurable.\n\nI think they are configurable in that patch, since it provides\n\"worktree\" as a n entry in color_branch_slots. But yeah, every color we\nadd needs to be configurable, and this is really just about defaults.\n\n> I suggested using green and dim green as the obvious theoretical choice\n> but after using it for a while I found out that both shades are way too\n> similar, making it really hard to tell by glancing at the output,\n> especially when they're not side by side.\n> \n> If we continue with two dual green approach, current branch needs to be\n> at least bold. But I'm not sure if it's enough.\n> \n> I've been trying some other colors, and cyan feels neutral-ish.\n\nYeah, cyan seems pretty reasonable to me.\n\n-Peff\n"},{"id":"363827","messageId":"CAC05387v6odwx3JTfJUR8tCxyqEEf7Z13ROgrLthc4rVLy3bJA@mail.gmail.com","threadId":"49438","inReplyTo":"xmqqd0r9zri6.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v2 1/2] ref-filter: add worktree atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-11-21T14:05:04Z","receivedAt":"2018-11-21T14:05:33Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"I think if we move to making this atom just store worktree path, that\nneeds to be implemented as a hashmap of refname->wtpath, which would\nalso solve this string_list issue, correct? Just making sure I'm not\nmissing something before I submit another patch.\nOn Tue, Nov 13, 2018 at 2:38 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Jeff King <peff@peff.net> writes:\n>\n> >> I wonder if \"The worktree at /local/src/wt1 has this branch checked\n> >> out\" is something the user of %(worktree) atom, or a variant thereof\n> >> e.g. \"%(worktree:detailed)\", may want to learn, but because that\n> >> information is lost when this function returns, such an enhancement\n> >> cannot be done without fixing this funciton.\n> >\n> > Hmm. I think for the purposes of this series we could jump straight to\n> > converting %(worktree) to mean \"the path of the worktree for which this\n> > branch is HEAD, or the empty string otherwise\".\n> >\n> > Then the caller from git-branch (or anybody wanting to emulate it) could\n> > still do:\n> >\n> >   %(if)%(worktree)%(then)+ %(refname)%(end)\n> >\n> > As a bonus, the decision to use \"+\" becomes a lot easier. It is no\n> > longer a part of the format language that we must promise forever, but\n> > simply a porcelain decision by git-branch.\n>\n> Yeah, thanks for following through the thought process to the\n> logical conclusion.  If a branch is multply checked out, which is a\n> condition \"git worktree\" and \"git checkout\" ought to prevent from\n> happening, we could leave the result unspecified but a non-empty\n> string, or something like that.\n>\n> > file-global data-structure storing the worktree info once (in an ideal\n> > world, it would be part of a \"struct ref_format\" that uses no global\n> > variables, but that is not how the code is structured today).\n>\n> Yes, I agree that would be the ideal longer-term direction to move\n> this code in.\n>\n> >> > +          } else if (!strcmp(name, \"worktree\")) {\n> >> > +                  if (string_list_has_string(&atom->u.worktree_heads, ref->refname))\n> >>\n> >> I thought we were moving towards killing the use of string_list as a\n> >> look-up table, as we do not want to see thoughtless copy&paste such\n> >> a code from parts of the code that are not performance critical to a\n> >> part.  Not very satisfying.\n> >>\n> >>      I think we can let this pass, and later add a wrapper around\n> >>      hashmap that is meant to only be used to replace string-list\n> >>      used for this exact purpose, i.e. key is a string, and there\n> >>      is no need to iterate over the existing elements in any\n> >>      sorted order.  Optionally, we can limit the look up to only\n> >>      checking for existence, if it makes the code for the wrapper\n> >>      simpler.\n> >\n> > This came up over in another thread yesterday, too. So yeah, perhaps we\n> > should move on that (I am OK punting on it for this series and\n> > converting it later, though).\n>\n> FWIW, I am OK punting and leaving, too.\n"},{"id":"363829","messageId":"CAC05385gbR+_cuD+9NPgX+f9aOoRhxu4BHXU+hvtdO54excE4Q@mail.gmail.com","threadId":"49438","inReplyTo":"20181113144931.GC17454@sigill.intra.peff.net","subject":"Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-11-21T14:07:54Z","receivedAt":"2018-11-21T14:08:24Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"OK, I see 3 votes for cyan and 4-5 people participating in the thread,\nso I'll make it cyan in the next revision.\nOn Tue, Nov 13, 2018 at 3:49 PM Jeff King <peff@peff.net> wrote:\n>\n> On Mon, Nov 12, 2018 at 06:07:18PM +0000, Rafael Ascensão wrote:\n>\n> > On Mon, Nov 12, 2018 at 07:14:23AM -0500, Jeff King wrote:\n> > > just adding a bunch of color variants. It would be nice if we could just\n> > > do this with a run-time parse_color(\"bold red\") or whatever, but we use\n> > > these as static initializers.\n> >\n> > I suggested those colors, but now, I think this needs to be\n> > configurable.\n>\n> I think they are configurable in that patch, since it provides\n> \"worktree\" as a n entry in color_branch_slots. But yeah, every color we\n> add needs to be configurable, and this is really just about defaults.\n>\n> > I suggested using green and dim green as the obvious theoretical choice\n> > but after using it for a while I found out that both shades are way too\n> > similar, making it really hard to tell by glancing at the output,\n> > especially when they're not side by side.\n> >\n> > If we continue with two dual green approach, current branch needs to be\n> > at least bold. But I'm not sure if it's enough.\n> >\n> > I've been trying some other colors, and cyan feels neutral-ish.\n>\n> Yeah, cyan seems pretty reasonable to me.\n>\n> -Peff\n"},{"id":"363830","messageId":"20181121140853.GA10210@sigill.intra.peff.net","threadId":"49438","inReplyTo":"CAC05387v6odwx3JTfJUR8tCxyqEEf7Z13ROgrLthc4rVLy3bJA@mail.gmail.com","subject":"Re: [PATCH v2 1/2] ref-filter: add worktree atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-11-21T14:08:54Z","receivedAt":"2018-11-21T14:08:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Nov 21, 2018 at 03:05:04PM +0100, Nickolai Belakovski wrote:\n\n> I think if we move to making this atom just store worktree path, that\n> needs to be implemented as a hashmap of refname->wtpath, which would\n> also solve this string_list issue, correct? Just making sure I'm not\n> missing something before I submit another patch.\n\nstring_list has a \"util\" field, so you actually _can_ use it to create\na mapping. I do think a hashmap is a little more obvious.\n\nOTOH, the hashmap API is a little tricky; if we are going to add a\n\"strmap\" API soon, it may be simpler to just use a string_list now and\nconvert to strmap when it is a available.\n\n-Peff\n"},{"id":"365466","messageId":"20181216215759.24011-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181111235831.44824-1-nbelakovski@gmail.com","subject":"[PATCH v3 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-16T21:57:56Z","receivedAt":"2018-12-16T21:58:10Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nFinally got around to submitting latest changes.\n\nI think this addresses all the feedback\n\nThe atom now returns the worktree path instead of '+'\n\nI stuck to cyan for the coloring, since it seemed most popular\n\nI added one more change to display the worktree path in cyan for git branch -vvv\nNot sure if it's in the best place, but it seemed like it would be nice to add\nthe path in the same color so that there's some visibility as to why a particular\nbranch is colored in cyan. If it proves to be controversial, I wouldn't want it to\nhold up this series, we can skip it and I can move discussion to a separate thread\n(or just forget it, as the case may be)\n\nTravis CI results: https://travis-ci.org/nbelakovski/git/builds/468569102\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: Mark and color a branch differently if it is checked out in a\n    linked worktree\n  branch: Add an extra verbose output displaying worktree path for refs\n    checked out in a linked worktree\n\n Documentation/git-for-each-ref.txt |  4 +++\n builtin/branch.c                   | 16 ++++++---\n ref-filter.c                       | 70 ++++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  |  8 ++---\n t/t3203-branch-output.sh           | 21 ++++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 6 files changed, 126 insertions(+), 8 deletions(-)\n\n-- \n2.14.2\n\n"},{"id":"365467","messageId":"20181216215759.24011-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181216215759.24011-1-nbelakovski@gmail.com","subject":"[PATCH v3 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-16T21:57:57Z","receivedAt":"2018-12-16T21:58:13Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom proving the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n---\n Documentation/git-for-each-ref.txt |  4 +++\n ref-filter.c                       | 70 ++++++++++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 3 files changed, 89 insertions(+)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 901faef1bf..9590f7beab 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -209,6 +209,10 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. ' ' otherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 5de616befe..e8713484a1 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -34,6 +36,8 @@ static struct ref_msg {\n \t\"ahead %d, behind %d\"\n };\n \n+static struct worktree ** worktrees;\n+\n void setup_ref_filter_porcelain_msg(void)\n {\n \tmsgs.gone = _(\"gone\");\n@@ -75,6 +79,12 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct reftoworktreeinfo_entry {\n+    struct hashmap_entry ent; // must be the first member!\n+    char * ref; // key into map\n+    struct worktree * wt;\n+};\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -114,6 +124,7 @@ static struct used_atom {\n \t\t} objectname;\n \t\tstruct refname_atom refname;\n \t\tchar *head;\n+\t\tstruct hashmap reftoworktreeinfo_map;\n \t} u;\n } *used_atom;\n static int used_atom_cnt, need_tagged, need_symref;\n@@ -420,6 +431,31 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n \treturn 0;\n }\n \n+static int worktree_atom_parser(const struct ref_format *format,\n+\t\t\t\tstruct used_atom *atom,\n+\t\t\t\tconst char *arg,\n+\t\t\t\tstruct strbuf *unused_err)\n+{\n+\tint i;\n+\tworktrees = get_worktrees(0);\n+\n+\thashmap_init(&(atom->u.reftoworktreeinfo_map), NULL, NULL, 0);\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct reftoworktreeinfo_entry *entry;\n+\t\t\tFLEXPTR_ALLOC_STR(entry, ref, worktrees[i]->head_ref);\n+\t\t\thashmap_entry_init(entry, strhash(entry->ref));\n+\n+\t\t\tentry->wt = worktrees[i];\n+\n+\t\t\thashmap_add(&(atom->u.reftoworktreeinfo_map), entry);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static struct {\n \tconst char *name;\n \tinfo_source source;\n@@ -461,6 +497,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE, FIELD_STR, worktree_atom_parser },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1500,6 +1537,28 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static const char * get_worktree_info(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct strbuf val = STRBUF_INIT;\n+\tstruct reftoworktreeinfo_entry * entry;\n+\tstruct reftoworktreeinfo_entry * lookup_result;\n+\n+\tFLEXPTR_ALLOC_STR(entry, ref, ref->refname);\n+\thashmap_entry_init(entry, strhash(entry->ref));\n+\tlookup_result = hashmap_get(&(atom->u.reftoworktreeinfo_map), entry, NULL);\n+\tfree(entry);\n+\n+\tif (lookup_result)\n+\t{\n+\t\tif (!strncmp(atom->name, \"worktreepath\", strlen(atom->name)))\n+\t\t\tstrbuf_addstr(&val, lookup_result->wt->path);\n+\t}\n+\telse\n+\t\tstrbuf_addstr(&val, \" \");\n+\n+\treturn strbuf_detach(&val, NULL);\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1537,6 +1596,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (starts_with(name, \"worktreepath\")) {\n+\t\t\tv->s = get_worktree_info(atom, ref);\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2013,7 +2076,14 @@ void ref_array_clear(struct ref_array *array)\n \tint i;\n \n \tfor (i = 0; i < used_atom_cnt; i++)\n+\t{\n+\t\tif (!strncmp(used_atom[i].name, \"worktreepath\", strlen(\"worktreepath\")))\n+\t\t{\n+\t\t\thashmap_free(&(used_atom[i].u.reftoworktreeinfo_map), 1);\n+\t\t\tfree_worktrees(worktrees);\n+\t\t}\n \t\tfree((char *)used_atom[i].name);\n+\t}\n \tFREE_AND_NULL(used_atom);\n \tused_atom_cnt = 0;\n \tfor (i = 0; i < array->nr; i++)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..add70a4c3e 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-\\EOF &&\n+\tmaster: checked out in a worktree\n+\tmaster_worktree: checked out in a worktree\n+\tside: not checked out in a worktree\n+\tEOF\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)checked out in a worktree%(else)not checked out in a worktree%(end)\" refs/heads/ >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"365468","messageId":"20181216215759.24011-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181216215759.24011-1-nbelakovski@gmail.com","subject":"[PATCH v3 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-16T21:57:58Z","receivedAt":"2018-12-16T21:58:16Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nIn order to more clearly display which branches are active, the output\nof git branch is modified to mark branches checkout out in a linked\nworktree with a \"+\" and color them in cyan (in contrast to the current\nbranch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to simplify workflows related to worktree, particularly\ndue to the limitations of not being able to check out the same branch in\ntwo worktrees and the inability to delete a branch checked out in a\nworktree. When performing branch operations like checkout and delete, it\nwould be useful to know more readily if the branches in which the user\nis interested are already checked out in a worktree.\n\nThe git worktree list command contains the relevant information, however\nthis is a much less frquently used command than git branch.\n---\n builtin/branch.c         | 12 ++++++++----\n t/t3200-branch.sh        |  8 ++++----\n t/t3203-branch-output.sh | 21 +++++++++++++++++++++\n 3 files changed, 33 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0c55f7f065..2a24153b78 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..e404f6e23c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '\n test_expect_success 'git branch --column' '\n \tCOLUMNS=81 git branch --column=column >actual &&\n \tcat >expected <<\\EOF &&\n-  a/b/c     bam       foo       l       * master    n         o/p       r\n+  a/b/c   + bam       foo       l       * master    n         o/p       r\n   abc       bar       j/k       m/m       master2   o/o       q\n EOF\n \ttest_cmp expected actual\n@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '\n \tcat >expected <<EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\n@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '\n \tgit config --unset column.branch &&\n \tgit config --unset column.ui &&\n \tcat >expected <<\\EOF &&\n-  a/b/c   bam   foo   l   * master    n     o/p   r\n+  a/b/c + bam   foo   l   * master    n     o/p   r\n   abc     bar   j/k   m/m   master2   o/o   q\n EOF\n \ttest_cmp expected actual\n@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '\n \tcat >expected <<\\EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614c..94ab05ad59 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n++ <CYAN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+\ttest_terminal git branch >actual.raw &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"365469","messageId":"20181216215759.24011-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181216215759.24011-1-nbelakovski@gmail.com","subject":"[PATCH v3 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-16T21:57:59Z","receivedAt":"2018-12-16T21:58:18Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\n---\n builtin/branch.c | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 2a24153b78..56589a3684 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n+\t\tif (filter->verbose > 2)\n+\t\t\tstrbuf_addf(&local, \"%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n+\n \t\tif (filter->verbose > 1)\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n-- \n2.14.2\n\n"},{"id":"365542","messageId":"20181218172236.GA28455@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20181216215759.24011-2-nbelakovski@gmail.com","subject":"Re: [PATCH v3 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-12-18T17:22:37Z","receivedAt":"2018-12-18T17:22:41Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Dec 16, 2018 at 01:57:57PM -0800, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> Add an atom proving the path of the linked worktree where this ref is\n> checked out, if it is checked out in any linked worktrees, and empty\n> string otherwise.\n\nI stumbled over the word \"proving\" here. Maybe \"showing\" would be more\nclear?\n\n> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n> index 901faef1bf..9590f7beab 100644\n> --- a/Documentation/git-for-each-ref.txt\n> +++ b/Documentation/git-for-each-ref.txt\n> @@ -209,6 +209,10 @@ symref::\n>  \t`:lstrip` and `:rstrip` options in the same way as `refname`\n>  \tabove.\n>  \n> +worktreepath::\n> +\tThe absolute path to the worktree in which the ref is checked\n> +\tout, if it is checked out in any linked worktree. ' ' otherwise.\n> +\n\nNormally single-quotes are used in asciidoc to emphasize text, and the\nquotes aren't passed through. Asciidoc (and asciidoctor) do seem to\nrender the literal quotes here, which is good. I wonder if it would be\nmore clear to just write it out, though, like:\n\n  ...any linked worktree. Otherwise, replaced with a single space.\n\nAlso, why are we replacing it with a single space? Wouldn't the empty\nstring be more customary (and work with the other \"if empty, then do\nthis\" formatting options)?\n\n> @@ -34,6 +36,8 @@ static struct ref_msg {\n>  \t\"ahead %d, behind %d\"\n>  };\n>  \n> +static struct worktree ** worktrees;\n\nMinor style nit: we put the \"*\" in a pointer declaration next to the\nvariable name, without intervening whitespace. Like:\n\n  static struct worktree **worktrees;\n\n> @@ -75,6 +79,12 @@ static struct expand_data {\n>  \tstruct object_info info;\n>  } oi, oi_deref;\n>  \n> +struct reftoworktreeinfo_entry {\n> +    struct hashmap_entry ent; // must be the first member!\n> +    char * ref; // key into map\n> +    struct worktree * wt;\n> +};\n\nA few style nits:\n\n  - the \"*\" space thing from above (it's in other places below, too, but\n    I won't point out each)\n\n  - we prefer \"/* */\" comments, even for single-liners\n\n  - since we do all-lowercase identifiers, use more underscores to break\n    things up. E.g., ref_to_worktree_entry.\n\nHere we store the refname as a separate variable, but then point to the\nworktree itself to access wt->path. Why do we treat these differently?\nI.e., I'd expect to see either:\n\n  1. Each entry holding a single worktree object, and using its head_ref\n     and path fields, like:\n\n       struct ref_to_worktree_entry {\n               struct hashmap_entry ent; /* must be first */\n\t       struct worktree *wt;\n       };\n       ....\n       entry = xmalloc(sizeof(*entry));\n       entry->wt = wt;\n       hashmap_entry_init(entry, strhash(wt->head_ref));\n       ...\n       strbuf_addstr(&out, result->wt->path);\n\n\n  2. Each entry containing just the bits it needs, like:\n\n       struct ref_to_worktree_entry {\n               struct hashmap_entry ent; /* must be first */\n\t       char *ref;\n\t       char *path;\n       };\n       ...\n       /*\n        * We could use FLEXPTR_ALLOC_STR() here, but it doesn't actually\n\t* support holding _two_ strings. Separate allocations probably\n\t* aren't a huge deal here, since there are only a handful of\n\t* worktrees.\n\t*/\n       entry = xmalloc(sizeof(*entry));\n       entry->ref = wt->head_ref;\n       entry->path = wt->path;\n       hashmap_entry_init(entry, strhash(entry->ref));\n       ...\n       strbuf_addstr(&out, result->path);\n\n\nI think the first one is strictly preferable unless we're worried about\nthe lifetime of the \"struct worktree\" going away. I don't think that's\nan issue, though; they are ours until we call free_worktrees().\n\n> @@ -114,6 +124,7 @@ static struct used_atom {\n>  \t\t} objectname;\n>  \t\tstruct refname_atom refname;\n>  \t\tchar *head;\n> +\t\tstruct hashmap reftoworktreeinfo_map;\n>  \t} u;\n>  } *used_atom;\n\nThis uses one map for each %(worktree) we use. But won't they all be the\nsame? It would ideally be associated with the ref-filter.  There's no\nref-filter context struct to hold this kind of data, just static globals\nin ref-filter.c (including this used_atom struct!). That's something\nwe'll probably need to fix in the long run, but I think it would be\nreasonable to just have:\n\n  static struct hashmap ref_to_worktree_map;\n\nnext to the declaration of used_atom_cnt, need_symref, etc. And then\nthose can all eventually get moved into a struct together.\n\n> @@ -461,6 +497,7 @@ static struct {\n>  \t{ \"flag\", SOURCE_NONE },\n>  \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n>  \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n> +\t{ \"worktreepath\", SOURCE_NONE, FIELD_STR, worktree_atom_parser },\n>  \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n>  \t{ \"end\", SOURCE_NONE },\n>  \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n\nMarking as SOURCE_NONE makes sense.\n\n> +static const char * get_worktree_info(const struct used_atom *atom, const struct ref_array_item *ref)\n> +{\n> +\tstruct strbuf val = STRBUF_INIT;\n> +\tstruct reftoworktreeinfo_entry * entry;\n> +\tstruct reftoworktreeinfo_entry * lookup_result;\n> +\n> +\tFLEXPTR_ALLOC_STR(entry, ref, ref->refname);\n> +\thashmap_entry_init(entry, strhash(entry->ref));\n> +\tlookup_result = hashmap_get(&(atom->u.reftoworktreeinfo_map), entry, NULL);\n> +\tfree(entry);\n\nWe shouldn't need to do an allocation just for a lookup. That's what the\nextra \"keydata\" parameter is for in the comparison function. And I guess\nthis is what led you to have \"char *ref\" in the struct, rather than\nreusing wt->head_ref (because you don't have a \"struct worktree\" here).\n\nYou should be able to do it like this:\n\n  struct hashmap_entry entry;\n  struct ref_to_worktree_entry *result;\n\n  hashmap_entry_init(entry, strhash(ref->refname));\n  result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname));\n  ...\n\nand then your comparison function would look like this:\n\n  int ref_to_worktree_hashcmp(const void *data,\n                              const void *entry,\n\t\t\t      const void *entry_or_key,\n\t\t\t      const void *keydata)\n  {\n          const struct ref_to_worktree_entry *a = entry;\n          const struct ref_to_worktree_entry *b = entry;\n\t  if (keydata)\n\t          return strcmp(a->wt->head_ref, keydata);\n\t  else\n\t          return strcmp(a->wt->head_ref, b->wt->head_ref);\n  }\n\nIf you're thinking that this API is totally confusing and hard to figure\nout, I agree. It's optimized to avoid extra allocations. I wish we had a\nbetter one for simple cases (especially string->string mappings like\nthis).\n\nSpeaking of comparison functions, I didn't see one in your patch. Don't\nyou need to pass one to hashmap_init?\n\n> +\tif (lookup_result)\n> +\t{\n> +\t\tif (!strncmp(atom->name, \"worktreepath\", strlen(atom->name)))\n> +\t\t\tstrbuf_addstr(&val, lookup_result->wt->path);\n> +\t}\n> +\telse\n> +\t\tstrbuf_addstr(&val, \" \");\n\nWhat's this extra strncmp about? If we're _not_ a worktreepath atom,\nwe'd still do the lookup only to put nothing in the string?\n\nI think we'd only call this function when populate_value() sees a\nworktreepath atom, though:\n\n> @@ -1537,6 +1596,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>  \n>  \t\tif (starts_with(name, \"refname\"))\n>  \t\t\trefname = get_refname(atom, ref);\n> +\t\telse if (starts_with(name, \"worktreepath\")) {\n> +\t\t\tv->s = get_worktree_info(atom, ref);\n> +\t\t\tcontinue;\n> +\t\t}\n\nSo it would be OK to drop the check of atom->name again inside\nget_worktree_info().\n\n> @@ -2013,7 +2076,14 @@ void ref_array_clear(struct ref_array *array)\n>  \tint i;\n>  \n>  \tfor (i = 0; i < used_atom_cnt; i++)\n> +\t{\n> +\t\tif (!strncmp(used_atom[i].name, \"worktreepath\", strlen(\"worktreepath\")))\n> +\t\t{\n> +\t\t\thashmap_free(&(used_atom[i].u.reftoworktreeinfo_map), 1);\n> +\t\t\tfree_worktrees(worktrees);\n> +\t\t}\n\nAnd if we move the mapping out to a static global, then this only has to\nbe done once, not once per atom. In fact, I think this could double-free\n\"worktrees\" with your current patch if you have two \"%(worktree)\"\nplaceholders, since \"worktrees\" already is a global.\n\n> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\n> index fc067ed672..add70a4c3e 100755\n> --- a/t/t6302-for-each-ref-filter.sh\n> +++ b/t/t6302-for-each-ref-filter.sh\n> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n>  \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n>  '\n>  \n> +test_expect_success '\"add\" a worktree' '\n> +\tmkdir worktree_dir &&\n> +\tgit worktree add -b master_worktree worktree_dir master\n> +'\n> +\n> +test_expect_success 'validate worktree atom' '\n> +\tcat >expect <<-\\EOF &&\n> +\tmaster: checked out in a worktree\n> +\tmaster_worktree: checked out in a worktree\n> +\tside: not checked out in a worktree\n> +\tEOF\n> +\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)checked out in a worktree%(else)not checked out in a worktree%(end)\" refs/heads/ >actual &&\n> +\ttest_cmp expect actual\n> +'\n\nIt's probably worth testing that the path we get is actually sane, too.\nI.e., expect something more like:\n\n   cat >expect <<-\\EOF\n   master: $PWD\n   master: $PWD/worktree\n   side: not checked out\n   EOF\n   git for-each-ref \\\n     --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked %out%(end)\n\n(I wish there was a way to avoid that really long line, but I don't\nthink there is).\n\n-Peff\n"},{"id":"365543","messageId":"20181218172544.GB28455@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20181216215759.24011-1-nbelakovski@gmail.com","subject":"Re: [PATCH v3 0/3]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-12-18T17:25:44Z","receivedAt":"2018-12-18T17:25:48Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Dec 16, 2018 at 01:57:56PM -0800, nbelakovski@gmail.com wrote:\n\n> Finally got around to submitting latest changes.\n> \n> I think this addresses all the feedback\n> \n> The atom now returns the worktree path instead of '+'\n\nThanks, I think patch 1 is definitely going in the right direction.\nThere are a few issues I found in its implementation, but they should be\neasy to fix (and won't affect the other patches).\n\nI don't really have a strong opinion on the behavior of the other\npatches.\n\n-Peff\n"},{"id":"365618","messageId":"CAC05384H1LgsGMO=ggUyfFTXrXAFcjUXDSdcmev9ActPt5081A@mail.gmail.com","threadId":"49438","inReplyTo":"20181218172236.GA28455@sigill.intra.peff.net","subject":"Re: [PATCH v3 1/3] ref-filter: add worktreepath atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-20T07:09:59Z","receivedAt":"2018-12-20T07:10:29Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Tue, Dec 18, 2018 at 9:22 AM Jeff King <peff@peff.net> wrote:\n>\n> On Sun, Dec 16, 2018 at 01:57:57PM -0800, nbelakovski@gmail.com wrote:\n>\n> > From: Nickolai Belakovski <nbelakovski@gmail.com>\n> >\n> > Add an atom proving the path of the linked worktree where this ref is\n> > checked out, if it is checked out in any linked worktrees, and empty\n> > string otherwise.\n>\n> I stumbled over the word \"proving\" here. Maybe \"showing\" would be more\n> clear?\n\nOops, providing\n\n> > +worktreepath::\n> > +     The absolute path to the worktree in which the ref is checked\n> > +     out, if it is checked out in any linked worktree. ' ' otherwise.\n> > +\n>\n> Also, why are we replacing it with a single space? Wouldn't the empty\n> string be more customary (and work with the other \"if empty, then do\n> this\" formatting options)?\n\nI was just following what was done for HEAD, but overall I agree that\nempty is preferable to single space, will change.\n\n> Minor style nit: we put the \"*\" in a pointer declaration next to the\n> variable name, without intervening whitespace. Like:\n>\n>   static struct worktree **worktrees;\n\nGotcha, will do, thanks for pointing it out.\n\n\nTo sum up the hashmap comments:\n-I hadn't thought to re-use the head_ref of worktree as the key.\nThat's clever. I like the readability of having separate entries for\nkey and value, but I can see the benefit of not having to do an extra\nallocation. I can make up for the readability hit with a comment.\n-Actually, for any valid use case there will only be one instance of\nthe map since the entries of used_atom are cached, but regardless it\nmakes sense to keep per-atom info in used_atom and global context\nsomewhere else, so I'll make that change to make it a static variable\noutside of used_atom.\n-Will change the lookup logic to remove the extra allocation. Since\nI'm letting the hashmap use its internal comparison function on the\nhash, I don't need to provide a comparison function.\n\n> What's this extra strncmp about? If we're _not_ a worktreepath atom,\n> we'd still do the lookup only to put nothing in the string?\n\nLeftover from an earlier iteration where I was going to support\ngetting more info out of the worktree struct. I decided to limit scope\nto just the info I really needed for the branch change. I left it like\nthis because I thought it would make the code more readable for\nsomeone who wanted to come in and add that extra info, but I think\nyou're right that it ends up just reading kind of awkwardly.\n\n>\n> > @@ -2013,7 +2076,14 @@ void ref_array_clear(struct ref_array *array)\n> >       int i;\n> >\n> >       for (i = 0; i < used_atom_cnt; i++)\n> > +     {\n> > +             if (!strncmp(used_atom[i].name, \"worktreepath\", strlen(\"worktreepath\")))\n> > +             {\n> > +                     hashmap_free(&(used_atom[i].u.reftoworktreeinfo_map), 1);\n> > +                     free_worktrees(worktrees);\n> > +             }\n>\n> And if we move the mapping out to a static global, then this only has to\n> be done once, not once per atom. In fact, I think this could double-free\n> \"worktrees\" with your current patch if you have two \"%(worktree)\"\n> placeholders, since \"worktrees\" already is a global.\n\nOnly if someone put a colon on one of the %(worktree) atoms, otherwise\nthey're all cached, but as you say moot point anyway if the map is\nmoved outside the used_atom structure.\n\n>\n> It's probably worth testing that the path we get is actually sane, too.\n> I.e., expect something more like:\n>\n>    cat >expect <<-\\EOF\n>    master: $PWD\n>    master: $PWD/worktree\n>    side: not checked out\n>    EOF\n>    git for-each-ref \\\n>      --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked %out%(end)\n>\n> (I wish there was a way to avoid that really long line, but I don't\n> think there is).\n>\n\nYea good call, can do.\n\nThanks for all the feedback, will try to turn these around quickly.\n"},{"id":"365643","messageId":"20181220145931.GB27361@sigill.intra.peff.net","threadId":"49438","inReplyTo":"CAC05384H1LgsGMO=ggUyfFTXrXAFcjUXDSdcmev9ActPt5081A@mail.gmail.com","subject":"Re: [PATCH v3 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-12-20T14:59:31Z","receivedAt":"2018-12-20T14:59:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Dec 19, 2018 at 11:09:59PM -0800, Nickolai Belakovski wrote:\n\n> > Also, why are we replacing it with a single space? Wouldn't the empty\n> > string be more customary (and work with the other \"if empty, then do\n> > this\" formatting options)?\n> \n> I was just following what was done for HEAD, but overall I agree that\n> empty is preferable to single space, will change.\n\nAh, right, that makes more sense. I do still think for %(HEAD) it's a\nlittle different because it is \"+\" or a single space, so always one\ncharacter.  Here we have some value or not, and in the \"not\" case for\nsuch things we usually give an empty string (e.g., for %(push),\n%(upstream), etc).\n\n> To sum up the hashmap comments:\n> -I hadn't thought to re-use the head_ref of worktree as the key.\n> That's clever. I like the readability of having separate entries for\n> key and value, but I can see the benefit of not having to do an extra\n> allocation. I can make up for the readability hit with a comment.\n\nThanks, that makes sense.\n\n> -Actually, for any valid use case there will only be one instance of\n> the map since the entries of used_atom are cached, but regardless it\n> makes sense to keep per-atom info in used_atom and global context\n> somewhere else, so I'll make that change to make it a static variable\n> outside of used_atom.\n\nAh, right, I forgot there was some magic around used_atom. I do still\nagree that the separate static global makes things a little simpler.\n\n> -Will change the lookup logic to remove the extra allocation. Since\n> I'm letting the hashmap use its internal comparison function on the\n> hash, I don't need to provide a comparison function.\n\nI don't think that works. The default function is always_equal(), which\nwill treat two entries equal if they have the same hash value. I.e., any\ncollisions would be considered a match.\n\n> Thanks for all the feedback, will try to turn these around quickly.\n\nGreat, thanks! I'll be on vacation for the next two weeks, so I may be\nvery slow to look at the next iteration. :)\n\n-Peff\n"},{"id":"365772","messageId":"20181224084756.49952-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181220145931.GB27361@sigill.intra.peff.net","subject":"[PATCH v4 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-24T08:47:53Z","receivedAt":"2018-12-24T08:48:07Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\n> I don't think that works. The default function is always_equal(), which\n> will treat two entries equal if they have the same hash value. I.e., any\n> collisions would be considered a match.\n\nYou're absolutely right. I've added a compare function, but I left out the\nfunctionality for it to work with an entry passed in as a key. Doing so would\nmean the user would have to allocate a worktree struct, which just seems silly\nwhen the ref is all that's needed (and also defeats the purpose of avoiding\nextra allocations).\n\nAnd while most of the hashmap API seems OK, yea, this is definitely awful. It\nfeels like it should just be able to take a key and return either an entry or\nNULL, and do away with entry_or_key and equals_function_data.\n\nTravis-CI results: https://travis-ci.org/nbelakovski/git/builds/471787317\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: Mark and color a branch differently if it is checked out in a\n    linked worktree\n  branch: Add an extra verbose output displaying worktree path for refs\n    checked out in a linked worktree\n\n Documentation/git-for-each-ref.txt |  5 +++\n builtin/branch.c                   | 16 ++++++---\n ref-filter.c                       | 72 +++++++++++++++++++++++++++++++++++++-\n t/t3200-branch.sh                  |  8 ++---\n t/t3203-branch-output.sh           | 21 +++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 6 files changed, 128 insertions(+), 9 deletions(-)\n\n-- \n2.14.2\n"},{"id":"365773","messageId":"20181224084756.49952-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181224084756.49952-1-nbelakovski@gmail.com","subject":"[PATCH v4 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-24T08:47:54Z","receivedAt":"2018-12-24T08:48:10Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom providing the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n---\n Documentation/git-for-each-ref.txt |  5 +++\n ref-filter.c                       | 72 +++++++++++++++++++++++++++++++++++++-\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 3 files changed, 91 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 901faef1bf..caba1c23b8 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -209,6 +209,11 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. Empty string\n+\totherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 5de616befe..240e7b80f8 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -34,6 +36,8 @@ static struct ref_msg {\n \t\"ahead %d, behind %d\"\n };\n \n+static struct worktree **worktrees;\n+\n void setup_ref_filter_porcelain_msg(void)\n {\n \tmsgs.gone = _(\"gone\");\n@@ -75,6 +79,11 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct ref_to_worktree_entry {\n+    struct hashmap_entry ent; /* must be the first member! */\n+    struct worktree *wt; /* key is wt->head_ref */\n+};\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -116,7 +125,8 @@ static struct used_atom {\n \t\tchar *head;\n \t} u;\n } *used_atom;\n-static int used_atom_cnt, need_tagged, need_symref;\n+static int used_atom_cnt, need_tagged, need_symref, has_worktree;\n+static struct hashmap ref_to_worktree_map;\n \n /*\n  * Expand string, append it to strbuf *sb, then return error code ret.\n@@ -420,6 +430,42 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n \treturn 0;\n }\n \n+static int worktree_hashmap_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,\n+\t\t\t\t   const void *unused_key, const void *keydata_aka_refname)\n+{\n+\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n+\treturn strcmp(e->wt->head_ref, keydata_aka_refname);\n+}\n+\n+static int worktree_atom_parser(const struct ref_format *format,\n+\t\t\t\tstruct used_atom *atom,\n+\t\t\t\tconst char *arg,\n+\t\t\t\tstruct strbuf *unused_err)\n+{\n+\tint i;\n+\tif (has_worktree)\n+\t\treturn 0;\n+\n+\tworktrees = get_worktrees(0);\n+\n+\thashmap_init(&ref_to_worktree_map, worktree_hashmap_cmpfnc, NULL, 0);\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct ref_to_worktree_entry *entry;\n+\t\t\tentry = xmalloc(sizeof(*entry));\n+\t\t\tentry->wt = worktrees[i];\n+\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\n+\t\t\thashmap_add(&ref_to_worktree_map, entry);\n+\t\t}\n+\t}\n+\n+\thas_worktree = 1;\n+\n+\treturn 0;\n+}\n+\n static struct {\n \tconst char *name;\n \tinfo_source source;\n@@ -461,6 +507,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE, FIELD_STR, worktree_atom_parser },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1500,6 +1547,20 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static const char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct strbuf val = STRBUF_INIT;\n+\tstruct hashmap_entry entry;\n+\tstruct ref_to_worktree_entry *lookup_result;\n+\n+\thashmap_entry_init(&entry, strhash(ref->refname));\n+\tlookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);\n+\n+\tstrbuf_addstr(&val, lookup_result ? lookup_result->wt->path : \"\");\n+\n+\treturn strbuf_detach(&val, NULL);\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1537,6 +1598,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (starts_with(name, \"worktreepath\")) {\n+\t\t\tv->s = get_worktree_path(atom, ref);\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2020,6 +2085,11 @@ void ref_array_clear(struct ref_array *array)\n \t\tfree_array_item(array->items[i]);\n \tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n+\tif (has_worktree)\n+\t{\n+\t\thashmap_free(&ref_to_worktree_map, 1);\n+\t\tfree_worktrees(worktrees);\n+\t}\n }\n \n static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..d70517a6ae 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+test_expect_success 'validate worktree atom' '\n+\t{\n+\techo master: $PWD &&\n+\techo master_worktree: $PWD/worktree_dir &&\n+\techo side: not checked out\n+\t} > expect &&\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"365774","messageId":"20181224084756.49952-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181224084756.49952-1-nbelakovski@gmail.com","subject":"[PATCH v4 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-24T08:47:55Z","receivedAt":"2018-12-24T08:48:13Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nIn order to more clearly display which branches are active, the output\nof git branch is modified to mark branches checkout out in a linked\nworktree with a \"+\" and color them in cyan (in contrast to the current\nbranch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to simplify workflows related to worktree, particularly\ndue to the limitations of not being able to check out the same branch in\ntwo worktrees and the inability to delete a branch checked out in a\nworktree. When performing branch operations like checkout and delete, it\nwould be useful to know more readily if the branches in which the user\nis interested are already checked out in a worktree.\n\nThe git worktree list command contains the relevant information, however\nthis is a much less frquently used command than git branch.\n---\n builtin/branch.c         | 12 ++++++++----\n t/t3200-branch.sh        |  8 ++++----\n t/t3203-branch-output.sh | 21 +++++++++++++++++++++\n 3 files changed, 33 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0c55f7f065..2a24153b78 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..e404f6e23c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '\n test_expect_success 'git branch --column' '\n \tCOLUMNS=81 git branch --column=column >actual &&\n \tcat >expected <<\\EOF &&\n-  a/b/c     bam       foo       l       * master    n         o/p       r\n+  a/b/c   + bam       foo       l       * master    n         o/p       r\n   abc       bar       j/k       m/m       master2   o/o       q\n EOF\n \ttest_cmp expected actual\n@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '\n \tcat >expected <<EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\n@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '\n \tgit config --unset column.branch &&\n \tgit config --unset column.ui &&\n \tcat >expected <<\\EOF &&\n-  a/b/c   bam   foo   l   * master    n     o/p   r\n+  a/b/c + bam   foo   l   * master    n     o/p   r\n   abc     bar   j/k   m/m   master2   o/o   q\n EOF\n \ttest_cmp expected actual\n@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '\n \tcat >expected <<\\EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614c..94ab05ad59 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n++ <CYAN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+\ttest_terminal git branch >actual.raw &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"365775","messageId":"20181224084756.49952-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20181224084756.49952-1-nbelakovski@gmail.com","subject":"[PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2018-12-24T08:47:56Z","receivedAt":"2018-12-24T08:48:14Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\n---\n builtin/branch.c | 4 ++++\n 1 file changed, 4 insertions(+)\n\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 2a24153b78..56589a3684 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n+\t\tif (filter->verbose > 2)\n+\t\t\tstrbuf_addf(&local, \"%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n+\n \t\tif (filter->verbose > 1)\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n-- \n2.14.2\n\n"},{"id":"366067","messageId":"20190103052219.GF20047@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20181224084756.49952-1-nbelakovski@gmail.com","subject":"Re: [PATCH v4 0/3]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-03T05:22:19Z","receivedAt":"2019-01-03T05:23:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Dec 24, 2018 at 12:47:53AM -0800, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> > I don't think that works. The default function is always_equal(), which\n> > will treat two entries equal if they have the same hash value. I.e., any\n> > collisions would be considered a match.\n> \n> You're absolutely right. I've added a compare function, but I left out the\n> functionality for it to work with an entry passed in as a key. Doing so would\n> mean the user would have to allocate a worktree struct, which just seems silly\n> when the ref is all that's needed (and also defeats the purpose of avoiding\n> extra allocations).\n\nUnfortunately, that doesn't quite work. :)\n\nYour compare function has to handle _both_ cases: two keys, or one key\nand a keydata.\n\nThe former may be called when the hashmap has to compare two entries\ninternally (e.g., when it has to re-bucket all of the entries after a\nresize). Your tests likely wouldn't run into this case in practice,\nsince you'd only have a handful of worktrees. But if you added, say,\nthousands of worktrees and we had to grow the hash midway through the\nprocess, it would segfault.  So you do need to handle the case when your\nkeydata is NULL.\n\nIn theory it would also be used for comparisons if we used a more clever\ndata structure to hold entries within a bucket. But since we just use a\nlinked list and linear search for now, we don't.\n\n> And while most of the hashmap API seems OK, yea, this is definitely awful. It\n> feels like it should just be able to take a key and return either an entry or\n> NULL, and do away with entry_or_key and equals_function_data.\n\nIn your case, yeah, equals_function_data is not used at all (but there\nare a few call-sites which need it to avoid relying on global data).\n\nBut the entry_or_key (coupled with keydata) is the magic that lets the\nsame function be used for both lookups as well as internal entry\ncomparisons.\n\nI think having two separate comparison functions would make this a lot\nmore clear, though likely at the cost of having more boilerplate.\n\n-Peff\n"},{"id":"366068","messageId":"20190103054043.GG20047@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20181224084756.49952-2-nbelakovski@gmail.com","subject":"Re: [PATCH v4 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-03T05:40:43Z","receivedAt":"2019-01-03T05:40:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Dec 24, 2018 at 12:47:54AM -0800, nbelakovski@gmail.com wrote:\n\n> [...]\n\nThanks for keeping with this.  I think we're getting quite close, though\nI did find a few small-ish issues.\n\n> @@ -34,6 +36,8 @@ static struct ref_msg {\n>  \t\"ahead %d, behind %d\"\n>  };\n>  \n> +static struct worktree **worktrees;\n> +\n\nMaybe define this near \"struct hashmap ref_to_worktree_map\" so it's\nmore obvious that the two are related?\n\n> @@ -75,6 +79,11 @@ static struct expand_data {\n>  \tstruct object_info info;\n>  } oi, oi_deref;\n>  \n> +struct ref_to_worktree_entry {\n> +    struct hashmap_entry ent; /* must be the first member! */\n> +    struct worktree *wt; /* key is wt->head_ref */\n> +};\n\nIndent with spaces?\n\n> -static int used_atom_cnt, need_tagged, need_symref;\n> +static int used_atom_cnt, need_tagged, need_symref, has_worktree;\n> +static struct hashmap ref_to_worktree_map;\n\nMakes sense. I thought at first has_worktree was a flag that we might\ncare about between parsing and formatting, but it's really just a flag\nto say \"we lazy-loaded the worktree list\".\n\n> +static int worktree_hashmap_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,\n> +\t\t\t\t   const void *unused_key, const void *keydata_aka_refname)\n> +{\n> +\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n> +\treturn strcmp(e->wt->head_ref, keydata_aka_refname);\n> +}\n\nSo from the discussion in the cover letter, this needs to be more like:\n\n  static int worktree_hashmap_cmpfnc(const void *unused_lookupdata,\n                                     const void *ve1, const void *ve2,\n\t\t\t\t     const void *keydata_aka_refname)\n  {\n\tconst struct ref_to_worktree_entry *e1 = ve1, *e2 = ve2;\n\treturn strcmp(e1->wt->head_ref, keydata_aka_refname ?\n\t\t                        keydata_aka_refname :\n\t\t\t\t\te2->wt->head_ref);\n  }\n\n> +static int worktree_atom_parser(const struct ref_format *format,\n> +\t\t\t\tstruct used_atom *atom,\n> +\t\t\t\tconst char *arg,\n> +\t\t\t\tstruct strbuf *unused_err)\n> +{\n> +\tint i;\n> +\tif (has_worktree)\n> +\t\treturn 0;\n\nMinor style nit, but please put a space between the declarations and the\nstart of the code (not strictly necessary for a short function which has\nno other linebreaks, like the cmpfunc above, but here I think it's\nconfusing not to).\n\n> +\tworktrees = get_worktrees(0);\n> +\n> +\thashmap_init(&ref_to_worktree_map, worktree_hashmap_cmpfnc, NULL, 0);\n> +\n> +\tfor (i = 0; worktrees[i]; i++) {\n> +\t\tif (worktrees[i]->head_ref) {\n> +\t\t\tstruct ref_to_worktree_entry *entry;\n> +\t\t\tentry = xmalloc(sizeof(*entry));\n> +\t\t\tentry->wt = worktrees[i];\n> +\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n> +\n> +\t\t\thashmap_add(&ref_to_worktree_map, entry);\n> +\t\t}\n> +\t}\n\nMakes sense to load the map.\n\n> +static const char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n> +{\n> +\tstruct strbuf val = STRBUF_INIT;\n> +\tstruct hashmap_entry entry;\n> +\tstruct ref_to_worktree_entry *lookup_result;\n> +\n> +\thashmap_entry_init(&entry, strhash(ref->refname));\n> +\tlookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);\n> +\n> +\tstrbuf_addstr(&val, lookup_result ? lookup_result->wt->path : \"\");\n> +\n> +\treturn strbuf_detach(&val, NULL);\n> +}\n\nAnd that makes sense to look up an item in it. Good.\n\nAdding an empty string to a strbuf is a noop, so that part might more\nclearly be written as just:\n\n  if (lookup_result)\n\tstrbuf_addstr(&val, lookup_result->wt->path);\n\nWe return a \"const char *\" here, but the result is always allocated. Do\nwe leak the result? Or should this return a \"char *\"?\n\nI think there are a lot of other atoms that leak currently, but that is\nbeing fixed in another topic that is currently in pu.\n\n> @@ -2020,6 +2085,11 @@ void ref_array_clear(struct ref_array *array)\n>  \t\tfree_array_item(array->items[i]);\n>  \tFREE_AND_NULL(array->items);\n>  \tarray->nr = array->alloc = 0;\n> +\tif (has_worktree)\n> +\t{\n> +\t\thashmap_free(&ref_to_worktree_map, 1);\n> +\t\tfree_worktrees(worktrees);\n> +\t}\n\nHere we free everything, but we don't unset has_worktree. So anybody\ntrying to format more refs afterward would see our freed worktree list.\n\nWe probably want:\n\n  has_worktree = 0;\n\nhere. Or simpler still, I think get_worktrees() will always return a\nnon-NULL list (even if it is empty). So you could just drop has_worktree\nentirely, and use:\n\n  if (worktrees)\n\treturn; /* already loaded */;\n\nin the loading function, and:\n\n  free_worktrees(worktrees);\n  worktrees = NULL;\n\nhere.\n\n> +test_expect_success '\"add\" a worktree' '\n> +\tmkdir worktree_dir &&\n> +\tgit worktree add -b master_worktree worktree_dir master\n> +'\n> +\n> +test_expect_success 'validate worktree atom' '\n> +\t{\n> +\techo master: $PWD &&\n> +\techo master_worktree: $PWD/worktree_dir &&\n> +\techo side: not checked out\n> +\t} > expect &&\n\nMinor style nit: use \"} >expect\" without the extra space.\n\nThis checks the actual directories. Good. I can never remember the rules\nfor when to use $PWD versus $(pwd) on Windows. We may run afoul of the\ndistinction here.\n\n-Peff\n"},{"id":"366069","messageId":"20190103054208.GH20047@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20181224084756.49952-4-nbelakovski@gmail.com","subject":"Re: [PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-03T05:42:08Z","receivedAt":"2019-01-03T05:42:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Dec 24, 2018 at 12:47:56AM -0800, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> ---\n>  builtin/branch.c | 4 ++++\n>  1 file changed, 4 insertions(+)\n\nThis patch should describe the new behavior in Documentation/git-branch.txt,\nI'd think.\n\n-Peff\n"},{"id":"366080","messageId":"CAPig+cQfjQBW-pAb1w92CVD3a4juRrkpnvwHsVM50xtUeSnf8g@mail.gmail.com","threadId":"49438","inReplyTo":"20190103054043.GG20047@sigill.intra.peff.net","subject":"Re: [PATCH v4 1/3] ref-filter: add worktreepath atom","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-01-03T09:31:29Z","receivedAt":"2019-01-03T09:31:42Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Thu, Jan 3, 2019 at 12:40 AM Jeff King <peff@peff.net> wrote:\n> On Mon, Dec 24, 2018 at 12:47:54AM -0800, nbelakovski@gmail.com wrote:\n> > +test_expect_success 'validate worktree atom' '\n> > +     {\n> > +     echo master: $PWD &&\n> > +     echo master_worktree: $PWD/worktree_dir &&\n> > +     echo side: not checked out\n> > +     } > expect &&\n>\n> Minor style nit: use \"} >expect\" without the extra space.\n\nAn interpolating here-doc would be even more natural:\n\n    cat >expect <-EOF &&\n    master: $(pwd)\n    master_worktree: $(pwd)/worktree_dir\n    side: not checked out\n    EOF\n\n> This checks the actual directories. Good. I can never remember the rules\n> for when to use $PWD versus $(pwd) on Windows. We may run afoul of the\n> distinction here.\n\nAs I understand it, this is exactly a case in which you would need to\nuse $(pwd); namely, when coming up with an \"expect\" value. t/README\ntalks about it.\n"},{"id":"366196","messageId":"20190106002619.54741-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"[PATCH v5 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-06T00:26:16Z","receivedAt":"2019-01-06T00:26:30Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nReplying to my original email to try to clean up the email chain\n\n> Thanks for keeping with this.  I think we're getting quite close\n\nThanks to you as well for continuing to review the change set and provide feedback!\nIt does feel rather close, I'm getting exciting about following it through, even if\nwe just end up merging the worktreepath commit and not the ones to modify the branch\noutput, since I can always just make a local alias that uses the worktreepath atom.\n\nThe last set of changes all made sense, very non-controversial, so I've simply implemented\nthem. Beyond that, I moved where the structures for the ref<->worktree map are defined now\nthat they're no longer associated with used_atom. They still feel a little awkwardly\nplaced to me; I couldn't quite find a way I liked of arranging them together while also\nsticking to the style in the rest of the code but I think it's a little better that\nall of the relevant structs and the cmpfnc are all in the same place.\n\nTravis-CI results: https://travis-ci.org/nbelakovski/git/builds/475825245\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: Mark and color a branch differently if it is checked out in a\n    linked worktree\n  branch: Add an extra verbose output displaying worktree path for refs\n    checked out in a linked worktree\n\n Documentation/git-branch.txt       | 20 ++++++-----\n Documentation/git-for-each-ref.txt |  5 +++\n builtin/branch.c                   | 16 ++++++---\n ref-filter.c                       | 71 ++++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  |  8 ++---\n t/t3203-branch-output.sh           | 21 +++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 7 files changed, 140 insertions(+), 16 deletions(-)\n\n-- \n2.14.2\n\n"},{"id":"366197","messageId":"20190106002619.54741-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190106002619.54741-1-nbelakovski@gmail.com","subject":"[PATCH v5 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-06T00:26:17Z","receivedAt":"2019-01-06T00:26:33Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom providing the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n---\n Documentation/git-for-each-ref.txt |  5 +++\n ref-filter.c                       | 71 ++++++++++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 3 files changed, 91 insertions(+)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 901faef1bf..caba1c23b8 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -209,6 +209,11 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. Empty string\n+\totherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 5de616befe..e7ca45f39b 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -75,6 +77,22 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct ref_to_worktree_entry {\n+\tstruct hashmap_entry ent; /* must be the first member! */\n+\tstruct worktree *wt; /* key is wt->head_ref */\n+};\n+\n+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,\n+\t\t\t\t   const void *key, const void *keydata_aka_refname)\n+{\n+\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n+\tconst struct ref_to_worktree_entry *k = key;\n+\treturn strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n+}\n+\n+static struct hashmap ref_to_worktree_map;\n+static struct worktree **worktrees = NULL;\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -420,6 +438,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n \treturn 0;\n }\n \n+static int worktree_atom_parser(const struct ref_format *format,\n+\t\t\t\tstruct used_atom *atom,\n+\t\t\t\tconst char *arg,\n+\t\t\t\tstruct strbuf *unused_err)\n+{\n+\tint i;\n+\n+\tif (worktrees)\n+\t\treturn 0;\n+\n+\tworktrees = get_worktrees(0);\n+\n+\thashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct ref_to_worktree_entry *entry;\n+\t\t\tentry = xmalloc(sizeof(*entry));\n+\t\t\tentry->wt = worktrees[i];\n+\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\n+\t\t\thashmap_add(&ref_to_worktree_map, entry);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static struct {\n \tconst char *name;\n \tinfo_source source;\n@@ -461,6 +507,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE, FIELD_STR, worktree_atom_parser },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1500,6 +1547,21 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct strbuf val = STRBUF_INIT;\n+\tstruct hashmap_entry entry;\n+\tstruct ref_to_worktree_entry *lookup_result;\n+\n+\thashmap_entry_init(&entry, strhash(ref->refname));\n+\tlookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);\n+\n+\tif (lookup_result)\n+\t\tstrbuf_addstr(&val, lookup_result->wt->path);\n+\n+\treturn strbuf_detach(&val, NULL);\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1537,6 +1599,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (starts_with(name, \"worktreepath\")) {\n+\t\t\tv->s = get_worktree_path(atom, ref);\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2020,6 +2086,11 @@ void ref_array_clear(struct ref_array *array)\n \t\tfree_array_item(array->items[i]);\n \tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n+\tif (worktrees)\n+\t{\n+\t\thashmap_free(&ref_to_worktree_map, 1);\n+\t\tfree_worktrees(worktrees);\n+\t}\n }\n \n static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..87e0222ea1 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-EOF &&\n+\tmaster: $(pwd)\n+\tmaster_worktree: $(pwd)/worktree_dir\n+\tside: not checked out\n+\tEOF\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"366198","messageId":"20190106002619.54741-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190106002619.54741-1-nbelakovski@gmail.com","subject":"[PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-06T00:26:18Z","receivedAt":"2019-01-06T00:26:36Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nIn order to more clearly display which branches are active, the output\nof git branch is modified to mark branches checkout out in a linked\nworktree with a \"+\" and color them in cyan (in contrast to the current\nbranch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to simplify workflows related to worktree, particularly\ndue to the limitations of not being able to check out the same branch in\ntwo worktrees and the inability to delete a branch checked out in a\nworktree. When performing branch operations like checkout and delete, it\nwould be useful to know more readily if the branches in which the user\nis interested are already checked out in a worktree.\n\nThe git worktree list command contains the relevant information, however\nthis is a much less frquently used command than git branch.\n---\n Documentation/git-branch.txt | 15 ++++++++-------\n builtin/branch.c             | 12 ++++++++----\n t/t3200-branch.sh            |  8 ++++----\n t/t3203-branch-output.sh     | 21 +++++++++++++++++++++\n 4 files changed, 41 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex bf5316ffa9..b3eca6ffdc 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -26,13 +26,14 @@ DESCRIPTION\n -----------\n \n If `--list` is given, or if there are no non-option arguments, existing\n-branches are listed; the current branch will be highlighted with an\n-asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n-and option `-a` shows both local and remote branches. If a `<pattern>`\n-is given, it is used as a shell wildcard to restrict the output to\n-matching branches. If multiple patterns are given, a branch is shown if\n-it matches any of the patterns.  Note that when providing a\n-`<pattern>`, you must use `--list`; otherwise the command is interpreted\n+branches are listed; the current branch will be highlighted in green and\n+marked with an asterisk.  Any branches checked out in linked worktrees will\n+be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n+remote-tracking branches to be listed, and option `-a` shows both local and\n+remote branches. If a `<pattern>` is given, it is used as a shell wildcard to\n+restrict the output to matching branches. If multiple patterns are given, a\n+branch is shown if it matches any of the patterns.  Note that when providing\n+a `<pattern>`, you must use `--list`; otherwise the command is interpreted\n as branch creation.\n \n With `--contains`, shows only the branches that contain the named commit\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 0c55f7f065..2a24153b78 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..e404f6e23c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '\n test_expect_success 'git branch --column' '\n \tCOLUMNS=81 git branch --column=column >actual &&\n \tcat >expected <<\\EOF &&\n-  a/b/c     bam       foo       l       * master    n         o/p       r\n+  a/b/c   + bam       foo       l       * master    n         o/p       r\n   abc       bar       j/k       m/m       master2   o/o       q\n EOF\n \ttest_cmp expected actual\n@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '\n \tcat >expected <<EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\n@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '\n \tgit config --unset column.branch &&\n \tgit config --unset column.ui &&\n \tcat >expected <<\\EOF &&\n-  a/b/c   bam   foo   l   * master    n     o/p   r\n+  a/b/c + bam   foo   l   * master    n     o/p   r\n   abc     bar   j/k   m/m   master2   o/o   q\n EOF\n \ttest_cmp expected actual\n@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '\n \tcat >expected <<\\EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614c..94ab05ad59 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n++ <CYAN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+\ttest_terminal git branch >actual.raw &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"366199","messageId":"20190106002619.54741-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190106002619.54741-1-nbelakovski@gmail.com","subject":"[PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-06T00:26:19Z","receivedAt":"2019-01-06T00:26:36Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\n---\n Documentation/git-branch.txt | 5 ++++-\n builtin/branch.c             | 4 ++++\n 2 files changed, 8 insertions(+), 1 deletion(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex b3eca6ffdc..6d1fc59e32 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -163,12 +163,15 @@ This option is only applicable in non-verbose mode.\n \n -v::\n -vv::\n+-vvv::\n --verbose::\n \tWhen in list mode,\n \tshow sha1 and commit subject line for each head, along with\n \trelationship to upstream branch (if any). If given twice, print\n \tthe name of the upstream branch, as well (see also `git remote\n-\tshow <remote>`).\n+\tshow <remote>`). If given 3 times, print the path of the linked\n+\tworktree, if applicable (not applicable for main worktree since\n+\tits path will be a subset of $PWD)\n \n -q::\n --quiet::\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 2a24153b78..56589a3684 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n+\t\tif (filter->verbose > 2)\n+\t\t\tstrbuf_addf(&local, \"%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n+\n \t\tif (filter->verbose > 1)\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n-- \n2.14.2\n\n"},{"id":"366272","messageId":"xmqq5zv09vns.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190106002619.54741-2-nbelakovski@gmail.com","subject":"Re: [PATCH v5 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-07T18:20:39Z","receivedAt":"2019-01-07T18:20:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> +static struct hashmap ref_to_worktree_map;\n> +static struct worktree **worktrees = NULL;\n> +\n>  /*\n>   * An atom is a valid field atom listed below, possibly prefixed with\n>   * a \"*\" to denote deref_tag().\n> @@ -420,6 +438,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n>  \treturn 0;\n>  }\n>  \n> +static int worktree_atom_parser(const struct ref_format *format,\n> +\t\t\t\tstruct used_atom *atom,\n> +\t\t\t\tconst char *arg,\n> +\t\t\t\tstruct strbuf *unused_err)\n> +{\n> +\tint i;\n> +\n> +\tif (worktrees)\n> +\t\treturn 0;\n\nOK, so verify_ref_format() etc. will trigger this to be called via\nvalid_atom[].parser when \"%(worktreepath)\" is seen in the user\nformat, and then this grabs all the worktrees and record their paths\nin the hashmap.  This if() statement makes sure that it happens only\nonce.\n\n> +\tworktrees = get_worktrees(0);\n> +\n> +\thashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);\n> +\n> +\tfor (i = 0; worktrees[i]; i++) {\n> +\t\tif (worktrees[i]->head_ref) {\n> +\t\t\tstruct ref_to_worktree_entry *entry;\n> +\t\t\tentry = xmalloc(sizeof(*entry));\n> +\t\t\tentry->wt = worktrees[i];\n> +\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n> +\n> +\t\t\thashmap_add(&ref_to_worktree_map, entry);\n> +\t\t}\n> +\t}\n> +\n> +\treturn 0;\n> +}\n> +\n>  static struct {\n>  \tconst char *name;\n>  \tinfo_source source;\n> @@ -461,6 +507,7 @@ static struct {\n>  \t{ \"flag\", SOURCE_NONE },\n>  \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n>  \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n> +\t{ \"worktreepath\", SOURCE_NONE, FIELD_STR, worktree_atom_parser },\n>  \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n>  \t{ \"end\", SOURCE_NONE },\n>  \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n> @@ -1500,6 +1547,21 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n>  \treturn 0;\n>  }\n>  \n> +static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n> +{\n> +\tstruct strbuf val = STRBUF_INIT;\n> +\tstruct hashmap_entry entry;\n> +\tstruct ref_to_worktree_entry *lookup_result;\n\nAnd then this will be called from populate_value() for each of the\nref.  It looks up the worktree that has checked out this branch, if\nany, from the hashmap, and yields the path to it.\n\nWhen seeing a tag or note ref, by definition that's not something we\ncan have checked out in any worktree.  I wonder if it is worth to\noptimize further by omitting this lookup when ref is not a local\nbranch?\n\nIOW, with a typical number of worktrees and refs, how costly would ...\n\n> +\thashmap_entry_init(&entry, strhash(ref->refname));\n> +\tlookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);\n\n... this sequence of calls be.\n\n> +\n> +\tif (lookup_result)\n> +\t\tstrbuf_addstr(&val, lookup_result->wt->path);\n> +\n> +\treturn strbuf_detach(&val, NULL);\n> +}\n> +\n>  /*\n>   * Parse the object referred by ref, and grab needed value.\n>   */\n> @@ -1537,6 +1599,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>  \n>  \t\tif (starts_with(name, \"refname\"))\n>  \t\t\trefname = get_refname(atom, ref);\n> +\t\telse if (starts_with(name, \"worktreepath\")) {\n> +\t\t\tv->s = get_worktree_path(atom, ref);\n> +\t\t\tcontinue;\n> +\t\t}\n>  \t\telse if (starts_with(name, \"symref\"))\n>  \t\t\trefname = get_symref(atom, ref);\n>  \t\telse if (starts_with(name, \"upstream\")) {\n> @@ -2020,6 +2086,11 @@ void ref_array_clear(struct ref_array *array)\n>  \t\tfree_array_item(array->items[i]);\n>  \tFREE_AND_NULL(array->items);\n>  \tarray->nr = array->alloc = 0;\n> +\tif (worktrees)\n> +\t{\n\nHave this opening brace at the end of the previous line, i.e.\n\n\tif (worktrees) {\n\n> +\t\thashmap_free(&ref_to_worktree_map, 1);\n> +\t\tfree_worktrees(worktrees);\n> +\t}\n>  }\n\nWhat's the point of ref_array_clear()?  What does the caller of this\nfunction really want?  Is it merely to release the resources\nconsumed?  If so, then this is good enough, but then the existing\ncalls to FREE_AND_NULL() for releasing resources in the function is\noverkill.\n\nOr is it envisioned that we are preparing a clean slate so that\nanother call, possibly after the external environment changed, can\nbe made into this machinery (i.e. imagine we lift ref-filter.c code\nand link it to a long running service process; after serving one\nfor-each-ref request, a new worktree or a new branch may get\ncreated, and then we may get another for-each-ref request)?  If that\nis the case, then the added code breaks that hope, as it leaves a\ndangling pointer in the worktrees variable.\n\n>  static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\n> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\n> index fc067ed672..87e0222ea1 100755\n> --- a/t/t6302-for-each-ref-filter.sh\n> +++ b/t/t6302-for-each-ref-filter.sh\n> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n>  \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n>  '\n>  \n> +test_expect_success '\"add\" a worktree' '\n> +\tmkdir worktree_dir &&\n> +\tgit worktree add -b master_worktree worktree_dir master\n> +'\n> +\n> +test_expect_success 'validate worktree atom' '\n> +\tcat >expect <<-EOF &&\n> +\tmaster: $(pwd)\n> +\tmaster_worktree: $(pwd)/worktree_dir\n> +\tside: not checked out\n> +\tEOF\n> +\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n> +\ttest_cmp expect actual\n> +'\n> +\n>  test_done\n"},{"id":"366274","messageId":"xmqqzhsc8f32.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190106002619.54741-3-nbelakovski@gmail.com","subject":"Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-07T19:04:01Z","receivedAt":"2019-01-07T19:04:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n>\n> In order to more clearly display which branches are active, the output\n> of git branch is modified to mark branches checkout out in a linked\n> worktree with a \"+\" and color them in cyan (in contrast to the current\n> branch, which will still be denoted with a \"*\" and colored in green)\n>\n> This is meant to simplify workflows related to worktree, particularly\n> due to the limitations of not being able to check out the same branch in\n> two worktrees and the inability to delete a branch checked out in a\n> worktree. When performing branch operations like checkout and delete, it\n> would be useful to know more readily if the branches in which the user\n> is interested are already checked out in a worktree.\n\nI do not think it is warranted to paint the safety features as\n\"limitations\".\n\nA branch that is checked out in another worktree cannot be checked\nout to be worked on, as that will make the checkout of the other\nworktree out of sync.  If you want to work on that branch, you can\neither (1) go to that worktree that has a checkout of that branch\nand work there, or (2) go to that worktree that has a checkout of\nthat branch, check out a different branch there, come back to the\nworktree you want to work in and check out that branch.  Knowing\nwhere that other worktree is is the first step in either case.\n\nAnd a branch that is checked out in a worktree cannot be removed, as\nit is a sign that it is still being worked on for a branch to have\nbeen checked out somewhere.  If you do want to remove that branch,\nyou need to go to that worktree that has a checkout of that branch,\ncheck out a different branch there, and then remove it.  Again,\nknowing where that other worktree is is the fist thing you need to\nknow.\n\nBut then I am not sure if the feature being added by these patches\nis a good match for that justification.\n\nFor one thing, it would be more direct and helpful way for\n\n\tgit checkout one-branch\n\tgit branch -d one-branch\n\nto say \"The branch `one-branch` is checked out in a worktree at\n$DIRECTORY\" when they refused to go ahead.  And that would eliminate\nthe need for this new feature to help these two use cases.\n\nIn fact, these two command already behave that way, so the paragraph\nI just commented on is not a good justification for this new feature\nat all.\n\nBesides, showing \"That branch is checked out somewhere\" would not\nhelp user to decide \"ah, if I want to work on that branch, I need to\nchdir to that directory\" with the patch in question, as it only\nshows \"It is checked out _somewhere_\" without saying where.\n\n> The git worktree list command contains the relevant information, however\n> this is a much less frquently used command than git branch.\n\nIt is not a good justification.  If the \"relevant information\" given\nby the command is necessary one, the user can run that command.  If\nthe situation where that \"relevant information\" becomes necessary is\nrare, the command is run much less frequently is not a problem---it\nis expected.  And overloading a more frequently used command with\ninformation that is less frequently wanted is actually not a great\ndesign.\n\nA more relevant justification may be that even though the\ninformation can already be found in \"worktree list\" output, it would\ngive us flexibility in presentation to allow the custom format in\nfor-each-ref to show it.\n\nSo, I am between moderately Meh to fairly negative on this step; Meh\nin the sense that \"thanks to the previous step, we _could_ do this,\nit does not give incorrect information, and it makes the output more\ncheerful, but it does not add that much useful and actionable piece\nof information\".\n"},{"id":"366275","messageId":"xmqqtvik8eua.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190106002619.54741-4-nbelakovski@gmail.com","subject":"Re: [PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-07T19:09:17Z","receivedAt":"2019-01-07T19:09:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n>\n> ---\n\nAll three patches lack sign off.\n\nI am fairly negative on 2/3, but I think this one makes sense\nwithout introducing a new verbosity level.  We do not promise\nstability of Porcelain command output and update the UI if we\nhave useful information to give.  Just making\n\n\tgit branch --list -v -v\n\nshow additional information should be sufficient.\n\n> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> index b3eca6ffdc..6d1fc59e32 100644\n> --- a/Documentation/git-branch.txt\n> +++ b/Documentation/git-branch.txt\n> @@ -163,12 +163,15 @@ This option is only applicable in non-verbose mode.\n>  \n>  -v::\n>  -vv::\n> +-vvv::\n>  --verbose::\n>  \tWhen in list mode,\n>  \tshow sha1 and commit subject line for each head, along with\n>  \trelationship to upstream branch (if any). If given twice, print\n>  \tthe name of the upstream branch, as well (see also `git remote\n> -\tshow <remote>`).\n> +\tshow <remote>`). If given 3 times, print the path of the linked\n> +\tworktree, if applicable (not applicable for main worktree since\n> +\tits path will be a subset of $PWD)\n>  \n>  -q::\n>  --quiet::\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index 2a24153b78..56589a3684 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n>  \t\tstrbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));\n>  \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n>  \n> +\t\tif (filter->verbose > 2)\n> +\t\t\tstrbuf_addf(&local, \"%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s\",\n> +\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n> +\n>  \t\tif (filter->verbose > 1)\n>  \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n>  \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n"},{"id":"366538","messageId":"e313d0b1-54b1-9fe2-6c75-d2ae7b57fe3a@iee.org","threadId":"49438","inReplyTo":"xmqqzhsc8f32.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Philip Oakley","fromEmail":"philipoakley@iee.org","sentAt":"2019-01-10T21:42:19Z","receivedAt":"2019-01-10T21:42:21Z","isPatch":true,"sender":{"key":"philipoakley@iee.email","avatar":"https://avatars.githubusercontent.com/u/914343?v=4"},"body":"On 07/01/2019 19:04, Junio C Hamano wrote:\n> nbelakovski@gmail.com writes:\n>\n>> From: Nickolai Belakovski <nbelakovski@gmail.com>\n>>\n>> In order to more clearly display which branches are active, the output\n>> of git branch is modified to mark branches checkout out in a linked\n>> worktree with a \"+\" and color them in cyan (in contrast to the current\n>> branch, which will still be denoted with a \"*\" and colored in green)\n>>\n>> This is meant to simplify workflows related to worktree, particularly\n>> due to the limitations of not being able to check out the same branch in\n>> two worktrees and the inability to delete a branch checked out in a\n>> worktree. When performing branch operations like checkout and delete, it\n>> would be useful to know more readily if the branches in which the user\n>> is interested are already checked out in a worktree.\n> I do not think it is warranted to paint the safety features as\n> \"limitations\".\n\nIs this not just a case of needing to clarify that this is 'safety' \nrelated to the _users_ mental model (or lack of) relative to the limited \ninformation that was previously given by the branch command's list.\n\nYou are right that there is no data safety issue, but users make \nmistakes when they misunderstand the situation.\n\n>\n> A branch that is checked out in another worktree cannot be checked\n> out to be worked on, as that will make the checkout of the other\n> worktree out of sync.  If you want to work on that branch, you can\n> either (1) go to that worktree that has a checkout of that branch\n> and work there, or (2) go to that worktree that has a checkout of\n> that branch, check out a different branch there, come back to the\n> worktree you want to work in and check out that branch.  Knowing\n> where that other worktree is is the first step in either case.\n>\n> And a branch that is checked out in a worktree cannot be removed, as\n> it is a sign that it is still being worked on for a branch to have\n> been checked out somewhere.\n\nI'm not sure that all users will recognise the signs, which I think is \none reason for the value of the patch.\n\n\n>    If you do want to remove that branch,\n> you need to go to that worktree that has a checkout of that branch,\n> check out a different branch there, and then remove it.  Again,\n> knowing where that other worktree is is the fist thing you need to\n> know.\n>\n> But then I am not sure if the feature being added by these patches\n> is a good match for that justification.\nI'd agree that the justification needs clarified.\n>\n> For one thing, it would be more direct and helpful way for\n>\n> \tgit checkout one-branch\n> \tgit branch -d one-branch\n>\n> to say \"The branch `one-branch` is checked out in a worktree at\n> $DIRECTORY\" when they refused to go ahead.  And that would eliminate\n> the need for this new feature to help these two use cases.\n>\n> In fact, these two command already behave that way, so the paragraph\n> I just commented on is not a good justification for this new feature\n> at all.\n>\n> Besides, showing \"That branch is checked out somewhere\" would not\n> help user to decide \"ah, if I want to work on that branch, I need to\n> chdir to that directory\" with the patch in question, as it only\n> shows \"It is checked out _somewhere_\" without saying where.\n>\n>> The git worktree list command contains the relevant information, however\n>> this is a much less frquently used command than git branch.\n> It is not a good justification.  If the \"relevant information\" given\n> by the command is necessary one, the user can run that command.  If\n> the situation where that \"relevant information\" becomes necessary is\n> rare, the command is run much less frequently is not a problem---it\n> is expected.  And overloading a more frequently used command with\n> information that is less frequently wanted is actually not a great\n> design.\nBut leaving the older command unaware of the newer developments and the \nuser unwise as to its missing info is equally a poor situation.\n>\n> A more relevant justification may be that even though the\n> information can already be found in \"worktree list\" output, it would\n> give us flexibility in presentation to allow the custom format in\n> for-each-ref to show it.\n>\n> So, I am between moderately Meh to fairly negative on this step; Meh\n> in the sense that \"thanks to the previous step, we _could_ do this,\n> it does not give incorrect information, and it makes the output more\n> cheerful, but it does not add that much useful and actionable piece\n> of information\".\n\nThe patch did appear to me as being a proper update to the branch \ncommand to include the information about the branches in the other worktrees\n\nPhilip\n\n"},{"id":"366625","messageId":"CAC05384uh_xRboFhxohRq-vKFrTPDnszSaS3vW+BAv30h-Zd+g@mail.gmail.com","threadId":"49438","inReplyTo":"e313d0b1-54b1-9fe2-6c75-d2ae7b57fe3a@iee.org","subject":"Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-13T01:41:12Z","receivedAt":"2019-01-13T01:41:41Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Thu, Jan 10, 2019 at 1:43 PM Philip Oakley <philipoakley@iee.org> wrote:\n>\n> On 07/01/2019 19:04, Junio C Hamano wrote:\n> > I do not think it is warranted to paint the safety features as\n> > \"limitations\".\n>\n> Is this not just a case of needing to clarify that this is 'safety'\n> related to the _users_ mental model (or lack of) relative to the limited\n> information that was previously given by the branch command's list.\n>\n> You are right that there is no data safety issue, but users make\n> mistakes when they misunderstand the situation.\n\nNot trying to paint anything one way or another. I found that these\nfeatures got in the way of my workflows and didn't see any immediate\nreason why they had to exist. Thinking about it a bit more, is it\nunreasonable to delete a branch even if it's checked out in a worktree\nas long as the user uses git branch --delete --force or -D? This would\nleave the worktree in a detached head state, but all the data would be\nuntouched. The output of deletion could mention that the branch had\nbeen checked out in a worktree so that the user is fully informed.\n\nChecking out the same branch in two worktrees should be technically\npossible to implement safely, but I don't see a use case for having\nthe same branch checked out in multiple worktrees anyway. Why use\nmultiple worktrees at that point? If a user really wants the same\ncontents in two directories they can work around this\nlimitation/safety feature by just making another branch pointing at\nthe same commit. But anyway I'm just explaining why I chose the word\n'limitation'.\n\n\n> >    If you do want to remove that branch,\n> > you need to go to that worktree that has a checkout of that branch,\n> > check out a different branch there, and then remove it.  Again,\n> > knowing where that other worktree is is the fist thing you need to\n> > know.\n\nThis just seems silly to me when git branch --delete has a --force\noption. But that's off topic.\n\n> >\n> >> The git worktree list command contains the relevant information, however\n> >> this is a much less frquently used command than git branch.\n> > It is not a good justification.  If the \"relevant information\" given\n> > by the command is necessary one, the user can run that command.  If\n> > the situation where that \"relevant information\" becomes necessary is\n> > rare, the command is run much less frequently is not a problem---it\n> > is expected.  And overloading a more frequently used command with\n> > information that is less frequently wanted is actually not a great\n> > design.\n> But leaving the older command unaware of the newer developments and the\n> user unwise as to its missing info is equally a poor situation.\n> >\n> > A more relevant justification may be that even though the\n> > information can already be found in \"worktree list\" output, it would\n> > give us flexibility in presentation to allow the custom format in\n> > for-each-ref to show it.\n> >\n> > So, I am between moderately Meh to fairly negative on this step; Meh\n> > in the sense that \"thanks to the previous step, we _could_ do this,\n> > it does not give incorrect information, and it makes the output more\n> > cheerful, but it does not add that much useful and actionable piece\n> > of information\".\n\nAllow me to add some color to my original commit message. The point of\nthis patch is so that the user is not surprised when they see the\nmessage that this branch is checked out in another worktree when\ntrying to delete it or check it out, since they have presumably run\ngit branch recently and seen the formatted output indicating that a\nbranch they may want to delete/checkout is checked out in a worktree.\nThis was my frustration that prompted me to dive into this in the\nfirst place - I'm cleaning up my branches and all of a sudden git\ndecides it doesn't want to let me delete one because it's checked out\nsomewhere else, even though I know I don't care about it because I\nknow the branch has already been merged upstream, or is old, or\nwhatever. I thought, if git branch output could at least let me know\nthat it's going to treat some branches differently, I can be proactive\nabout things and go to my worktree and delete the branch, or skip\ntrying to clean it up or not check it out.\n\nI'll pursue the above-mentioned topic of allowing git branch -D to\nallow the user to delete branches checked out in a worktree\nseparately, but even if that goes through, I think this patch would\nstill be useful in that it tells me that I can't check out the\nbranches that are colored in cyan.\n\nDoes that make more sense?\n"},{"id":"366662","messageId":"xmqqbm4jw1aq.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"CAC05384uh_xRboFhxohRq-vKFrTPDnszSaS3vW+BAv30h-Zd+g@mail.gmail.com","subject":"Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-14T18:18:21Z","receivedAt":"2019-01-14T18:18:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nickolai Belakovski <nbelakovski@gmail.com> writes:\n\n> Not trying to paint anything one way or another. I found that these\n> features got in the way of my workflows and didn't see any immediate\n> reason why they had to exist. Thinking about it a bit more, is it\n> unreasonable to delete a branch even if it's checked out in a worktree\n> as long as the user uses git branch --delete --force or -D?\n\n[For ease of discussion, let's assume that our worktree has a\ncheckout of branch B, and you are mucking with that branch in\nanother worktree connected to the same repository]\n\nIt is probably a sane enhancement to allow but require --force to\ndelete branch B in the other worktree.  It is a different matter to\nallow \"git branch -m AnotherBranch B\" run in the other worktree to\noverwrite branch B--it will be a disaster if we allowed it and then\ncommitted what we have in our worktree.\n\n> This would\n> leave the worktree in a detached head state,\n\nIt does not.  It will leave us on branch B that is unborn, and the\nnext commit will start that branch with a root commit.\n\n> but all the data would be\n> untouched. \n\nAs far as the person, who is working in our worktree, is concerned,\nshe wanted to extend the history of branch B before you deleted it\nin another worktree.  But because you deleted B while she was\nlooking the other way, she ended up creating a root commit, losing\nall the history behind that branch.  I'd grant you that \"--force\"\nwill give us an excuse when she complains, though.\n\nMost likely, you and she are the same person, but one big point in\nthe ability to work in multiple worktrees is to allow the user to\nswitch context and multi-task.  When she gives branch B its own\nworktree, she does so because she wants to have a stable place to\nwork on it, without getting affected by other things she does to the\nrepository in other worktrees.\n\n"},{"id":"367149","messageId":"CAC05386ZxQsCPAV+nEXr2LJv-y48qL+YT3E+wg2T8Pf0fPRDsQ@mail.gmail.com","threadId":"49438","inReplyTo":"xmqq5zv09vns.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 1/3] ref-filter: add worktreepath atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-18T22:17:24Z","receivedAt":"2019-01-18T22:17:53Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Mon, Jan 7, 2019 at 10:20 AM Junio C Hamano <gitster@pobox.com> wrote:\n> When seeing a tag or note ref, by definition that's not something we\n> can have checked out in any worktree.  I wonder if it is worth to\n> optimize further by omitting this lookup when ref is not a local\n> branch?\n>\n> IOW, with a typical number of worktrees and refs, how costly would ...\n>\n> > +     hashmap_entry_init(&entry, strhash(ref->refname));\n> > +     lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);\n>\n> ... this sequence of calls be.\n>\n\nIt certainly wouldn't be free. Every check would compute the hash of\nthe refname and do a lookup into the hash table. If the bucket it\nlooked up was empty that'd be it, but if it were non-empty a few more\ncomparisons would happen.\n\nI think avoiding this would be check, we can simply check ref->kind ==\nFILTER_REFS_BRANCHES ahead of calling into get_worktree_path and\nprovide an empty string otherwise.\n\n> >               free_array_item(array->items[i]);\n> >       FREE_AND_NULL(array->items);\n> >       array->nr = array->alloc = 0;\n> > +     if (worktrees)\n> > +     {\n>\n>\n> What's the point of ref_array_clear()?  ...  If that\n> is the case, then the added code breaks that hope, as it leaves a\n> dangling pointer in the worktrees variable.\n>\n\nDiscussion of the point of ref_array_clear would be out of scope of\nthis change, but your point is well taken that setting worktrees to\nNULL would be consistent with the rest of the function. Will\nimplement.\n"},{"id":"367150","messageId":"CAC053875ZH2Sx55s3gzL8Kcp3mduwc_D60=w_v7CjsG+_=LsQQ@mail.gmail.com","threadId":"49438","inReplyTo":"xmqqbm4jw1aq.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-18T22:18:46Z","receivedAt":"2019-01-18T22:19:15Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"I will start a separate thread containing these replies for the\npotential change to allow deleting branches checked out in worktrees.\n\nGetting back on track for this series, specifically this 2/3 patch,\nhow do you feel about it? As I pointed out the goal is to communicate\nto the user that the branches marked/colored will behave differently\nfrom the other branches if the user tries to delete them or check them\nout.\n"},{"id":"367152","messageId":"CAC05385tK4sk0F7tLhPnQN44eKifbb_KKkernKQMEBFHoz8hgw@mail.gmail.com","threadId":"49438","inReplyTo":"CAC05386ZxQsCPAV+nEXr2LJv-y48qL+YT3E+wg2T8Pf0fPRDsQ@mail.gmail.com","subject":"Re: [PATCH v5 1/3] ref-filter: add worktreepath atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-18T22:20:16Z","receivedAt":"2019-01-18T22:20:46Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Fri, Jan 18, 2019 at 2:17 PM Nickolai Belakovski\n<nbelakovski@gmail.com> wrote:\n>\n>\n> I think avoiding this would be check, we can simply check ref->kind ==\n> FILTER_REFS_BRANCHES ahead of calling into get_worktree_path and\n> provide an empty string otherwise.\n>\n\n*would be check -> would be cheap\n"},{"id":"367391","messageId":"20190122232301.95971-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"[PATCH v6 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-22T23:22:58Z","receivedAt":"2019-01-22T23:23:18Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nFrom the latest round of comments:\n-Added a check in populate_value to only do the hashmap lookup for refs of type branch,\nsince other types would not be checked out in a worktree\n-Reworded the commit message on 2/3 to make it clearer that the change in output is meant\nto inform users that the colored/marked branches will behave differently from the others\nupon attempts to delete or check out\n-Removed the extra verbose check on 3/3 and added the worktree path to the output if it exists\n-Set 'worktrees' variable to NULL after free-ing, to allow for ref-filter to be reentrant\n\nTravis-CI results: https://travis-ci.org/nbelakovski/git/builds/483134182\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: Mark and color a branch differently if it is checked out in a\n    linked worktree\n  branch: Add an extra verbose output displaying worktree path for refs\n    checked out in a linked worktree\n\n Documentation/git-branch.txt       | 22 +++++++-----\n Documentation/git-for-each-ref.txt |  5 +++\n builtin/branch.c                   | 16 ++++++---\n ref-filter.c                       | 74 ++++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  |  8 ++---\n t/t3203-branch-output.sh           | 21 +++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 7 files changed, 144 insertions(+), 17 deletions(-)\n\n-- \n2.14.2\n\n"},{"id":"367392","messageId":"20190122232301.95971-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190122232301.95971-1-nbelakovski@gmail.com","subject":"[PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-22T23:22:59Z","receivedAt":"2019-01-22T23:23:20Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom providing the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n---\n Documentation/git-for-each-ref.txt |  5 +++\n ref-filter.c                       | 74 ++++++++++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 3 files changed, 94 insertions(+)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 774cecc7ed..6dcd39f6f6 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -214,6 +214,11 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. Empty string\n+\totherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 422a9c9ae3..3c056cc148 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -75,6 +77,22 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct ref_to_worktree_entry {\n+\tstruct hashmap_entry ent; /* must be the first member! */\n+\tstruct worktree *wt; /* key is wt->head_ref */\n+};\n+\n+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,\n+\t\t\t\t   const void *key, const void *keydata_aka_refname)\n+{\n+\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n+\tconst struct ref_to_worktree_entry *k = key;\n+\treturn strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n+}\n+\n+static struct hashmap ref_to_worktree_map;\n+static struct worktree **worktrees = NULL;\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -438,6 +456,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n \treturn 0;\n }\n \n+static int worktree_atom_parser(const struct ref_format *format,\n+\t\t\t\tstruct used_atom *atom,\n+\t\t\t\tconst char *arg,\n+\t\t\t\tstruct strbuf *unused_err)\n+{\n+\tint i;\n+\n+\tif (worktrees)\n+\t\treturn 0;\n+\n+\tworktrees = get_worktrees(0);\n+\n+\thashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct ref_to_worktree_entry *entry;\n+\t\t\tentry = xmalloc(sizeof(*entry));\n+\t\t\tentry->wt = worktrees[i];\n+\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\n+\t\t\thashmap_add(&ref_to_worktree_map, entry);\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static struct {\n \tconst char *name;\n \tinfo_source source;\n@@ -480,6 +526,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE, FIELD_STR, worktree_atom_parser },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1525,6 +1572,21 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct strbuf val = STRBUF_INIT;\n+\tstruct hashmap_entry entry;\n+\tstruct ref_to_worktree_entry *lookup_result;\n+\n+\thashmap_entry_init(&entry, strhash(ref->refname));\n+\tlookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);\n+\n+\tif (lookup_result)\n+\t\tstrbuf_addstr(&val, lookup_result->wt->path);\n+\n+\treturn strbuf_detach(&val, NULL);\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1562,6 +1624,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (starts_with(name, \"worktreepath\")) {\n+\t\t\tif (ref->kind == FILTER_REFS_BRANCHES)\n+\t\t\t\tv->s = get_worktree_path(atom, ref);\n+\t\t\telse\n+\t\t\t\tv->s = xstrdup(\"\");\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2045,6 +2114,11 @@ void ref_array_clear(struct ref_array *array)\n \t\tfree_array_item(array->items[i]);\n \tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n+\tif (worktrees) {\n+\t\thashmap_free(&ref_to_worktree_map, 1);\n+\t\tfree_worktrees(worktrees);\n+\t\tworktrees = NULL;\n+\t}\n }\n \n static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..87e0222ea1 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-EOF &&\n+\tmaster: $(pwd)\n+\tmaster_worktree: $(pwd)/worktree_dir\n+\tside: not checked out\n+\tEOF\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"367393","messageId":"20190122232301.95971-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190122232301.95971-1-nbelakovski@gmail.com","subject":"[PATCH v6 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-22T23:23:00Z","receivedAt":"2019-01-22T23:23:23Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nThe output of git branch is modified to mark branches checkout out in a\nlinked worktree with a \"+\" and color them in cyan (in contrast to the\ncurrent branch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to communicate to the user that the branches that are\nmarked or colored will behave differently from other branches if the user\nattempts to check them out or delete them, since branches checked out in\nanother worktree cannot be checked out or deleted.\n---\n Documentation/git-branch.txt | 15 ++++++++-------\n builtin/branch.c             | 12 ++++++++----\n t/t3200-branch.sh            |  8 ++++----\n t/t3203-branch-output.sh     | 21 +++++++++++++++++++++\n 4 files changed, 41 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex bf5316ffa9..b3eca6ffdc 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -26,13 +26,14 @@ DESCRIPTION\n -----------\n \n If `--list` is given, or if there are no non-option arguments, existing\n-branches are listed; the current branch will be highlighted with an\n-asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n-and option `-a` shows both local and remote branches. If a `<pattern>`\n-is given, it is used as a shell wildcard to restrict the output to\n-matching branches. If multiple patterns are given, a branch is shown if\n-it matches any of the patterns.  Note that when providing a\n-`<pattern>`, you must use `--list`; otherwise the command is interpreted\n+branches are listed; the current branch will be highlighted in green and\n+marked with an asterisk.  Any branches checked out in linked worktrees will\n+be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n+remote-tracking branches to be listed, and option `-a` shows both local and\n+remote branches. If a `<pattern>` is given, it is used as a shell wildcard to\n+restrict the output to matching branches. If multiple patterns are given, a\n+branch is shown if it matches any of the patterns.  Note that when providing\n+a `<pattern>`, you must use `--list`; otherwise the command is interpreted\n as branch creation.\n \n With `--contains`, shows only the branches that contain the named commit\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 1be727209b..c2a86362bb 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..e404f6e23c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '\n test_expect_success 'git branch --column' '\n \tCOLUMNS=81 git branch --column=column >actual &&\n \tcat >expected <<\\EOF &&\n-  a/b/c     bam       foo       l       * master    n         o/p       r\n+  a/b/c   + bam       foo       l       * master    n         o/p       r\n   abc       bar       j/k       m/m       master2   o/o       q\n EOF\n \ttest_cmp expected actual\n@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '\n \tcat >expected <<EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\n@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '\n \tgit config --unset column.branch &&\n \tgit config --unset column.ui &&\n \tcat >expected <<\\EOF &&\n-  a/b/c   bam   foo   l   * master    n     o/p   r\n+  a/b/c + bam   foo   l   * master    n     o/p   r\n   abc     bar   j/k   m/m   master2   o/o   q\n EOF\n \ttest_cmp expected actual\n@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '\n \tcat >expected <<\\EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614c..94ab05ad59 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n++ <CYAN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+\ttest_terminal git branch >actual.raw &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"367394","messageId":"20190122232301.95971-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190122232301.95971-1-nbelakovski@gmail.com","subject":"[PATCH v6 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-22T23:23:01Z","receivedAt":"2019-01-22T23:23:25Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\n---\n Documentation/git-branch.txt | 7 +++++--\n builtin/branch.c             | 4 ++++\n 2 files changed, 9 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex b3eca6ffdc..a1aef00af0 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -163,12 +163,15 @@ This option is only applicable in non-verbose mode.\n \n -v::\n -vv::\n+-vvv::\n --verbose::\n \tWhen in list mode,\n \tshow sha1 and commit subject line for each head, along with\n \trelationship to upstream branch (if any). If given twice, print\n-\tthe name of the upstream branch, as well (see also `git remote\n-\tshow <remote>`).\n+\tthe path of the linked worktree, if applicable (not applicable\n+\tfor main worktree since user's path will already be in main\n+\tworktree) and the name of the upstream branch, as well (see also\n+\t`git remote show <remote>`).\n \n -q::\n --quiet::\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex c2a86362bb..0b8ba9e4c5 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n \t\tif (filter->verbose > 1)\n+\t\t{\n+\t\t\tstrbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n \t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n+\t\t}\n \t\telse\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)\");\n \n-- \n2.14.2\n\n"},{"id":"367449","messageId":"xmqq36pjcicw.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190122232301.95971-2-nbelakovski@gmail.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-23T18:57:19Z","receivedAt":"2019-01-23T18:57:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n>\n> Add an atom providing the path of the linked worktree where this ref is\n> checked out, if it is checked out in any linked worktrees, and empty\n> string otherwise.\n> ---\n\nMissing sign-off?\n\n> +static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,\n> +\t\t\t\t   const void *key, const void *keydata_aka_refname)\n> +{\n> +\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n> +\tconst struct ref_to_worktree_entry *k = key;\n> +\treturn strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n\nOverlong line.\n\n> +}\n\n\n> +\n> +static struct hashmap ref_to_worktree_map;\n> +static struct worktree **worktrees = NULL;\n\nNo need to initialize static vars to 0/NULL.\n\n> @@ -438,6 +456,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a\n>  \treturn 0;\n>  }\n>  \n> +static int worktree_atom_parser(const struct ref_format *format,\n> +\t\t\t\tstruct used_atom *atom,\n> +\t\t\t\tconst char *arg,\n> +\t\t\t\tstruct strbuf *unused_err)\n> +{\n> +\tint i;\n> +\n> +\tif (worktrees)\n> +\t\treturn 0;\n> +\n> +\tworktrees = get_worktrees(0);\n> +\n> +\thashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);\n> +\n> +\tfor (i = 0; worktrees[i]; i++) {\n> +\t\tif (worktrees[i]->head_ref) {\n> +\t\t\tstruct ref_to_worktree_entry *entry;\n> +\t\t\tentry = xmalloc(sizeof(*entry));\n> +\t\t\tentry->wt = worktrees[i];\n> +\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n> +\n> +\t\t\thashmap_add(&ref_to_worktree_map, entry);\n> +\t\t}\n> +\t}\n> +\n> +\treturn 0;\n> +}\n\nIt is kind of interesting that a function for parsing an \"atom\" in\n\"format\" does not look at none of its arguments at all ;-)  The fact\nthat \"%(worktreepath)\" atom got noticed by verify_ref_format() alone\nis of interest for this function.\n\nThe helper iterates over all worktrees, registers them in a hashmap\nref_to_worktree_map, indexed by the head reference.\n\nOK.\n\n> +static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n> +{\n> +\tstruct strbuf val = STRBUF_INIT;\n> +\tstruct hashmap_entry entry;\n> +\tstruct ref_to_worktree_entry *lookup_result;\n> +\n> +\thashmap_entry_init(&entry, strhash(ref->refname));\n> +\tlookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);\n> +\n> +\tif (lookup_result)\n> +\t\tstrbuf_addstr(&val, lookup_result->wt->path);\n> +\n> +\treturn strbuf_detach(&val, NULL);\n> +}\n\nWe do not need a strbuf to do the above, do we?\n\n\thashmap_entry_init(...);\n\tlookup_result = hashmap_get(...);\n\tif (lookup_result)\n\t\treturn xstrdup(lookup_result->wt->path);\n\telse\n\t\treturn xstrdup(\"\");\n\nor something like that, perhaps?\n\n> @@ -1562,6 +1624,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>  \n>  \t\tif (starts_with(name, \"refname\"))\n>  \t\t\trefname = get_refname(atom, ref);\n> +\t\telse if (starts_with(name, \"worktreepath\")) {\n> +\t\t\tif (ref->kind == FILTER_REFS_BRANCHES)\n> +\t\t\t\tv->s = get_worktree_path(atom, ref);\n> +\t\t\telse\n> +\t\t\t\tv->s = xstrdup(\"\");\n> +\t\t\tcontinue;\n> +\t\t}\n\nI am wondering if get_worktree_path() being called should be the\ntriggering event for lazy initialization worktree_atom_parser() is\ndoing in this patch, instead of verify_ref_format() seeing the\n\"%(worktreepath)\" atom.  Is there any codepath that wants to make\nsure the lazy initialization is done without/before populate_value()\nsees a use of the \"%(worktreepath)\" atom?  If so, such a plan would\nnot work, but otherwise, we can do the following:\n\n - rename worktree_atom_parser() to lazy_init_worktrees() or\n   something, and remove all of its unused parameters.\n\n - remove parser callback for \"worktreepath\" from valid_atom[].\n\n - call lazy_inti_worktrees() at the beginning of\n   get_worktree_path().\n\nHmm?\n"},{"id":"367496","messageId":"CAC05384+KjC=4_ZF9BrxweMUjwpkaGXNqRNSnwif6yci6TxMMw@mail.gmail.com","threadId":"49438","inReplyTo":"xmqq36pjcicw.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-23T23:34:22Z","receivedAt":"2019-01-23T23:34:53Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Wed, Jan 23, 2019 at 10:57 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Missing sign-off?\n>\n\nMy mistake, forgot -s on format-patch. Will remember to add it next go-around.\n\n> > +static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,\n> > +                                const void *key, const void *keydata_aka_refname)\n> > +{\n> > +     const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n> > +     const struct ref_to_worktree_entry *k = key;\n> > +     return strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n>\n> Overlong line.\n>\n> > +}\n>\n\nOK, should I shorten the function signature as well? Is it too long\nbecause it's 101 characters and you're trying to stick to 100?\n\n>\n> > +\n> > +static struct hashmap ref_to_worktree_map;\n> > +static struct worktree **worktrees = NULL;\n>\n> No need to initialize static vars to 0/NULL.\n\nOK\n\n>\n> We do not need a strbuf to do the above, do we?\n>\n>         hashmap_entry_init(...);\n>         lookup_result = hashmap_get(...);\n>         if (lookup_result)\n>                 return xstrdup(lookup_result->wt->path);\n>         else\n>                 return xstrdup(\"\");\n>\n> or something like that, perhaps?\n>\n\nSure.\n\n> > @@ -1562,6 +1624,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n> >\n> >               if (starts_with(name, \"refname\"))\n> >                       refname = get_refname(atom, ref);\n> > +             else if (starts_with(name, \"worktreepath\")) {\n> > +                     if (ref->kind == FILTER_REFS_BRANCHES)\n> > +                             v->s = get_worktree_path(atom, ref);\n> > +                     else\n> > +                             v->s = xstrdup(\"\");\n> > +                     continue;\n> > +             }\n>\n> I am wondering if get_worktree_path() being called should be the\n> triggering event for lazy initialization worktree_atom_parser() is\n> doing in this patch, instead of verify_ref_format() seeing the\n> \"%(worktreepath)\" atom.  Is there any codepath that wants to make\n> sure the lazy initialization is done without/before populate_value()\n> sees a use of the \"%(worktreepath)\" atom?  If so, such a plan would\n> not work, but otherwise, we can do the following:\n>\n>  - rename worktree_atom_parser() to lazy_init_worktrees() or\n>    something, and remove all of its unused parameters.\n>\n>  - remove parser callback for \"worktreepath\" from valid_atom[].\n>\n>  - call lazy_inti_worktrees() at the beginning of\n>    get_worktree_path().\n>\n> Hmm?\n\nYes, the parser used the atom argument in an earlier version of this\npatch, but we since moved the map out of the atom since it only needs\nto exist once globally. Even though we have a caching mechanism for\natoms it still seemed like a logical move to explicitly keep one\ninstance of the map globally. Will make the change, thanks for taking\na look at it through fresh eyes.\n"},{"id":"367571","messageId":"xmqq5zud52ut.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"CAC05384+KjC=4_ZF9BrxweMUjwpkaGXNqRNSnwif6yci6TxMMw@mail.gmail.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-24T18:26:18Z","receivedAt":"2019-01-24T18:26:22Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nickolai Belakovski <nbelakovski@gmail.com> writes:\n\n> Yes, the parser used the atom argument in an earlier version of this\n> patch, but we since moved the map out of the atom since it only needs\n> to exist once globally. Even though we have a caching mechanism for\n> atoms it still seemed like a logical move to explicitly keep one\n> instance of the map globally.\n\nI think that is a mistaken move from an earlier version to this\none.  The worktree-related stuff only becomes necessary and belongs\nto the %(worktreepath) atom, so unless there is a compelling reason\nnot to, we should hang it there, instead of introducing a global.\nWhen you have --format='%(worktreepath) %(worktreepath)', you'd have\nonly one shared instance of it in used_atom[] to ensure that we have\na singleton instance.\n\nThe object_info support in the file, which is relatively new, may be\nwhat you borrowed the wrong idea of preferring globals from; I think\nit should be taken as an anti-pattern.\n\n"},{"id":"367572","messageId":"20190124183235.GA16580@sigill.intra.peff.net","threadId":"49438","inReplyTo":"xmqq5zud52ut.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-24T18:32:35Z","receivedAt":"2019-01-24T18:32:38Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 24, 2019 at 10:26:18AM -0800, Junio C Hamano wrote:\n\n> Nickolai Belakovski <nbelakovski@gmail.com> writes:\n> \n> > Yes, the parser used the atom argument in an earlier version of this\n> > patch, but we since moved the map out of the atom since it only needs\n> > to exist once globally. Even though we have a caching mechanism for\n> > atoms it still seemed like a logical move to explicitly keep one\n> > instance of the map globally.\n> \n> I think that is a mistaken move from an earlier version to this\n> one.  The worktree-related stuff only becomes necessary and belongs\n> to the %(worktreepath) atom, so unless there is a compelling reason\n> not to, we should hang it there, instead of introducing a global.\n> When you have --format='%(worktreepath) %(worktreepath)', you'd have\n> only one shared instance of it in used_atom[] to ensure that we have\n> a singleton instance.\n\nWhat if you have other atoms that need worktrees? E.g., does\n%(worktreepath:foo) use the same used_atom slot? What if we have another\nworktree-related atom?\n\nIf anything, I'd suggest going in the opposite direction, and teaching\nthe worktree code a function for looking up a working tree by ref. And\nthen it can handle its own cache to implement that reverse-mapping\nefficiently.\n\n> The object_info support in the file, which is relatively new, may be\n> what you borrowed the wrong idea of preferring globals from; I think\n> it should be taken as an anti-pattern.\n\nAnd that one is a good example where we _do_ need the global, because we\nalready have multiple atoms pulling from it. I think the right level is\n\"global to the ref-filter context\", but we do not have that concept yet\n(hence why used_atoms, etc, are all file-static globals).\n\n-Peff\n"},{"id":"367584","messageId":"xmqqh8dxj1p3.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190124183235.GA16580@sigill.intra.peff.net","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-24T19:27:36Z","receivedAt":"2019-01-24T19:27:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> If anything, I'd suggest going in the opposite direction, and teaching\n> the worktree code a function for looking up a working tree by ref. And\n> then it can handle its own cache to implement that reverse-mapping\n> efficiently.\n\nYeah, that's a thought.  Then \"give me a worktree that checks out\nthis ref\" can be asked outside the context of for-each-ref and\nfriends, which is a big plus.\n"},{"id":"367589","messageId":"20190124193417.GA14896@sigill.intra.peff.net","threadId":"49438","inReplyTo":"xmqqh8dxj1p3.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-24T19:34:17Z","receivedAt":"2019-01-24T19:58:49Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 24, 2019 at 11:27:36AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > If anything, I'd suggest going in the opposite direction, and teaching\n> > the worktree code a function for looking up a working tree by ref. And\n> > then it can handle its own cache to implement that reverse-mapping\n> > efficiently.\n> \n> Yeah, that's a thought.  Then \"give me a worktree that checks out\n> this ref\" can be asked outside the context of for-each-ref and\n> friends, which is a big plus.\n\nOne tricky thing is that we do not store a list of \"struct worktree\",\nbut rather generate it on the fly when get_worktrees() is called.\n\nSo having an API to ask for one ref's worktree at a time is slightly\nawkward. It's only by having (and caching) this full list in\nref-filter.c that we can easily make the reverse-indexed hashmap.\n\n-Peff\n"},{"id":"367590","messageId":"xmqqd0olj1kj.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190124183235.GA16580@sigill.intra.peff.net","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-24T19:30:20Z","receivedAt":"2019-01-24T20:06:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> What if you have other atoms that need worktrees? E.g., does\n> %(worktreepath:foo) use the same used_atom slot? What if we have another\n> worktree-related atom?\n> ...\n> And that one is a good example where we _do_ need the global, because we\n> already have multiple atoms pulling from it.\n\nI guess that we broke the original atom design by mistake when we\nadded \":<modifiers>\" support.  There should have been one layer of\nindirection that binds the instances of the same atom with different\nmodifiers together---I agree with you that we cannot avoid globals\nwithout fixing that mistake first.\n\nThanks.\n"},{"id":"367606","messageId":"20190124212608.GD16114@sigill.intra.peff.net","threadId":"49438","inReplyTo":"xmqqd0olj1kj.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-24T21:26:08Z","receivedAt":"2019-01-24T21:26:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 24, 2019 at 11:30:20AM -0800, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > What if you have other atoms that need worktrees? E.g., does\n> > %(worktreepath:foo) use the same used_atom slot? What if we have another\n> > worktree-related atom?\n> > ...\n> > And that one is a good example where we _do_ need the global, because we\n> > already have multiple atoms pulling from it.\n> \n> I guess that we broke the original atom design by mistake when we\n> added \":<modifiers>\" support.  There should have been one layer of\n> indirection that binds the instances of the same atom with different\n> modifiers together---I agree with you that we cannot avoid globals\n> without fixing that mistake first.\n\nYes, that's one way to fix it.\n\nI actually think the biggest mistake is having that used_atoms list in\nthe first place, as we iterate over it several times asking \"can we fill\nthis in yet?\". The way pretty.c does it is just to incrementally parse\nthe commit, saving intermediate results. And in cat-file.c, we figure\nout what we need ahead of time in a single pass, and then just fill it\nin for each object (which sort of works out the same, but doesn't\nrequire that the parsing needed for item X is a strict superset of item\nY).\n\nSo I'd much rather see us parse the format into a real tree of nodes,\nand figure out (once) which properties of each object are required to\nfulfill that. Then for each object, we grab those properties, and then\nwalk the tree to generate the output string.\n\n-Peff\n"},{"id":"368270","messageId":"CAC05385KQPXodr-LymXVK97fBAp5==M=OBr1mRYueGbG1qcepA@mail.gmail.com","threadId":"49438","inReplyTo":"20190124212608.GD16114@sigill.intra.peff.net","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-01-31T20:53:24Z","receivedAt":"2019-01-31T20:53:52Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"So where does that leave us for this series? We could move hashmap\nback into used_atom, but if a user entered\n--format=\"%(worktreepath)%(worktreepath:)\" we'd end up freeing\nworktrees twice. Not that that should stop us - that scenario is one\nwhere user input isn't sensible and personally I don't think it's\nnecessary to protect against such things (unless the user was\nreasonably confused, but I don't see that as the case here).\n\nI agree with Jeff that a ref-filter \"context\" would help. And in more\nways than one, it could help us decide ahead of time whether to check\nif a ref is a branch or a tag before doing a hashmap lookup or just\nskip the check (i.e. if there are no tags within the context, the\ncheck would only add cost). But I do believe that that would be\noutside the scope of this series.\n\nI think leaving it as globals is a tiny bit safer and also makes it\neasier to pack it into a context if/when we decide to do that work,\nbut as always I'm open to other interpretations.\n\n\nOn Thu, Jan 24, 2019 at 1:26 PM Jeff King <peff@peff.net> wrote:\n>\n> On Thu, Jan 24, 2019 at 11:30:20AM -0800, Junio C Hamano wrote:\n>\n> > Jeff King <peff@peff.net> writes:\n> >\n> > > What if you have other atoms that need worktrees? E.g., does\n> > > %(worktreepath:foo) use the same used_atom slot? What if we have another\n> > > worktree-related atom?\n> > > ...\n> > > And that one is a good example where we _do_ need the global, because we\n> > > already have multiple atoms pulling from it.\n> >\n> > I guess that we broke the original atom design by mistake when we\n> > added \":<modifiers>\" support.  There should have been one layer of\n> > indirection that binds the instances of the same atom with different\n> > modifiers together---I agree with you that we cannot avoid globals\n> > without fixing that mistake first.\n>\n> Yes, that's one way to fix it.\n>\n> I actually think the biggest mistake is having that used_atoms list in\n> the first place, as we iterate over it several times asking \"can we fill\n> this in yet?\". The way pretty.c does it is just to incrementally parse\n> the commit, saving intermediate results. And in cat-file.c, we figure\n> out what we need ahead of time in a single pass, and then just fill it\n> in for each object (which sort of works out the same, but doesn't\n> require that the parsing needed for item X is a strict superset of item\n> Y).\n>\n> So I'd much rather see us parse the format into a real tree of nodes,\n> and figure out (once) which properties of each object are required to\n> fulfill that. Then for each object, we grab those properties, and then\n> walk the tree to generate the output string.\n>\n> -Peff\n"},{"id":"368273","messageId":"xmqqef8s1p3d.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190124212608.GD16114@sigill.intra.peff.net","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-01-31T21:42:14Z","receivedAt":"2019-01-31T21:42:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, Jan 24, 2019 at 11:30:20AM -0800, Junio C Hamano wrote:\n>\n>> Jeff King <peff@peff.net> writes:\n>> \n>> > What if you have other atoms that need worktrees? E.g., does\n>> > %(worktreepath:foo) use the same used_atom slot? What if we have another\n>> > worktree-related atom?\n>> > ...\n>> > And that one is a good example where we _do_ need the global, because we\n>> > already have multiple atoms pulling from it.\n>> \n>> I guess that we broke the original atom design by mistake when we\n>> added \":<modifiers>\" support.  There should have been one layer of\n>> indirection that binds the instances of the same atom with different\n>> modifiers together---I agree with you that we cannot avoid globals\n>> without fixing that mistake first.\n>\n> Yes, that's one way to fix it.\n>\n> I actually think the biggest mistake is having that used_atoms list in\n> the first place, as we iterate over it several times asking \"can we fill\n> this in yet?\". The way pretty.c does it is just to incrementally parse\n> the commit, saving intermediate results. And in cat-file.c, we figure\n> out what we need ahead of time in a single pass, and then just fill it\n> in for each object (which sort of works out the same, but doesn't\n> require that the parsing needed for item X is a strict superset of item\n> Y).\n>\n> So I'd much rather see us parse the format into a real tree of nodes,\n> and figure out (once) which properties of each object are required to\n> fulfill that. Then for each object, we grab those properties, and then\n> walk the tree to generate the output string.\n\nThat sounds like a sensible longer-term strategy.  Let's however\nleave it outside the scope of this change.\n"},{"id":"368279","messageId":"20190131232057.GA3843@sigill.intra.peff.net","threadId":"49438","inReplyTo":"xmqqef8s1p3d.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-31T23:20:58Z","receivedAt":"2019-01-31T23:21:04Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 31, 2019 at 01:42:14PM -0800, Junio C Hamano wrote:\n\n> > So I'd much rather see us parse the format into a real tree of nodes,\n> > and figure out (once) which properties of each object are required to\n> > fulfill that. Then for each object, we grab those properties, and then\n> > walk the tree to generate the output string.\n> \n> That sounds like a sensible longer-term strategy.  Let's however\n> leave it outside the scope of this change.\n\nYeah, sorry if I got us too far afield. It's definitely out of scope for\nthis series. The takeaway I was trying to get at is that storing the\nworktree map as a static global is actually pretty reasonable given the\ncurrent design.\n\n-Peff\n"},{"id":"368280","messageId":"20190131232146.GA7260@sigill.intra.peff.net","threadId":"49438","inReplyTo":"CAC05385KQPXodr-LymXVK97fBAp5==M=OBr1mRYueGbG1qcepA@mail.gmail.com","subject":"Re: [PATCH v6 1/3] ref-filter: add worktreepath atom","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-01-31T23:21:47Z","receivedAt":"2019-01-31T23:21:52Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Jan 31, 2019 at 12:53:24PM -0800, Nickolai Belakovski wrote:\n\n> So where does that leave us for this series? We could move hashmap\n> back into used_atom, but if a user entered\n> --format=\"%(worktreepath)%(worktreepath:)\" we'd end up freeing\n> worktrees twice. Not that that should stop us - that scenario is one\n> where user input isn't sensible and personally I don't think it's\n> necessary to protect against such things (unless the user was\n> reasonably confused, but I don't see that as the case here).\n> \n> I agree with Jeff that a ref-filter \"context\" would help. And in more\n> ways than one, it could help us decide ahead of time whether to check\n> if a ref is a branch or a tag before doing a hashmap lookup or just\n> skip the check (i.e. if there are no tags within the context, the\n> check would only add cost). But I do believe that that would be\n> outside the scope of this series.\n> \n> I think leaving it as globals is a tiny bit safer and also makes it\n> easier to pack it into a context if/when we decide to do that work,\n> but as always I'm open to other interpretations.\n\nYeah, I agree with this: global for now, and then easily moved into a\ncontext struct later (along with all the other existing globals).\n\n-Peff\n"},{"id":"368377","messageId":"20190201220420.36216-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"[PATCH v7 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T22:04:17Z","receivedAt":"2019-02-01T22:04:30Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\n\nMoved initialization of ref_to_worktree_map outside of atom parser. Other minor fixes.\n\nPut the hashmap and the worktree struct in the same struct, to make it more obvious that\nthey are to be initialized and free'd together.\n\nTravis CI results: https://travis-ci.org/nbelakovski/git/builds/487642061\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: Mark and color a branch differently if it is checked out in a\n    linked worktree\n  branch: Add an extra verbose output displaying worktree path for refs\n    checked out in a linked worktree\n\n Documentation/git-branch.txt       | 21 +++++-----\n Documentation/git-for-each-ref.txt |  5 +++\n builtin/branch.c                   | 16 ++++++--\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  |  8 ++--\n t/t3203-branch-output.sh           | 21 ++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 7 files changed, 147 insertions(+), 17 deletions(-)\n\n-- \n2.14.2\n\n"},{"id":"368378","messageId":"20190201220420.36216-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190201220420.36216-1-nbelakovski@gmail.com","subject":"[PATCH v7 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T22:04:18Z","receivedAt":"2019-02-01T22:04:33Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom providing the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  5 +++\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 15 ++++++++\n 3 files changed, 98 insertions(+)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 774cecc7ed..6dcd39f6f6 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -214,6 +214,11 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. Empty string\n+\totherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 422a9c9ae3..e46608476d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -75,6 +77,27 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct ref_to_worktree_entry {\n+\tstruct hashmap_entry ent; /* must be the first member! */\n+\tstruct worktree *wt; /* key is wt->head_ref */\n+};\n+\n+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,\n+\t\t\t\t      const void *existing_hashmap_entry_to_test,\n+\t\t\t\t      const void *key,\n+\t\t\t\t      const void *keydata_aka_refname)\n+{\n+\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n+\tconst struct ref_to_worktree_entry *k = key;\n+\treturn strcmp(e->wt->head_ref,\n+\t\tkeydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n+}\n+\n+static struct ref_to_worktree_map {\n+\tstruct hashmap map;\n+\tstruct worktree **worktrees;\n+} ref_to_worktree_map;\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -480,6 +503,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1525,6 +1549,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)\n+{\n+\tint i;\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct ref_to_worktree_entry *entry;\n+\t\t\tentry = xmalloc(sizeof(*entry));\n+\t\t\tentry->wt = worktrees[i];\n+\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\n+\t\t\thashmap_add(map, entry);\n+\t\t}\n+\t}\n+}\n+\n+static void lazy_init_worktree_map(void)\n+{\n+\tif (ref_to_worktree_map.worktrees)\n+\t\treturn;\n+\n+\tref_to_worktree_map.worktrees = get_worktrees(0);\n+\thashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);\n+\tpopulate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);\n+}\n+\n+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct hashmap_entry entry;\n+\tstruct ref_to_worktree_entry *lookup_result;\n+\n+\tlazy_init_worktree_map();\n+\n+\thashmap_entry_init(&entry, strhash(ref->refname));\n+\tlookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);\n+\n+\tif (lookup_result)\n+\t\treturn xstrdup(lookup_result->wt->path);\n+\telse\n+\t\treturn xstrdup(\"\");\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (starts_with(name, \"worktreepath\")) {\n+\t\t\tif (ref->kind == FILTER_REFS_BRANCHES)\n+\t\t\t\tv->s = get_worktree_path(atom, ref);\n+\t\t\telse\n+\t\t\t\tv->s = xstrdup(\"\");\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2045,6 +2118,11 @@ void ref_array_clear(struct ref_array *array)\n \t\tfree_array_item(array->items[i]);\n \tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n+\tif (ref_to_worktree_map.worktrees) {\n+\t\thashmap_free(&(ref_to_worktree_map.map), 1);\n+\t\tfree_worktrees(ref_to_worktree_map.worktrees);\n+\t\tref_to_worktree_map.worktrees = NULL;\n+\t}\n }\n \n static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..87e0222ea1 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-EOF &&\n+\tmaster: $(pwd)\n+\tmaster_worktree: $(pwd)/worktree_dir\n+\tside: not checked out\n+\tEOF\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"368379","messageId":"20190201220420.36216-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190201220420.36216-1-nbelakovski@gmail.com","subject":"[PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T22:04:19Z","receivedAt":"2019-02-01T22:04:35Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nThe output of git branch is modified to mark branches checkout out in a\nlinked worktree with a \"+\" and color them in cyan (in contrast to the\ncurrent branch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to communicate to the user that the branches that are\nmarked or colored will behave differently from other branches if the user\nattempts to check them out or delete them, since branches checked out in\nanother worktree cannot be checked out or deleted.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt | 15 ++++++++-------\n builtin/branch.c             | 12 ++++++++----\n t/t3200-branch.sh            |  8 ++++----\n t/t3203-branch-output.sh     | 21 +++++++++++++++++++++\n 4 files changed, 41 insertions(+), 15 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex bf5316ffa9..b3eca6ffdc 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -26,13 +26,14 @@ DESCRIPTION\n -----------\n \n If `--list` is given, or if there are no non-option arguments, existing\n-branches are listed; the current branch will be highlighted with an\n-asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n-and option `-a` shows both local and remote branches. If a `<pattern>`\n-is given, it is used as a shell wildcard to restrict the output to\n-matching branches. If multiple patterns are given, a branch is shown if\n-it matches any of the patterns.  Note that when providing a\n-`<pattern>`, you must use `--list`; otherwise the command is interpreted\n+branches are listed; the current branch will be highlighted in green and\n+marked with an asterisk.  Any branches checked out in linked worktrees will\n+be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n+remote-tracking branches to be listed, and option `-a` shows both local and\n+remote branches. If a `<pattern>` is given, it is used as a shell wildcard to\n+restrict the output to matching branches. If multiple patterns are given, a\n+branch is shown if it matches any of the patterns.  Note that when providing\n+a `<pattern>`, you must use `--list`; otherwise the command is interpreted\n as branch creation.\n \n With `--contains`, shows only the branches that contain the named commit\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 1be727209b..c2a86362bb 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..e404f6e23c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '\n test_expect_success 'git branch --column' '\n \tCOLUMNS=81 git branch --column=column >actual &&\n \tcat >expected <<\\EOF &&\n-  a/b/c     bam       foo       l       * master    n         o/p       r\n+  a/b/c   + bam       foo       l       * master    n         o/p       r\n   abc       bar       j/k       m/m       master2   o/o       q\n EOF\n \ttest_cmp expected actual\n@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '\n \tcat >expected <<EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\n@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '\n \tgit config --unset column.branch &&\n \tgit config --unset column.ui &&\n \tcat >expected <<\\EOF &&\n-  a/b/c   bam   foo   l   * master    n     o/p   r\n+  a/b/c + bam   foo   l   * master    n     o/p   r\n   abc     bar   j/k   m/m   master2   o/o   q\n EOF\n \ttest_cmp expected actual\n@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '\n \tcat >expected <<\\EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614c..94ab05ad59 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n++ <CYAN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+\ttest_terminal git branch >actual.raw &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"368380","messageId":"20190201220420.36216-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190201220420.36216-1-nbelakovski@gmail.com","subject":"[PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T22:04:20Z","receivedAt":"2019-02-01T22:04:36Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt | 6 ++++--\n builtin/branch.c             | 4 ++++\n 2 files changed, 8 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex b3eca6ffdc..778be7080f 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.\n \tWhen in list mode,\n \tshow sha1 and commit subject line for each head, along with\n \trelationship to upstream branch (if any). If given twice, print\n-\tthe name of the upstream branch, as well (see also `git remote\n-\tshow <remote>`).\n+\tthe path of the linked worktree, if applicable (not applicable\n+\tfor main worktree since user's path will already be in main\n+\tworktree) and the name of the upstream branch, as well (see also\n+\t`git remote show <remote>`).\n \n -q::\n --quiet::\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex c2a86362bb..0b8ba9e4c5 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n \t\tif (filter->verbose > 1)\n+\t\t{\n+\t\t\tstrbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n \t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n+\t\t}\n \t\telse\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)\");\n \n-- \n2.14.2\n\n"},{"id":"368381","messageId":"CAPig+cSfw=dun__contMMiHrdsZPPN68U4UzfBGz4Yt8DwO7mQ@mail.gmail.com","threadId":"49438","inReplyTo":"20190201220420.36216-2-nbelakovski@gmail.com","subject":"Re: [PATCH v7 1/3] ref-filter: add worktreepath atom","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-02-01T22:20:37Z","receivedAt":"2019-02-01T22:20:52Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:\n> Add an atom providing the path of the linked worktree where this ref is\n> checked out, if it is checked out in any linked worktrees, and empty\n> string otherwise.\n>\n> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n> ---\n> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n> @@ -214,6 +214,11 @@ symref::\n> +worktreepath::\n> +       The absolute path to the worktree in which the ref is checked\n> +       out, if it is checked out in any linked worktree. Empty string\n> +       otherwise.\n\nThis may have been asked previously, but is there a reason this name\nwas chosen over the more extensible \"worktree:\" with \"path\" as a\nmodifier (i.e. \"worktree:path\")? I scanned the thread a couple weeks\nago and did see mention of \"worktree:path\" but did not find any\nfollowup. I ask because it's conceivable that someone in the future\nmight want to retrieve other information about the worktree beyond its\npath (such as whether it's bare or detached, etc.). By using the form\n\"worktree:<foo>\", we leave that door open. (I'm not suggesting that\nthis patch series needs to implement fetching of any of the other\nworktree properties, but just asking if \"worktree:<foo>\" should be\nconsidered.)\n\n> diff --git a/ref-filter.c b/ref-filter.c\n> @@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n>                 if (starts_with(name, \"refname\"))\n>                         refname = get_refname(atom, ref);\n> +               else if (starts_with(name, \"worktreepath\")) {\n\nI think this was brought up previously, but shouldn't this be strcmp()\nrather than starts_with()?\n\n(starts_with() would be appropriate, if you went with the suggested\n\"worktree:<foo>\".)\n\n> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\n> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n> +test_expect_success '\"add\" a worktree' '\n> +       mkdir worktree_dir &&\n> +       git worktree add -b master_worktree worktree_dir master\n> +'\n\nI don't think 'mkdir' is needed since \"git worktree add\" should create\nthe directory itself.\n\n> +test_expect_success 'validate worktree atom' '\n> +       cat >expect <<-EOF &&\n> +       master: $(pwd)\n> +       master_worktree: $(pwd)/worktree_dir\n> +       side: not checked out\n> +       EOF\n> +       git for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n> +       test_cmp expect actual\n> +'\n\nIf this is the only test using that newly-created worktree, it might\nmake sense to squash the two tests together.\n"},{"id":"368382","messageId":"CAPig+cT0OY3vcjjoMUjaZ9JhJ2nKqyqbv4qL1ExiDw3h5GUw4Q@mail.gmail.com","threadId":"49438","inReplyTo":"20190201220420.36216-4-nbelakovski@gmail.com","subject":"Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2019-02-01T22:27:48Z","receivedAt":"2019-02-01T22:28:03Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:\n> Subject: branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree\n\nOverlong subject. Perhaps shorten it to:\n\n    branch: display worktree path in -v -v mode\n\nor something, and use the longer description as the rest of the body\nof the commit message.\n\n> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n> ---\n> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> @@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.\n>         When in list mode,\n>         show sha1 and commit subject line for each head, along with\n>         relationship to upstream branch (if any). If given twice, print\n> -       the name of the upstream branch, as well (see also `git remote\n> -       show <remote>`).\n> +       the path of the linked worktree, if applicable (not applicable\n> +       for main worktree since user's path will already be in main\n> +       worktree) and the name of the upstream branch, as well (see also\n> +       `git remote show <remote>`).\n\nI'm not sure I understand the \"not applicable\" explanation. When you\nsay \"user's path\", do you mean the current working directory? What\nhappens if the command is invoked from within one of the linked\nworktrees (not from within the main worktree)?\n"},{"id":"368384","messageId":"CAC05386a+FZP8hGawYsfZrmA--JuZBqi_aop7202JQnJEfKyJg@mail.gmail.com","threadId":"49438","inReplyTo":"CAPig+cSfw=dun__contMMiHrdsZPPN68U4UzfBGz4Yt8DwO7mQ@mail.gmail.com","subject":"Re: [PATCH v7 1/3] ref-filter: add worktreepath atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T22:41:30Z","receivedAt":"2019-02-01T22:42:02Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Fri, Feb 1, 2019 at 2:20 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:\n> > Add an atom providing the path of the linked worktree where this ref is\n> > checked out, if it is checked out in any linked worktrees, and empty\n> > string otherwise.\n> >\n> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n> > ---\n> > diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\n> > @@ -214,6 +214,11 @@ symref::\n> > +worktreepath::\n> > +       The absolute path to the worktree in which the ref is checked\n> > +       out, if it is checked out in any linked worktree. Empty string\n> > +       otherwise.\n>\n> This may have been asked previously, but is there a reason this name\n> was chosen over the more extensible \"worktree:\" with \"path\" as a\n> modifier (i.e. \"worktree:path\")? I scanned the thread a couple weeks\n> ago and did see mention of \"worktree:path\" but did not find any\n> followup. I ask because it's conceivable that someone in the future\n> might want to retrieve other information about the worktree beyond its\n> path (such as whether it's bare or detached, etc.). By using the form\n> \"worktree:<foo>\", we leave that door open. (I'm not suggesting that\n> this patch series needs to implement fetching of any of the other\n> worktree properties, but just asking if \"worktree:<foo>\" should be\n> considered.)\n>\n\nThere's been a little back and forth on it, but my understanding is\nthat using the colon separator bypasses the caching mechanism in the\natoms, so every instance of \"worktree:path\" in a format string would\nrequire a lookup. Future atoms should be along the lines of\n\"worktreeisdetached\", \"worktreeisbare\", etc. This is consistent with\nseveral of the other atoms, like objecttype/size/name,\ncomitter/name/email/date.\n\n> > diff --git a/ref-filter.c b/ref-filter.c\n> > @@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n> >                 if (starts_with(name, \"refname\"))\n> >                         refname = get_refname(atom, ref);\n> > +               else if (starts_with(name, \"worktreepath\")) {\n>\n> I think this was brought up previously, but shouldn't this be strcmp()\n> rather than starts_with()?\n>\n> (starts_with() would be appropriate, if you went with the suggested\n> \"worktree:<foo>\".)\n\nNot sure about it being brought up previously. starts_with seemed\nconsistent with other uses but now I see there's several other\ninstance of strcmp in populate value. Seems like a reasonable thing to\nchange. I had previously implemented \"worktree:<foo>\" and must've left\nit alone after we went with worktreepath.\n\n>\n> > diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\n> > @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '\n> > +test_expect_success '\"add\" a worktree' '\n> > +       mkdir worktree_dir &&\n> > +       git worktree add -b master_worktree worktree_dir master\n> > +'\n>\n> I don't think 'mkdir' is needed since \"git worktree add\" should create\n> the directory itself.\n>\n> > +test_expect_success 'validate worktree atom' '\n> > +       cat >expect <<-EOF &&\n> > +       master: $(pwd)\n> > +       master_worktree: $(pwd)/worktree_dir\n> > +       side: not checked out\n> > +       EOF\n> > +       git for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n> > +       test_cmp expect actual\n> > +'\n>\n> If this is the only test using that newly-created worktree, it might\n> make sense to squash the two tests together.\n\nSure, can do, on both points.\n"},{"id":"368385","messageId":"CAC05385Kr7Sg7fwNx+EUkfTKoPHBiguE0HTP4faFwvAQYnKckA@mail.gmail.com","threadId":"49438","inReplyTo":"CAPig+cT0OY3vcjjoMUjaZ9JhJ2nKqyqbv4qL1ExiDw3h5GUw4Q@mail.gmail.com","subject":"Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T22:45:31Z","receivedAt":"2019-02-01T22:46:01Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Fri, Feb 1, 2019 at 2:28 PM Eric Sunshine <sunshine@sunshineco.com> wrote:\n>\n> On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:\n> > Subject: branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree\n>\n> Overlong subject. Perhaps shorten it to:\n>\n>     branch: display worktree path in -v -v mode\n>\n> or something, and use the longer description as the rest of the body\n> of the commit message.\n\nOK\n\n>\n> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n> > ---\n> > diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> > @@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.\n> >         When in list mode,\n> >         show sha1 and commit subject line for each head, along with\n> >         relationship to upstream branch (if any). If given twice, print\n> > -       the name of the upstream branch, as well (see also `git remote\n> > -       show <remote>`).\n> > +       the path of the linked worktree, if applicable (not applicable\n> > +       for main worktree since user's path will already be in main\n> > +       worktree) and the name of the upstream branch, as well (see also\n> > +       `git remote show <remote>`).\n>\n> I'm not sure I understand the \"not applicable\" explanation. When you\n> say \"user's path\", do you mean the current working directory? What\n> happens if the command is invoked from within one of the linked\n> worktrees (not from within the main worktree)?\n\nI should correct that to say \"current worktree\" as opposed to main,\nsince that's what HEAD will give. And yes user's path means cwd. Does\nthat make more sense?\n"},{"id":"368387","messageId":"xmqqwomjw25s.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190201220420.36216-1-nbelakovski@gmail.com","subject":"Re: [PATCH v7 0/3]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-01T22:28:04Z","receivedAt":"2019-02-01T22:54:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n>   ref-filter: add worktreepath atom\n>   branch: Mark and color a branch differently if it is checked out in a\n>     linked worktree\n>   branch: Add an extra verbose output displaying worktree path for refs\n>     checked out in a linked worktree\n\nAs you can see in \"git shortlog --no-merges\", later two patches\nwould look quite out of place by having overlong title and starting\nthe description(i.e. after \"<area>: \") in a capital letter.\n\nIt is still not clear why we would want 2/3, even though I think 3/3\nis a good idea.\n\nThis round signs off all the three patches, which is a great\nimprovement ;-)\n\n"},{"id":"368388","messageId":"xmqqr2crw25r.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190201220420.36216-2-nbelakovski@gmail.com","subject":"Re: [PATCH v7 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-01T22:31:32Z","receivedAt":"2019-02-01T22:54:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> +static void lazy_init_worktree_map(void)\n> +{\n> +\tif (ref_to_worktree_map.worktrees)\n> +\t\treturn;\n> +\n> +\tref_to_worktree_map.worktrees = get_worktrees(0);\n> +\thashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);\n> +\tpopulate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);\n> +}\n> +\n> +static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n> +{\n> +\tstruct hashmap_entry entry;\n> +\tstruct ref_to_worktree_entry *lookup_result;\n> +\n> +\tlazy_init_worktree_map();\n> +\n> +\thashmap_entry_init(&entry, strhash(ref->refname));\n> +\tlookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);\n> +\n> +\tif (lookup_result)\n> +\t\treturn xstrdup(lookup_result->wt->path);\n> +\telse\n> +\t\treturn xstrdup(\"\");\n> +}\n\nMakes more sense than the previous round; much simpler to have\nlazy-init in this function.\n\nThanks.\n"},{"id":"368389","messageId":"xmqqftt7w25q.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190201220420.36216-4-nbelakovski@gmail.com","subject":"Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-01T22:53:28Z","receivedAt":"2019-02-01T22:54:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> @@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.\n>  \tWhen in list mode,\n>  \tshow sha1 and commit subject line for each head, along with\n>  \trelationship to upstream branch (if any). If given twice, print\n> -\tthe name of the upstream branch, as well (see also `git remote\n> -\tshow <remote>`).\n> +\tthe path of the linked worktree, if applicable (not applicable\n> +\tfor main worktree since user's path will already be in main\n> +\tworktree) and the name of the upstream branch, as well (see also\n> +\t`git remote show <remote>`).\n\nIt is unclear what you mean by \"user's path\"; I take it as the\n$(pwd) at least for now for the purpose of this review, but then\nI am not sure if I agree with that justification part \"since...\"\n\nIf I start from a normal repository at /home/gitster/main.git,\ncreate a linked worktree of it at /home/gitster/alt.git, chdir to\n/home/gitster/alt.git and ask \"git branch -v -v\", then the branch\nthat is checked out in the main.git \"main worktree\" is not shown?\n\nIf the rule were \"a branch that is checked out in one of the\nworktrees connected to the repository is shown with the path to that\nworktree\" (i.e. no exception), I would understand it.  If the rule\nwere \"a branch that is ... (the same sentence), unless it is the\nbranch that is checked out in the *current* worktree\", then I would\nunderstand it too.\n\nPuzzled.\n\nIn any case, please add a test or two to protect this feature from\nunintended future breakages.\n\nThanks.\n\n>  \n>  -q::\n>  --quiet::\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index c2a86362bb..0b8ba9e4c5 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n>  \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n>  \n>  \t\tif (filter->verbose > 1)\n> +\t\t{\n> +\t\t\tstrbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n> +\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n>  \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n>  \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n>  \t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n> +\t\t}\n>  \t\telse\n>  \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)\");\n"},{"id":"368390","messageId":"xmqqlg2zw25q.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190201220420.36216-3-nbelakovski@gmail.com","subject":"Re: [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-01T22:34:45Z","receivedAt":"2019-02-01T22:54:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n>  If `--list` is given, or if there are no non-option arguments, existing\n> -branches are listed; the current branch will be highlighted with an\n> -asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n> -and option `-a` shows both local and remote branches. If a `<pattern>`\n> -is given, it is used as a shell wildcard to restrict the output to\n> -matching branches. If multiple patterns are given, a branch is shown if\n> -it matches any of the patterns.  Note that when providing a\n> -`<pattern>`, you must use `--list`; otherwise the command is interpreted\n> +branches are listed; the current branch will be highlighted in green and\n> +marked with an asterisk.  Any branches checked out in linked worktrees will\n> +be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n> +remote-tracking branches to be listed, and option `-a` shows both local and\n> +remote branches. If a `<pattern>` is given, it is used as a shell wildcard to\n> +restrict the output to matching branches. If multiple patterns are given, a\n> +branch is shown if it matches any of the patterns.  Note that when providing\n> +a `<pattern>`, you must use `--list`; otherwise the command is interpreted\n>  as branch creation.\n\nI had to apply and then use --color-words to see what is going on.\nPlease avoid unnecessary reflowing of the text that makes the patch\nharder than necessary to read.\n\nI still do not quite see the point of this step in the series,\nthough.\n"},{"id":"368391","messageId":"CAC05386O=9CxkgUNGoYbwEOXiPPcAD7H5Kn97iCqPc1X7kAh6w@mail.gmail.com","threadId":"49438","inReplyTo":"xmqqftt7w25q.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T23:06:31Z","receivedAt":"2019-02-01T23:14:03Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:\n\n>\n> If the rule were \"a branch that is checked out in one of the\n> worktrees connected to the repository is shown with the path to that\n> worktree\" (i.e. no exception), I would understand it.  If the rule\n> were \"a branch that is ... (the same sentence), unless it is the\n> branch that is checked out in the *current* worktree\", then I would\n> understand it too.\n>\n\nIt is the latter, as in, yes, I meant \"current\". I will update the docs as such.\n\n>\n> In any case, please add a test or two to protect this feature from\n> unintended future breakages.\n>\n> Thanks.\n>\n\nWill do.\n"},{"id":"368392","messageId":"CAC05385Tnn+2x7Xx-Cy43S5aqjjY2gVkwcEzy+2=vYR72tNekA@mail.gmail.com","threadId":"49438","inReplyTo":"xmqqlg2zw25q.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T23:12:44Z","receivedAt":"2019-02-01T23:20:22Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n>\n> I had to apply and then use --color-words to see what is going on.\n> Please avoid unnecessary reflowing of the text that makes the patch\n> harder than necessary to read.\n\nI was trying to keep the line length consistent. How else can I accomplish that?\n"},{"id":"368393","messageId":"CAC05386CRvmLUbG+O89=i9oXsOSPsoP3VpnrR-w1HJhMa6U7AA@mail.gmail.com","threadId":"49438","inReplyTo":"xmqqwomjw25s.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 0/3]","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-01T23:31:52Z","receivedAt":"2019-02-01T23:32:23Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:\n>\n>\n> As you can see in \"git shortlog --no-merges\", later two patches\n> would look quite out of place by having overlong title and starting\n> the description(i.e. after \"<area>: \") in a capital letter.\n\nHadn't looked at it that way. OK, will shorten/uncapitalize.\n\n>\n> It is still not clear why we would want 2/3, even though I think 3/3\n> is a good idea.\n>\nIt's interesting to me that you like 3/3 but not 2/3 :)\n\nMy apologies for restating the commit message, but the point of 2/3 is\nto communicate to the user that highlighted/marked branches will\nbehave differently from unhighlighted/unmarked branches for commands\nto check out or delete. I think this is useful since it gives the user\nactionable information ahead of time, as opposed to providing that\ninformation upon failure of checkout/delete. It also makes sense since\n'git branch' is already highlighting the current branch, i.e. this is\njust an extension of that idea.\n\nAs we've stated earlier in this thread, 1/3 allows for users to\nimplement this on their own with a custom git branch format.\nPersonally I think there's value in making it default, since it's\nadding information in a minimally intrusive way. I do believe that\nmerely adding information isn't a good enough reason to change things,\nas information overload is a real thing, but in this case the output\nisn't changed for anyone not using a worktree (same goes for 3/3), and\nfor someone using a worktree this provides useful and actionable\ninformation, IMO.\n\nDoes that change your mind at all?\n"},{"id":"368396","messageId":"20190202012210.46950-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"CAC05386O=9CxkgUNGoYbwEOXiPPcAD7H5Kn97iCqPc1X7kAh6w@mail.gmail.com","subject":"[RFC] Sample of test for git branch -vv","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-02T01:22:10Z","receivedAt":"2019-02-02T01:22:23Z","isPatch":false,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nI remember now why I didn't add a test for this one earlier.\n\nTesting git branch -vv is a little tricky for a couple reasons.\n\nFor one thing, the output contains commit hashes, so the 'expect' file cannot be simply static.\n\nFor another, the output doesn't have clear delimiters for all columns, so trying to extract only\nthe commit hashes is tough.\n\nI took the approach of stripping all information before and including the commit hashes.\n\nYou can see below how I did this. For the patch with worktreepath information, the worktreepath would\nappear before the commit message on just one of those lines, but I crafted this patch so that it can be applied\nto master.\n\nThis works, but it's rather awkward and ugly. Does anyone have better suggestions either for how to test or\nhow to implement?\n\n---\n t/t3203-branch-output.sh | 20 +++++++++++++++++++-\n 1 file changed, 19 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex 94ab05ad59..b836ca21fa 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -285,4 +284,22 @@ test_expect_success '--color overrides auto-color' '\n \ttest_cmp expect.color actual\n '\n \n+test_expect_success 'test verbose verbose output' '\n+\tcat >expect <<-EOF &&\n+\tone\n+\tone\n+\ttwo\n+\tone\n+\ttwo\n+\ttwo\n+\ttwo\n+\tEOF\n+\tgit branch -vv >tmp &&\n+\thead -1 tmp >tmp2 &&\n+\tSUBSTRLENGTH=$(awk \"{print index(\\$0, \\\"one\\\")}\" <tmp2) &&\n+\tawk -v len=\"$SUBSTRLENGTH\" \"{print substr(\\$0,len,length(\\$0))}\" <tmp >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"368466","messageId":"xmqqsgx3v2sy.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"CAC05386a+FZP8hGawYsfZrmA--JuZBqi_aop7202JQnJEfKyJg@mail.gmail.com","subject":"Re: [PATCH v7 1/3] ref-filter: add worktreepath atom","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-04T18:14:37Z","receivedAt":"2019-02-04T18:14:42Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nickolai Belakovski <nbelakovski@gmail.com> writes:\n\n> There's been a little back and forth on it, but my understanding is\n> that using the colon separator bypasses the caching mechanism in the\n> atoms, so every instance of \"worktree:path\" in a format string would\n> require a lookup.\n\nWould that be a problem, though?  You now have a singleton hashmap\nthat is a file-scope global not tied to any particular atom, so...?\n"},{"id":"368467","messageId":"xmqqo97rv2m0.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"CAC05385Tnn+2x7Xx-Cy43S5aqjjY2gVkwcEzy+2=vYR72tNekA@mail.gmail.com","subject":"Re: [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-04T18:18:47Z","receivedAt":"2019-02-04T18:18:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nickolai Belakovski <nbelakovski@gmail.com> writes:\n\n> On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:\n>>\n>>\n>> I had to apply and then use --color-words to see what is going on.\n>> Please avoid unnecessary reflowing of the text that makes the patch\n>> harder than necessary to read.\n>\n> I was trying to keep the line length consistent. How else can I accomplish that?\n\nBy relying on the fact that in the final output it does not matter\nhow the sources look like, e.g.\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex bf5316ffa9..b64b3bf458 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -27,7 +27,9 @@ DESCRIPTION\n \n If `--list` is given, or if there are no non-option arguments, existing\n branches are listed; the current branch will be highlighted with an\n-asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n+asterisk and shown in green.  Any branch checked out in linked worktrees\n+is shown in cyan and marked with a plus sign. Option `-r` causes the\n+remote-tracking branches to be listed,\n and option `-a` shows both local and remote branches. If a `<pattern>`\n is given, it is used as a shell wildcard to restrict the output to\n matching branches. If multiple patterns are given, a branch is shown if\n"},{"id":"369524","messageId":"CAC05384mbqpq5QZJiXvVoKZyCx21ATM5TcKscnuKdbR0wi5o=w@mail.gmail.com","threadId":"49438","inReplyTo":"xmqqsgx3v2sy.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v7 1/3] ref-filter: add worktreepath atom","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-18T10:09:43Z","receivedAt":"2019-02-18T10:10:16Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"Well, it sounded like we didn't like the \":\" extender from another\nconversation on this thread. Do you think this patch should move back\nin that direction?\n\nOn Tue, Feb 5, 2019 at 3:14 AM Junio C Hamano <gitster@pobox.com> wrote:\n>\n> Nickolai Belakovski <nbelakovski@gmail.com> writes:\n>\n> > There's been a little back and forth on it, but my understanding is\n> > that using the colon separator bypasses the caching mechanism in the\n> > atoms, so every instance of \"worktree:path\" in a format string would\n> > require a lookup.\n>\n> Would that be a problem, though?  You now have a singleton hashmap\n> that is a file-scope global not tied to any particular atom, so...?\n"},{"id":"369617","messageId":"20190219083123.27686-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"[PATCH v8 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-19T08:31:20Z","receivedAt":"2019-02-19T08:31:52Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nI've made the various cosmetic changes that were suggested, as well as adding tests for 3/3\n\nI don't have a particularly strong opinion on the subject of keeping the atom as \"worktreepath\"\nor changing it to \"worktree:path\". We did feel earlier in this thread that if we went with\n\"worktree:path\", then \"worktree\" is somewhat ambiguous, and that discussion led to deciding to\nhave \"worktree\" return the path,. After that I chose to name it \"worktreepath\" because I like to\nmake things explicit and intuitive.\n\nTravis CI results: https://travis-ci.org/nbelakovski/git/builds/494817576\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: update output to include worktree info\n  branch: add worktree info on verbose output\n\n Documentation/git-branch.txt       | 12 ++++--\n Documentation/git-for-each-ref.txt |  5 +++\n builtin/branch.c                   | 16 ++++++--\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  |  8 ++--\n t/t3203-branch-output.sh           | 38 +++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 11 ++++++\n 7 files changed, 156 insertions(+), 12 deletions(-)\n\n-- \n2.14.2\n"},{"id":"369618","messageId":"20190219083123.27686-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190219083123.27686-1-nbelakovski@gmail.com","subject":"[PATCH v8 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-19T08:31:21Z","receivedAt":"2019-02-19T08:31:56Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom providing the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  5 +++\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 11 ++++++\n 3 files changed, 94 insertions(+)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 774cecc7ed..6dcd39f6f6 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -214,6 +214,11 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. Empty string\n+\totherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 422a9c9ae3..05531b7534 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -75,6 +77,27 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct ref_to_worktree_entry {\n+\tstruct hashmap_entry ent; /* must be the first member! */\n+\tstruct worktree *wt; /* key is wt->head_ref */\n+};\n+\n+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,\n+\t\t\t\t      const void *existing_hashmap_entry_to_test,\n+\t\t\t\t      const void *key,\n+\t\t\t\t      const void *keydata_aka_refname)\n+{\n+\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n+\tconst struct ref_to_worktree_entry *k = key;\n+\treturn strcmp(e->wt->head_ref,\n+\t\tkeydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n+}\n+\n+static struct ref_to_worktree_map {\n+\tstruct hashmap map;\n+\tstruct worktree **worktrees;\n+} ref_to_worktree_map;\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -480,6 +503,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1525,6 +1549,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)\n+{\n+\tint i;\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct ref_to_worktree_entry *entry;\n+\t\t\tentry = xmalloc(sizeof(*entry));\n+\t\t\tentry->wt = worktrees[i];\n+\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\n+\t\t\thashmap_add(map, entry);\n+\t\t}\n+\t}\n+}\n+\n+static void lazy_init_worktree_map(void)\n+{\n+\tif (ref_to_worktree_map.worktrees)\n+\t\treturn;\n+\n+\tref_to_worktree_map.worktrees = get_worktrees(0);\n+\thashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);\n+\tpopulate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);\n+}\n+\n+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct hashmap_entry entry;\n+\tstruct ref_to_worktree_entry *lookup_result;\n+\n+\tlazy_init_worktree_map();\n+\n+\thashmap_entry_init(&entry, strhash(ref->refname));\n+\tlookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);\n+\n+\tif (lookup_result)\n+\t\treturn xstrdup(lookup_result->wt->path);\n+\telse\n+\t\treturn xstrdup(\"\");\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (!strcmp(name, \"worktreepath\")) {\n+\t\t\tif (ref->kind == FILTER_REFS_BRANCHES)\n+\t\t\t\tv->s = get_worktree_path(atom, ref);\n+\t\t\telse\n+\t\t\t\tv->s = xstrdup(\"\");\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2045,6 +2118,11 @@ void ref_array_clear(struct ref_array *array)\n \t\tfree_array_item(array->items[i]);\n \tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n+\tif (ref_to_worktree_map.worktrees) {\n+\t\thashmap_free(&(ref_to_worktree_map.map), 1);\n+\t\tfree_worktrees(ref_to_worktree_map.worktrees);\n+\t\tref_to_worktree_map.worktrees = NULL;\n+\t}\n }\n \n static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..4ad20615d5 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,15 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-EOF &&\n+\tmaster: $(pwd)\n+\tmaster_worktree: $(pwd)/worktree_dir\n+\tside: not checked out\n+\tEOF\n+\tgit worktree add -b master_worktree worktree_dir master &&\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"369619","messageId":"20190219083123.27686-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190219083123.27686-1-nbelakovski@gmail.com","subject":"[PATCH v8 2/3] branch: update output to include worktree info","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-19T08:31:22Z","receivedAt":"2019-02-19T08:31:59Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nThe output of git branch is modified to mark branches checkout out in a\nlinked worktree with a \"+\" and color them in cyan (in contrast to the\ncurrent branch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to communicate to the user that the branches that are\nmarked or colored will behave differently from other branches if the user\nattempts to check them out or delete them, since branches checked out in\nanother worktree cannot be checked out or deleted.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt |  6 ++++--\n builtin/branch.c             | 12 ++++++++----\n t/t3200-branch.sh            |  8 ++++----\n t/t3203-branch-output.sh     | 21 +++++++++++++++++++++\n 4 files changed, 37 insertions(+), 10 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 3bd83a7cbd..f2e5a07d64 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -26,8 +26,10 @@ DESCRIPTION\n -----------\n \n If `--list` is given, or if there are no non-option arguments, existing\n-branches are listed; the current branch will be highlighted with an\n-asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n+branches are listed; the current branch will be highlighted in green and\n+marked with an asterisk.  Any branches checked out in linked worktrees will\n+be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n+remote-tracking branches to be listed,\n and option `-a` shows both local and remote branches. If a `<pattern>`\n is given, it is used as a shell wildcard to restrict the output to\n matching branches. If multiple patterns are given, a branch is shown if\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 1be727209b..c2a86362bb 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..e404f6e23c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '\n test_expect_success 'git branch --column' '\n \tCOLUMNS=81 git branch --column=column >actual &&\n \tcat >expected <<\\EOF &&\n-  a/b/c     bam       foo       l       * master    n         o/p       r\n+  a/b/c   + bam       foo       l       * master    n         o/p       r\n   abc       bar       j/k       m/m       master2   o/o       q\n EOF\n \ttest_cmp expected actual\n@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '\n \tcat >expected <<EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\n@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '\n \tgit config --unset column.branch &&\n \tgit config --unset column.ui &&\n \tcat >expected <<\\EOF &&\n-  a/b/c   bam   foo   l   * master    n     o/p   r\n+  a/b/c + bam   foo   l   * master    n     o/p   r\n   abc     bar   j/k   m/m   master2   o/o   q\n EOF\n \ttest_cmp expected actual\n@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '\n \tcat >expected <<\\EOF &&\n   a/b/c\n   abc\n-  bam\n++ bam\n   bar\n   foo\n   j/k\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ee6787614c..94ab05ad59 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success '\"add\" a worktree' '\n+\tmkdir worktree_dir &&\n+\tgit worktree add -b master_worktree worktree_dir master\n+'\n+\n+cat >expect <<'EOF'\n+* <GREEN>(HEAD detached from fromtag)<RESET>\n+  ambiguous<RESET>\n+  branch-one<RESET>\n+  branch-two<RESET>\n+  master<RESET>\n++ <CYAN>master_worktree<RESET>\n+  ref-to-branch<RESET> -> branch-one\n+  ref-to-remote<RESET> -> origin/branch-one\n+EOF\n+test_expect_success TTY 'worktree colors correct' '\n+\ttest_terminal git branch >actual.raw &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"369620","messageId":"20190219083123.27686-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190219083123.27686-1-nbelakovski@gmail.com","subject":"[PATCH v8 3/3] branch: add worktree info on verbose output","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-02-19T08:31:23Z","receivedAt":"2019-02-19T08:34:01Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nTo display worktree path for refs checked out in a linked worktree\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt |  6 ++++--\n builtin/branch.c             |  4 ++++\n t/t3203-branch-output.sh     | 21 ++++++++++++++++++++-\n 3 files changed, 28 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex f2e5a07d64..326a45f648 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -168,8 +168,10 @@ This option is only applicable in non-verbose mode.\n \tWhen in list mode,\n \tshow sha1 and commit subject line for each head, along with\n \trelationship to upstream branch (if any). If given twice, print\n-\tthe name of the upstream branch, as well (see also `git remote\n-\tshow <remote>`).\n+\tthe path of the linked worktree, if applicable (not applicable\n+\tfor current worktree since user's path will already be in current\n+\tworktree) and the name of the upstream branch, as well (see also\n+\t`git remote show <remote>`).\n \n -q::\n --quiet::\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex c2a86362bb..0b8ba9e4c5 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n \t\tif (filter->verbose > 1)\n+\t\t{\n+\t\t\tstrbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n \t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n+\t\t}\n \t\telse\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)\");\n \ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex 94ab05ad59..012ddde7f2 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -241,7 +241,6 @@ test_expect_success 'git branch --format option' '\n '\n \n test_expect_success '\"add\" a worktree' '\n-\tmkdir worktree_dir &&\n \tgit worktree add -b master_worktree worktree_dir master\n '\n \n@@ -285,4 +284,24 @@ test_expect_success '--color overrides auto-color' '\n \ttest_cmp expect.color actual\n '\n \n+# This test case has some special code to strip the first 30 characters or so\n+# of the output so that we do not have to put commit hashes into the expect\n+test_expect_success 'verbose output lists worktree path' '\n+\tcat >expect <<-EOF &&\n+\tone\n+\tone\n+\ttwo\n+\tone\n+\ttwo\n+\t($(pwd)/worktree_dir) two\n+\ttwo\n+\ttwo\n+\tEOF\n+\tgit branch -vv >tmp &&\n+\tSUBSTRLENGTH=$(head -1 tmp | awk \"{print index(\\$0, \\\"one\\\")}\") &&\n+\tawk -v substrlength=\"$SUBSTRLENGTH\" \"{print substr(\\$0,substrlength,length(\\$0))}\" <tmp >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"369799","messageId":"20190221123646.GA12185@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20190219083123.27686-1-nbelakovski@gmail.com","subject":"Re: [PATCH v8 0/3]","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-02-21T12:36:46Z","receivedAt":"2019-02-21T12:36:49Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 19, 2019 at 05:31:20PM +0900, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> I've made the various cosmetic changes that were suggested, as well as adding tests for 3/3\n> \n> I don't have a particularly strong opinion on the subject of keeping the atom as \"worktreepath\"\n> or changing it to \"worktree:path\". We did feel earlier in this thread that if we went with\n> \"worktree:path\", then \"worktree\" is somewhat ambiguous, and that discussion led to deciding to\n> have \"worktree\" return the path,. After that I chose to name it \"worktreepath\" because I like to\n> make things explicit and intuitive.\n\nI am OK with it either way. We have used \":\" for some variants (e.g.,\nobjectsize:disk). But we have also used long single names with related\nprefixes (e.g., objectname versus objecttype versus objectsize).\n\nPatch 1 looks good to me. Given that we're on v8 and most of the other\ncomments are for patches 2 and 3, I think we might consider graduating\nit separately if the other two are not ready soon. It's independently\nuseful, IMHO.\n\nI have a few comments on the others which I'll leave as replies there.\n\n-Peff\n"},{"id":"369800","messageId":"20190221124408.GA13403@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20190219083123.27686-3-nbelakovski@gmail.com","subject":"Re: [PATCH v8 2/3] branch: update output to include worktree info","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-02-21T12:44:08Z","receivedAt":"2019-02-21T12:44:11Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 19, 2019 at 05:31:22PM +0900, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> The output of git branch is modified to mark branches checkout out in a\n\ns/checkout out/checked out/ ?\n\n> linked worktree with a \"+\" and color them in cyan (in contrast to the\n> current branch, which will still be denoted with a \"*\" and colored in green)\n> \n> This is meant to communicate to the user that the branches that are\n> marked or colored will behave differently from other branches if the user\n> attempts to check them out or delete them, since branches checked out in\n> another worktree cannot be checked out or deleted.\n\nI think this makes sense to have. You cannot \"git checkout\" such a\nmarked branch (since it would conflict with the other worktree), and\nthat alone seems to make it worth marking in the output.\n\n> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> index 3bd83a7cbd..f2e5a07d64 100644\n> --- a/Documentation/git-branch.txt\n> +++ b/Documentation/git-branch.txt\n> @@ -26,8 +26,10 @@ DESCRIPTION\n>  -----------\n>  \n>  If `--list` is given, or if there are no non-option arguments, existing\n> -branches are listed; the current branch will be highlighted with an\n> -asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n> +branches are listed; the current branch will be highlighted in green and\n> +marked with an asterisk.  Any branches checked out in linked worktrees will\n> +be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n> +remote-tracking branches to be listed,\n\nThis makes sense to me.\n\n> -\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n> -\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n> -\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n> +\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n> +\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n> +\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n> +\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n\nMakes sense. The long line is ugly. Our format does not support breaking\nlong lines, though we could break the C string, I think, like:\n\n  strbuf_add(&local,\n\t     \"%%(if)%%(HEAD)\"\n\t       \"%%(then)* %s\"\n\t     \"%%(else)%(if)%%(worktreepath)\"\n\t       \"%%(then)+ %s\"\n\t     \"%%(else)\"\n\t       \"%%(then)  %s\"\n\t     \"%%(end)%%(end)\");\n\nThat's pretty ugly, too, but it at least shows the conditional\nstructure.\n\n> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\n> index ee6787614c..94ab05ad59 100755\n> --- a/t/t3203-branch-output.sh\n> +++ b/t/t3203-branch-output.sh\n> @@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '\n>  \ttest_i18ncmp expect actual\n>  '\n>  \n> +test_expect_success '\"add\" a worktree' '\n> +\tmkdir worktree_dir &&\n> +\tgit worktree add -b master_worktree worktree_dir master\n> +'\n\nThis mkdir gets deleted in the next patch. It should just not be added\nhere.\n\n> +cat >expect <<'EOF'\n> +* <GREEN>(HEAD detached from fromtag)<RESET>\n> +  ambiguous<RESET>\n> +  branch-one<RESET>\n> +  branch-two<RESET>\n> +  master<RESET>\n> ++ <CYAN>master_worktree<RESET>\n> +  ref-to-branch<RESET> -> branch-one\n> +  ref-to-remote<RESET> -> origin/branch-one\n> +EOF\n> +test_expect_success TTY 'worktree colors correct' '\n> +\ttest_terminal git branch >actual.raw &&\n> +\ttest_decode_color <actual.raw >actual &&\n> +\ttest_cmp expect actual\n> +'\n\nWe are not testing the auto-color behavior here, so I think you could\njust use \"git branch --color >actual.raw\" and drop the TTY prerequisite.\nThat's shorter and simpler, and will let your test run on more\nplatforms.\n\n-Peff\n"},{"id":"369801","messageId":"20190221125952.GB13403@sigill.intra.peff.net","threadId":"49438","inReplyTo":"20190219083123.27686-4-nbelakovski@gmail.com","subject":"Re: [PATCH v8 3/3] branch: add worktree info on verbose output","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2019-02-21T12:59:52Z","receivedAt":"2019-02-21T12:59:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, Feb 19, 2019 at 05:31:23PM +0900, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> To display worktree path for refs checked out in a linked worktree\n\nThis would be a good place to describe why this is useful. :)\n\nI do not have an opinion myself. Patch 2 makes a lot of sense to me, but\nI don't know if people would like this one or not. I don't use \"-v\"\nmyself, though, so what do I know. :)\n\n> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> index f2e5a07d64..326a45f648 100644\n> --- a/Documentation/git-branch.txt\n> +++ b/Documentation/git-branch.txt\n> @@ -168,8 +168,10 @@ This option is only applicable in non-verbose mode.\n>  \tWhen in list mode,\n>  \tshow sha1 and commit subject line for each head, along with\n>  \trelationship to upstream branch (if any). If given twice, print\n> -\tthe name of the upstream branch, as well (see also `git remote\n> -\tshow <remote>`).\n> +\tthe path of the linked worktree, if applicable (not applicable\n> +\tfor current worktree since user's path will already be in current\n> +\tworktree) and the name of the upstream branch, as well (see also\n> +\t`git remote show <remote>`).\n\nThat parenthetical feels a bit awkward. Maybe:\n\n  ...print the path of the linked worktree (if any) and the name of the\n  upstream branch, as well (see also `git remote show <remote>`). Note\n  that the current worktree's HEAD will not have its path printed (it\n  will always be your current directory).\n\n> diff --git a/builtin/branch.c b/builtin/branch.c\n> index c2a86362bb..0b8ba9e4c5 100644\n> --- a/builtin/branch.c\n> +++ b/builtin/branch.c\n> @@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n>  \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n>  \n>  \t\tif (filter->verbose > 1)\n> +\t\t{\n> +\t\t\tstrbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n> +\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n>  \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n>  \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n>  \t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n> +\t\t}\n\nAnother unreadable long line (both the one you're adding, and the existing\none!). I don't know if it's worth trying to clean these up, but if we\ndo, it might be worth hitting the existing ones, too.\n\nI'm OK if that comes as a patch on top later on, though.\n\n> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\n> index 94ab05ad59..012ddde7f2 100755\n> --- a/t/t3203-branch-output.sh\n> +++ b/t/t3203-branch-output.sh\n> @@ -241,7 +241,6 @@ test_expect_success 'git branch --format option' '\n>  '\n>  \n>  test_expect_success '\"add\" a worktree' '\n> -\tmkdir worktree_dir &&\n>  \tgit worktree add -b master_worktree worktree_dir master\n>  '\n\nHere's that mysterious mkdir going away. :)\n\n> @@ -285,4 +284,24 @@ test_expect_success '--color overrides auto-color' '\n>  \ttest_cmp expect.color actual\n>  '\n>  \n> +# This test case has some special code to strip the first 30 characters or so\n> +# of the output so that we do not have to put commit hashes into the expect\n> +test_expect_success 'verbose output lists worktree path' '\n> +\tcat >expect <<-EOF &&\n> +\tone\n> +\tone\n> +\ttwo\n> +\tone\n> +\ttwo\n> +\t($(pwd)/worktree_dir) two\n> +\ttwo\n> +\ttwo\n> +\tEOF\n> +\tgit branch -vv >tmp &&\n> +\tSUBSTRLENGTH=$(head -1 tmp | awk \"{print index(\\$0, \\\"one\\\")}\") &&\n> +\tawk -v substrlength=\"$SUBSTRLENGTH\" \"{print substr(\\$0,substrlength,length(\\$0))}\" <tmp >actual &&\n> +\ttest_cmp expect actual\n> +'\n\nIt's hard to tell if this awk is doing the right thing. I guess it works\nbecause git-branch tries to line up all of the hashes. I think the\nresult might be easier to verify if we simply blanked the hashes.\nUnfortunately the output is actually pretty hard to parse. Since there\nare only two tip commits, perhaps it would not be so bad to just do\nsomething like this:\n\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex 012ddde7f2..8065279be6 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -284,22 +284,20 @@ test_expect_success '--color overrides auto-color' '\n \ttest_cmp expect.color actual\n '\n \n-# This test case has some special code to strip the first 30 characters or so\n-# of the output so that we do not have to put commit hashes into the expect\n test_expect_success 'verbose output lists worktree path' '\n+\tone=$(git rev-parse --short HEAD) &&\n+\ttwo=$(git rev-parse --short master) &&\n \tcat >expect <<-EOF &&\n-\tone\n-\tone\n-\ttwo\n-\tone\n-\ttwo\n-\t($(pwd)/worktree_dir) two\n-\ttwo\n-\ttwo\n+\t* (HEAD detached from fromtag) $one one\n+\t  ambiguous                    $one one\n+\t  branch-one                   $two two\n+\t  branch-two                   $one one\n+\t  master                       $two two\n+\t+ master_worktree              $two ($(pwd)/worktree_dir) two\n+\t  ref-to-branch                $two two\n+\t  ref-to-remote                $two two\n \tEOF\n-\tgit branch -vv >tmp &&\n-\tSUBSTRLENGTH=$(head -1 tmp | awk \"{print index(\\$0, \\\"one\\\")}\") &&\n-\tawk -v substrlength=\"$SUBSTRLENGTH\" \"{print substr(\\$0,substrlength,length(\\$0))}\" <tmp >actual &&\n+\tgit branch -vv >actual &&\n \ttest_cmp expect actual\n '\n \n\nI don't like how it depends on the space alignment of the branches, but\nI do like that you can clearly see which branch is being annotated.\n\n-Peff\n"},{"id":"371461","messageId":"CAC05385ECz0=zfBHungpFHqPT5Wr0PviduEBraUWbBVrwHMzaA@mail.gmail.com","threadId":"49438","inReplyTo":"20190221124408.GA13403@sigill.intra.peff.net","subject":"Re: [PATCH v8 2/3] branch: update output to include worktree info","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-03-14T05:45:33Z","receivedAt":"2019-03-14T05:46:02Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Thu, Feb 21, 2019 at 4:44 AM Jeff King <peff@peff.net> wrote:\n>\n> On Tue, Feb 19, 2019 at 05:31:22PM +0900, nbelakovski@gmail.com wrote:\n>\n> > From: Nickolai Belakovski <nbelakovski@gmail.com>\n> >\n> > The output of git branch is modified to mark branches checkout out in a\n>\n> s/checkout out/checked out/ ?\n>\nYes, thanks\n>\n> > -     strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n> > -                 branch_get_color(BRANCH_COLOR_CURRENT),\n> > -                 branch_get_color(BRANCH_COLOR_LOCAL));\n> > +     strbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n> > +                     branch_get_color(BRANCH_COLOR_CURRENT),\n> > +                     branch_get_color(BRANCH_COLOR_WORKTREE),\n> > +                     branch_get_color(BRANCH_COLOR_LOCAL));\n>\n> Makes sense. The long line is ugly. Our format does not support breaking\n> long lines, though we could break the C string, I think, like:\n>\n>   strbuf_add(&local,\n>              \"%%(if)%%(HEAD)\"\n>                \"%%(then)* %s\"\n>              \"%%(else)%(if)%%(worktreepath)\"\n>                \"%%(then)+ %s\"\n>              \"%%(else)\"\n>                \"%%(then)  %s\"\n>              \"%%(end)%%(end)\");\n>\n> That's pretty ugly, too, but it at least shows the conditional\n> structure.\nTrue, but other lines within that file are about as long. I'd feel\nthat I should make all of them reflect the conditional structure if\nI'm going to make one of them reflect it. Granted none of the others\nhave nested if's, but personally I think it's OK as is. The nested if\nis short enough.\n>\n> >\n> > +test_expect_success '\"add\" a worktree' '\n> > +     mkdir worktree_dir &&\n> > +     git worktree add -b master_worktree worktree_dir master\n> > +'\n>\n> This mkdir gets deleted in the next patch. It should just not be added\n> here.\nWhoops, removed\n>\n> > +cat >expect <<'EOF'\n> > +* <GREEN>(HEAD detached from fromtag)<RESET>\n> > +  ambiguous<RESET>\n> > +  branch-one<RESET>\n> > +  branch-two<RESET>\n> > +  master<RESET>\n> > ++ <CYAN>master_worktree<RESET>\n> > +  ref-to-branch<RESET> -> branch-one\n> > +  ref-to-remote<RESET> -> origin/branch-one\n> > +EOF\n> > +test_expect_success TTY 'worktree colors correct' '\n> > +     test_terminal git branch >actual.raw &&\n> > +     test_decode_color <actual.raw >actual &&\n> > +     test_cmp expect actual\n> > +'\n>\n> We are not testing the auto-color behavior here, so I think you could\n> just use \"git branch --color >actual.raw\" and drop the TTY prerequisite.\n> That's shorter and simpler, and will let your test run on more\n> platforms.\n>\nDone locally, will be part of v9\n\n> -Peff\n"},{"id":"371463","messageId":"CAC05385Q0EQWX8B5PfR2m6N7o573NTF+a0HyXS+zqYAAdgTVOw@mail.gmail.com","threadId":"49438","inReplyTo":"20190221125952.GB13403@sigill.intra.peff.net","subject":"Re: [PATCH v8 3/3] branch: add worktree info on verbose output","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-03-14T05:58:06Z","receivedAt":"2019-03-14T05:58:36Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"On Thu, Feb 21, 2019 at 4:59 AM Jeff King <peff@peff.net> wrote:\n>\n> On Tue, Feb 19, 2019 at 05:31:23PM +0900, nbelakovski@gmail.com wrote:\n>\n> > From: Nickolai Belakovski <nbelakovski@gmail.com>\n> >\n> > To display worktree path for refs checked out in a linked worktree\n>\n> This would be a good place to describe why this is useful. :)\n>\n> I do not have an opinion myself. Patch 2 makes a lot of sense to me, but\n> I don't know if people would like this one or not. I don't use \"-v\"\n> myself, though, so what do I know. :)\nI threw this one in because I thought it wouldn't be clear to the\naverage user why some\nbranches are in cyan. By putting the worktree path in cyan on the next\nlevel of output\nI thought this would help the user make the connection, but actually I\ndon't have strong\nfeelings about this one.\n>\n> > diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\n> > index f2e5a07d64..326a45f648 100644\n> > --- a/Documentation/git-branch.txt\n> > +++ b/Documentation/git-branch.txt\n> > @@ -168,8 +168,10 @@ This option is only applicable in non-verbose mode.\n> >       When in list mode,\n> >       show sha1 and commit subject line for each head, along with\n> >       relationship to upstream branch (if any). If given twice, print\n> > -     the name of the upstream branch, as well (see also `git remote\n> > -     show <remote>`).\n> > +     the path of the linked worktree, if applicable (not applicable\n> > +     for current worktree since user's path will already be in current\n> > +     worktree) and the name of the upstream branch, as well (see also\n> > +     `git remote show <remote>`).\n>\n> That parenthetical feels a bit awkward. Maybe:\n>\n>   ...print the path of the linked worktree (if any) and the name of the\n>   upstream branch, as well (see also `git remote show <remote>`). Note\n>   that the current worktree's HEAD will not have its path printed (it\n>   will always be your current directory).\nSure I can make that change\n>\n> > diff --git a/builtin/branch.c b/builtin/branch.c\n> > index c2a86362bb..0b8ba9e4c5 100644\n> > --- a/builtin/branch.c\n> > +++ b/builtin/branch.c\n> > @@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n> >               strbuf_addf(&local, \" %s \", obname.buf);\n> >\n> >               if (filter->verbose > 1)\n> > +             {\n> > +                     strbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n> > +                                 branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n> >                       strbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n> >                                   \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n> >                                   branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n> > +             }\n>\n> Another unreadable long line (both the one you're adding, and the existing\n> one!). I don't know if it's worth trying to clean these up, but if we\n> do, it might be worth hitting the existing ones, too.\n>\n> I'm OK if that comes as a patch on top later on, though.\nAgreed, but there's enough lines like this that it'll just look\ninconsistent if only one were broken up.\n>\n>\n> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\n> index 012ddde7f2..8065279be6 100755\n> --- a/t/t3203-branch-output.sh\n> +++ b/t/t3203-branch-output.sh\n> @@ -284,22 +284,20 @@ test_expect_success '--color overrides auto-color' '\n>         test_cmp expect.color actual\n>  '\n>\n> -# This test case has some special code to strip the first 30 characters or so\n> -# of the output so that we do not have to put commit hashes into the expect\n>  test_expect_success 'verbose output lists worktree path' '\n> +       one=$(git rev-parse --short HEAD) &&\n> +       two=$(git rev-parse --short master) &&\n>         cat >expect <<-EOF &&\n> -       one\n> -       one\n> -       two\n> -       one\n> -       two\n> -       ($(pwd)/worktree_dir) two\n> -       two\n> -       two\n> +       * (HEAD detached from fromtag) $one one\n> +         ambiguous                    $one one\n> +         branch-one                   $two two\n> +         branch-two                   $one one\n> +         master                       $two two\n> +       + master_worktree              $two ($(pwd)/worktree_dir) two\n> +         ref-to-branch                $two two\n> +         ref-to-remote                $two two\n>         EOF\n> -       git branch -vv >tmp &&\n> -       SUBSTRLENGTH=$(head -1 tmp | awk \"{print index(\\$0, \\\"one\\\")}\") &&\n> -       awk -v substrlength=\"$SUBSTRLENGTH\" \"{print substr(\\$0,substrlength,length(\\$0))}\" <tmp >actual &&\n> +       git branch -vv >actual &&\n>         test_cmp expect actual\n>  '\n>\n>\n> I don't like how it depends on the space alignment of the branches, but\n> I do like that you can clearly see which branch is being annotated.\nThanks for the suggestion. While I'm kinda proud of my awk thing, I\nthink yours is a lot easier to read. Will add.\n>\n> -Peff\n"},{"id":"371466","messageId":"CAC05385woS0XUsDHRBHrZkjzFU9q9+JOJ3BvE8pRh48794-iBA@mail.gmail.com","threadId":"49438","inReplyTo":"20190221123646.GA12185@sigill.intra.peff.net","subject":"Re: [PATCH v8 0/3]","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-03-14T06:10:06Z","receivedAt":"2019-03-14T06:10:36Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":">\n> Patch 1 looks good to me. Given that we're on v8 and most of the other\n> comments are for patches 2 and 3, I think we might consider graduating\n> it separately if the other two are not ready soon. It's independently\n> useful, IMHO.\n\nPatch 2 was my main motivation, so it would be nice to get it in\ntogether with 1 :)\nPatch 3, like I said in the thread on that one I don't have strong\nfeeling about it. It was an attempt to provide a connection between\nthe new cyan output and its intent, as opposed to having the user\nguess, but I think anyone who's using a worktree will figure it out\nsooner or later, and anyone not using a worktree will be unaffected.\n\nI'm willing to keep going with comments on patch 2. I can't imagine it\nwould take many more revisions as it's much more straightforward than\npatch 1, it's basically just modifying one line of branch.c. If we\ndecide to drop patch 3 fine with me.\n\nI'll send in v9 with the latest changes for both 2 and 3 sometime\ntomorrow unless I hear otherwise.\n\nThanks for the feedback.\n"},{"id":"371637","messageId":"20190316013807.38756-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"[PATCH v9 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-03-16T01:38:04Z","receivedAt":"2019-03-16T01:38:27Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nCleanup on 2/3 and 3/3\n\nTo reiterate from elsewhere in the thread, I'd really like to get 1/3 and 2/3 in together.\nFor 3/3 I'm basically indifferent. I see some value in it, but I also think it clutters up\nthe verbose output, so I could understand if there's a lack of interest in it.\n\nAlso, I changed my strategy for how I updated tests that were impacted by these changes.\nInstead of updating the impacted tests with the new expected output, I went back and made various\ntests more self-contained. This seemed like a more sensible strategy from the standpoint\nof decoupling tests and limiting scope of tests.\n\nTravis-CI results: https://travis-ci.org/nbelakovski/git/builds/506853143\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: update output to include worktree info\n  branch: add worktree info on verbose output\n\n Documentation/git-branch.txt       | 12 ++++--\n Documentation/git-for-each-ref.txt |  5 +++\n builtin/branch.c                   | 16 ++++++--\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  | 16 +++++---\n t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-\n t/t6302-for-each-ref-filter.sh     | 13 +++++++\n 7 files changed, 168 insertions(+), 15 deletions(-)\n\n-- \n2.14.2\n\n"},{"id":"371638","messageId":"20190316013807.38756-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190316013807.38756-1-nbelakovski@gmail.com","subject":"[PATCH v9 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-03-16T01:38:05Z","receivedAt":"2019-03-16T01:38:27Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom providing the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  5 +++\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 13 +++++++\n 3 files changed, 96 insertions(+)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 774cecc7ed..6dcd39f6f6 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -214,6 +214,11 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. Empty string\n+\totherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 3aca105307..79cfec914a 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -75,6 +77,27 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct ref_to_worktree_entry {\n+\tstruct hashmap_entry ent; /* must be the first member! */\n+\tstruct worktree *wt; /* key is wt->head_ref */\n+};\n+\n+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,\n+\t\t\t\t      const void *existing_hashmap_entry_to_test,\n+\t\t\t\t      const void *key,\n+\t\t\t\t      const void *keydata_aka_refname)\n+{\n+\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n+\tconst struct ref_to_worktree_entry *k = key;\n+\treturn strcmp(e->wt->head_ref,\n+\t\tkeydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n+}\n+\n+static struct ref_to_worktree_map {\n+\tstruct hashmap map;\n+\tstruct worktree **worktrees;\n+} ref_to_worktree_map;\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -480,6 +503,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1529,6 +1553,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)\n+{\n+\tint i;\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct ref_to_worktree_entry *entry;\n+\t\t\tentry = xmalloc(sizeof(*entry));\n+\t\t\tentry->wt = worktrees[i];\n+\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\n+\t\t\thashmap_add(map, entry);\n+\t\t}\n+\t}\n+}\n+\n+static void lazy_init_worktree_map(void)\n+{\n+\tif (ref_to_worktree_map.worktrees)\n+\t\treturn;\n+\n+\tref_to_worktree_map.worktrees = get_worktrees(0);\n+\thashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);\n+\tpopulate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);\n+}\n+\n+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct hashmap_entry entry;\n+\tstruct ref_to_worktree_entry *lookup_result;\n+\n+\tlazy_init_worktree_map();\n+\n+\thashmap_entry_init(&entry, strhash(ref->refname));\n+\tlookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);\n+\n+\tif (lookup_result)\n+\t\treturn xstrdup(lookup_result->wt->path);\n+\telse\n+\t\treturn xstrdup(\"\");\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1566,6 +1632,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (!strcmp(name, \"worktreepath\")) {\n+\t\t\tif (ref->kind == FILTER_REFS_BRANCHES)\n+\t\t\t\tv->s = get_worktree_path(atom, ref);\n+\t\t\telse\n+\t\t\t\tv->s = xstrdup(\"\");\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2049,6 +2122,11 @@ void ref_array_clear(struct ref_array *array)\n \t\tfree_array_item(array->items[i]);\n \tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n+\tif (ref_to_worktree_map.worktrees) {\n+\t\thashmap_free(&(ref_to_worktree_map.map), 1);\n+\t\tfree_worktrees(ref_to_worktree_map.worktrees);\n+\t\tref_to_worktree_map.worktrees = NULL;\n+\t}\n }\n \n static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..35408d53fd 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,17 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-EOF &&\n+\tmaster: $(pwd)\n+\tmaster_worktree: $(pwd)/worktree_dir\n+\tside: not checked out\n+\tEOF\n+\tgit worktree add -b master_worktree worktree_dir master &&\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"371639","messageId":"20190316013807.38756-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190316013807.38756-1-nbelakovski@gmail.com","subject":"[PATCH v9 2/3] branch: update output to include worktree info","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-03-16T01:38:06Z","receivedAt":"2019-03-16T01:38:31Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nThe output of git branch is modified to mark branches checked out in a\nlinked worktree with a \"+\" and color them in cyan (in contrast to the\ncurrent branch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to communicate to the user that the branches that are\nmarked or colored will behave differently from other branches if the user\nattempts to check them out or delete them, since branches checked out in\nanother worktree cannot be checked out or deleted.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt |  6 ++++--\n builtin/branch.c             | 12 ++++++++----\n t/t3200-branch.sh            | 16 +++++++++++-----\n t/t3203-branch-output.sh     | 24 ++++++++++++++++++++++--\n 4 files changed, 45 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 0cd87ddeff..7d18dffc4b 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -26,8 +26,10 @@ DESCRIPTION\n -----------\n \n If `--list` is given, or if there are no non-option arguments, existing\n-branches are listed; the current branch will be highlighted with an\n-asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n+branches are listed; the current branch will be highlighted in green and\n+marked with an asterisk.  Any branches checked out in linked worktrees will\n+be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n+remote-tracking branches to be listed,\n and option `-a` shows both local and remote branches. If a `<pattern>`\n is given, it is used as a shell wildcard to restrict the output to\n matching branches. If multiple patterns are given, a branch is shown if\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 4c83055730..350b039063 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..88719cc02c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -202,18 +202,22 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n \tgit worktree add -f bazdir2 baz &&\n \tgit branch -M baz bam &&\n \ttest $(git -C bazdir rev-parse --abbrev-ref HEAD) = bam &&\n-\ttest $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam\n+\ttest $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&\n+\trm -r bazdir bazdir2 &&\n+\tgit worktree prune\n '\n \n test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n \tgit checkout -b baz &&\n-\tgit worktree add -f bazdir3 baz &&\n+\tgit worktree add -f bazdir baz &&\n \t(\n-\t\tcd bazdir3 &&\n+\t\tcd bazdir &&\n \t\tgit branch -M baz bam &&\n \t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n \t) &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n+\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n+\trm -r bazdir &&\n+\tgit worktree prune\n '\n \n test_expect_success 'git branch -M master should work when master is checked out' '\n@@ -774,7 +778,9 @@ test_expect_success 'test deleting branch without config' '\n test_expect_success 'deleting currently checked out branch fails' '\n \tgit worktree add -b my7 my7 &&\n \ttest_must_fail git -C my7 branch -d my7 &&\n-\ttest_must_fail git branch -d my7\n+\ttest_must_fail git branch -d my7 &&\n+\trm -r my7 &&\n+\tgit worktree prune\n '\n \n test_expect_success 'test --track without .fetch entries' '\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex be55148930..ceb74e0826 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -136,11 +136,13 @@ test_expect_success 'git branch `--show-current` works properly with worktrees'\n \tbranch-two\n \tEOF\n \tgit checkout branch-one &&\n-\tgit worktree add worktree branch-two &&\n+\tgit worktree add worktree_dir branch-two &&\n \t{\n \t\tgit branch --show-current &&\n-\t\tgit -C worktree branch --show-current\n+\t\tgit -C worktree_dir branch --show-current\n \t} >actual &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n \ttest_cmp expect actual\n '\n \n@@ -284,6 +286,24 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success 'worktree colors correct' '\n+\tcat >expect <<-EOF &&\n+\t* <GREEN>(HEAD detached from fromtag)<RESET>\n+\t  ambiguous<RESET>\n+\t  branch-one<RESET>\n+\t+ <CYAN>branch-two<RESET>\n+\t  master<RESET>\n+\t  ref-to-branch<RESET> -> branch-one\n+\t  ref-to-remote<RESET> -> origin/branch-one\n+\tEOF\n+\tgit worktree add worktree_dir branch-two &&\n+\tgit branch --color >actual.raw &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_cmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"371640","messageId":"20190316013807.38756-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190316013807.38756-1-nbelakovski@gmail.com","subject":"[PATCH v9 3/3] branch: add worktree info on verbose output","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-03-16T01:38:07Z","receivedAt":"2019-03-16T01:38:34Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nTo display worktree path for refs checked out in a linked worktree\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt |  6 ++++--\n builtin/branch.c             |  4 ++++\n t/t3203-branch-output.sh     | 19 +++++++++++++++++++\n 3 files changed, 27 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 7d18dffc4b..d11d00583a 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -172,8 +172,10 @@ This option is only applicable in non-verbose mode.\n \tWhen in list mode,\n \tshow sha1 and commit subject line for each head, along with\n \trelationship to upstream branch (if any). If given twice, print\n-\tthe name of the upstream branch, as well (see also `git remote\n-\tshow <remote>`).\n+\tthe path of the linked worktree (if any) and the name of the upstream\n+\tbranch, as well (see also `git remote show <remote>`).  Note that the\n+\tcurrent worktree's HEAD will not have its path printed (it will always\n+\tbe your current directory).\n \n -q::\n --quiet::\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex 350b039063..3d1872babc 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n \t\tif (filter->verbose > 1)\n+\t\t{\n+\t\t\tstrbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n \t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n+\t\t}\n \t\telse\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)\");\n \ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex ceb74e0826..e5dc23e225 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -328,4 +328,23 @@ test_expect_success '--color overrides auto-color' '\n \ttest_cmp expect.color actual\n '\n \n+test_expect_success 'verbose output lists worktree path' '\n+\tone=$(git rev-parse --short HEAD) &&\n+\ttwo=$(git rev-parse --short master) &&\n+\tcat >expect <<-EOF &&\n+\t* (HEAD detached from fromtag) $one one\n+\t  ambiguous                    $one one\n+\t  branch-one                   $two two\n+\t+ branch-two                   $one ($(pwd)/worktree_dir) one\n+\t  master                       $two two\n+\t  ref-to-branch                $two two\n+\t  ref-to-remote                $two two\n+\tEOF\n+\tgit worktree add worktree_dir branch-two &&\n+\tgit branch -vv >actual &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"371762","messageId":"xmqqmult6idd.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"CAC05385Q0EQWX8B5PfR2m6N7o573NTF+a0HyXS+zqYAAdgTVOw@mail.gmail.com","subject":"Re: [PATCH v8 3/3] branch: add worktree info on verbose output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-03-18T02:12:14Z","receivedAt":"2019-03-18T02:12:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nickolai Belakovski <nbelakovski@gmail.com> writes:\n\n> On Thu, Feb 21, 2019 at 4:59 AM Jeff King <peff@peff.net> wrote:\n>>\n>> On Tue, Feb 19, 2019 at 05:31:23PM +0900, nbelakovski@gmail.com wrote:\n>>\n>> > From: Nickolai Belakovski <nbelakovski@gmail.com>\n>> >\n>> > To display worktree path for refs checked out in a linked worktree\n>>\n>> This would be a good place to describe why this is useful. :)\n>>\n>> I do not have an opinion myself. Patch 2 makes a lot of sense to me, but\n>> I don't know if people would like this one or not. I don't use \"-v\"\n>> myself, though, so what do I know. :)\n> I threw this one in because I thought it wouldn't be clear to the\n> average user why some\n> branches are in cyan. By putting the worktree path in cyan on the next\n> level of output\n> I thought this would help the user make the connection, but actually I\n> don't have strong\n> feelings about this one.\n\nI am moderately skeptical on 2/3, but together with 3/3 I think it\nmakes sense.\n\nThe fact that two branch names painted in different colors from the\nother ones, without knowing which one is checked out in what\nworktree, will not give enough information to allow the user to\nactually start working on one of them.  All the user gets with 2/3\nalone is \"don't touch it---it is used elsewhere and I am not telling\nwhere\", isn't it?\n\n\n"},{"id":"371774","messageId":"xmqqo9684ulo.fsf@gitster-ct.c.googlers.com","threadId":"49438","inReplyTo":"20190316013807.38756-1-nbelakovski@gmail.com","subject":"Re: [PATCH v9 0/3]","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-03-18T05:30:59Z","receivedAt":"2019-03-18T05:31:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"nbelakovski@gmail.com writes:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n>\n> Cleanup on 2/3 and 3/3\n\nI'll have to re-read the test part myself to see what you meant by\nthe \"strategy for updating tests\" and if it makes sense, but what\nyou wrote as the goal and approach in the cover letter all sounded\nsensible.\n\nThanks, will requeue.  \n"},{"id":"371806","messageId":"20190318121054.GC24175@szeder.dev","threadId":"49438","inReplyTo":"20190316013807.38756-4-nbelakovski@gmail.com","subject":"Re: [PATCH v9 3/3] branch: add worktree info on verbose output","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-03-18T12:10:54Z","receivedAt":"2019-03-18T12:10:59Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Fri, Mar 15, 2019 at 06:38:07PM -0700, nbelakovski@gmail.com wrote:\n> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\n> index ceb74e0826..e5dc23e225 100755\n> --- a/t/t3203-branch-output.sh\n> +++ b/t/t3203-branch-output.sh\n> @@ -328,4 +328,23 @@ test_expect_success '--color overrides auto-color' '\n>  \ttest_cmp expect.color actual\n>  '\n>  \n> +test_expect_success 'verbose output lists worktree path' '\n> +\tone=$(git rev-parse --short HEAD) &&\n> +\ttwo=$(git rev-parse --short master) &&\n> +\tcat >expect <<-EOF &&\n> +\t* (HEAD detached from fromtag) $one one\n\nThis 'HEAD detached from ...\" message is translated ...\n\n> +\t  ambiguous                    $one one\n> +\t  branch-one                   $two two\n> +\t+ branch-two                   $one ($(pwd)/worktree_dir) one\n> +\t  master                       $two two\n> +\t  ref-to-branch                $two two\n> +\t  ref-to-remote                $two two\n> +\tEOF\n> +\tgit worktree add worktree_dir branch-two &&\n> +\tgit branch -vv >actual &&\n> +\trm -r worktree_dir &&\n> +\tgit worktree prune &&\n> +\ttest_cmp expect actual\n\n... therefore here you should use 'test_i18ncmp', as otherwise the\nGETTEXT_POISON test run fails.\n\n> +'\n> +\n>  test_done\n> -- \n> 2.14.2\n> \n"},{"id":"374616","messageId":"20190429051944.77164-1-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com","subject":"[PATCH v10 0/3]","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-04-29T05:19:41Z","receivedAt":"2019-04-29T05:20:04Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdded test_i18ncmp per instructions from Szeder\n\nIs there some other part of the infrastructure that's testing for this? Because it did not fail in any of my Travis CI builds.\n\nTravis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210\n\nNickolai Belakovski (3):\n  ref-filter: add worktreepath atom\n  branch: update output to include worktree info\n  branch: add worktree info on verbose output\n\n Documentation/git-branch.txt       | 12 ++++--\n Documentation/git-for-each-ref.txt |  5 +++\n builtin/branch.c                   | 16 ++++++--\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t3200-branch.sh                  | 16 +++++---\n t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-\n t/t6302-for-each-ref-filter.sh     | 13 +++++++\n 7 files changed, 168 insertions(+), 15 deletions(-)\n\n-- \n2.14.2\n\n"},{"id":"374617","messageId":"20190429051944.77164-2-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190429051944.77164-1-nbelakovski@gmail.com","subject":"[PATCH v10 1/3] ref-filter: add worktreepath atom","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-04-29T05:19:42Z","receivedAt":"2019-04-29T05:20:05Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nAdd an atom providing the path of the linked worktree where this ref is\nchecked out, if it is checked out in any linked worktrees, and empty\nstring otherwise.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-for-each-ref.txt |  5 +++\n ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n t/t6302-for-each-ref-filter.sh     | 13 +++++++\n 3 files changed, 96 insertions(+)\n\ndiff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt\nindex 774cecc7ed..6dcd39f6f6 100644\n--- a/Documentation/git-for-each-ref.txt\n+++ b/Documentation/git-for-each-ref.txt\n@@ -214,6 +214,11 @@ symref::\n \t`:lstrip` and `:rstrip` options in the same way as `refname`\n \tabove.\n \n+worktreepath::\n+\tThe absolute path to the worktree in which the ref is checked\n+\tout, if it is checked out in any linked worktree. Empty string\n+\totherwise.\n+\n In addition to the above, for commit and tag objects, the header\n field names (`tree`, `parent`, `object`, `type`, and `tag`) can\n be used to specify the value in the header field.\ndiff --git a/ref-filter.c b/ref-filter.c\nindex 8d11a94cbd..13984fa8ca 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -20,6 +20,8 @@\n #include \"commit-slab.h\"\n #include \"commit-graph.h\"\n #include \"commit-reach.h\"\n+#include \"worktree.h\"\n+#include \"hashmap.h\"\n \n static struct ref_msg {\n \tconst char *gone;\n@@ -75,6 +77,27 @@ static struct expand_data {\n \tstruct object_info info;\n } oi, oi_deref;\n \n+struct ref_to_worktree_entry {\n+\tstruct hashmap_entry ent; /* must be the first member! */\n+\tstruct worktree *wt; /* key is wt->head_ref */\n+};\n+\n+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,\n+\t\t\t\t      const void *existing_hashmap_entry_to_test,\n+\t\t\t\t      const void *key,\n+\t\t\t\t      const void *keydata_aka_refname)\n+{\n+\tconst struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;\n+\tconst struct ref_to_worktree_entry *k = key;\n+\treturn strcmp(e->wt->head_ref,\n+\t\tkeydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);\n+}\n+\n+static struct ref_to_worktree_map {\n+\tstruct hashmap map;\n+\tstruct worktree **worktrees;\n+} ref_to_worktree_map;\n+\n /*\n  * An atom is a valid field atom listed below, possibly prefixed with\n  * a \"*\" to denote deref_tag().\n@@ -480,6 +503,7 @@ static struct {\n \t{ \"flag\", SOURCE_NONE },\n \t{ \"HEAD\", SOURCE_NONE, FIELD_STR, head_atom_parser },\n \t{ \"color\", SOURCE_NONE, FIELD_STR, color_atom_parser },\n+\t{ \"worktreepath\", SOURCE_NONE },\n \t{ \"align\", SOURCE_NONE, FIELD_STR, align_atom_parser },\n \t{ \"end\", SOURCE_NONE },\n \t{ \"if\", SOURCE_NONE, FIELD_STR, if_atom_parser },\n@@ -1529,6 +1553,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \treturn 0;\n }\n \n+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)\n+{\n+\tint i;\n+\n+\tfor (i = 0; worktrees[i]; i++) {\n+\t\tif (worktrees[i]->head_ref) {\n+\t\t\tstruct ref_to_worktree_entry *entry;\n+\t\t\tentry = xmalloc(sizeof(*entry));\n+\t\t\tentry->wt = worktrees[i];\n+\t\t\thashmap_entry_init(entry, strhash(worktrees[i]->head_ref));\n+\n+\t\t\thashmap_add(map, entry);\n+\t\t}\n+\t}\n+}\n+\n+static void lazy_init_worktree_map(void)\n+{\n+\tif (ref_to_worktree_map.worktrees)\n+\t\treturn;\n+\n+\tref_to_worktree_map.worktrees = get_worktrees(0);\n+\thashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);\n+\tpopulate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);\n+}\n+\n+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)\n+{\n+\tstruct hashmap_entry entry;\n+\tstruct ref_to_worktree_entry *lookup_result;\n+\n+\tlazy_init_worktree_map();\n+\n+\thashmap_entry_init(&entry, strhash(ref->refname));\n+\tlookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);\n+\n+\tif (lookup_result)\n+\t\treturn xstrdup(lookup_result->wt->path);\n+\telse\n+\t\treturn xstrdup(\"\");\n+}\n+\n /*\n  * Parse the object referred by ref, and grab needed value.\n  */\n@@ -1566,6 +1632,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)\n \n \t\tif (starts_with(name, \"refname\"))\n \t\t\trefname = get_refname(atom, ref);\n+\t\telse if (!strcmp(name, \"worktreepath\")) {\n+\t\t\tif (ref->kind == FILTER_REFS_BRANCHES)\n+\t\t\t\tv->s = get_worktree_path(atom, ref);\n+\t\t\telse\n+\t\t\t\tv->s = xstrdup(\"\");\n+\t\t\tcontinue;\n+\t\t}\n \t\telse if (starts_with(name, \"symref\"))\n \t\t\trefname = get_symref(atom, ref);\n \t\telse if (starts_with(name, \"upstream\")) {\n@@ -2049,6 +2122,11 @@ void ref_array_clear(struct ref_array *array)\n \t\tfree_array_item(array->items[i]);\n \tFREE_AND_NULL(array->items);\n \tarray->nr = array->alloc = 0;\n+\tif (ref_to_worktree_map.worktrees) {\n+\t\thashmap_free(&(ref_to_worktree_map.map), 1);\n+\t\tfree_worktrees(ref_to_worktree_map.worktrees);\n+\t\tref_to_worktree_map.worktrees = NULL;\n+\t}\n }\n \n static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)\ndiff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh\nindex fc067ed672..35408d53fd 100755\n--- a/t/t6302-for-each-ref-filter.sh\n+++ b/t/t6302-for-each-ref-filter.sh\n@@ -441,4 +441,17 @@ test_expect_success '--merged is incompatible with --no-merged' '\n \ttest_must_fail git for-each-ref --merged HEAD --no-merged HEAD\n '\n \n+test_expect_success 'validate worktree atom' '\n+\tcat >expect <<-EOF &&\n+\tmaster: $(pwd)\n+\tmaster_worktree: $(pwd)/worktree_dir\n+\tside: not checked out\n+\tEOF\n+\tgit worktree add -b master_worktree worktree_dir master &&\n+\tgit for-each-ref --format=\"%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)\" refs/heads/ >actual &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n+\ttest_cmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"374618","messageId":"20190429051944.77164-3-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190429051944.77164-1-nbelakovski@gmail.com","subject":"[PATCH v10 2/3] branch: update output to include worktree info","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-04-29T05:19:43Z","receivedAt":"2019-04-29T05:20:07Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nThe output of git branch is modified to mark branches checked out in a\nlinked worktree with a \"+\" and color them in cyan (in contrast to the\ncurrent branch, which will still be denoted with a \"*\" and colored in green)\n\nThis is meant to communicate to the user that the branches that are\nmarked or colored will behave differently from other branches if the user\nattempts to check them out or delete them, since branches checked out in\nanother worktree cannot be checked out or deleted.\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt |  6 ++++--\n builtin/branch.c             | 12 ++++++++----\n t/t3200-branch.sh            | 16 +++++++++++-----\n t/t3203-branch-output.sh     | 24 ++++++++++++++++++++++--\n 4 files changed, 45 insertions(+), 13 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 0cd87ddeff..7d18dffc4b 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -26,8 +26,10 @@ DESCRIPTION\n -----------\n \n If `--list` is given, or if there are no non-option arguments, existing\n-branches are listed; the current branch will be highlighted with an\n-asterisk.  Option `-r` causes the remote-tracking branches to be listed,\n+branches are listed; the current branch will be highlighted in green and\n+marked with an asterisk.  Any branches checked out in linked worktrees will\n+be highlighted in cyan and marked with a plus sign. Option `-r` causes the\n+remote-tracking branches to be listed,\n and option `-a` shows both local and remote branches. If a `<pattern>`\n is given, it is used as a shell wildcard to restrict the output to\n matching branches. If multiple patterns are given, a branch is shown if\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex d4359b33ac..a295380f45 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {\n \tGIT_COLOR_NORMAL,       /* LOCAL */\n \tGIT_COLOR_GREEN,        /* CURRENT */\n \tGIT_COLOR_BLUE,         /* UPSTREAM */\n+\tGIT_COLOR_CYAN,         /* WORKTREE */\n };\n enum color_branch {\n \tBRANCH_COLOR_RESET = 0,\n@@ -54,7 +55,8 @@ enum color_branch {\n \tBRANCH_COLOR_REMOTE = 2,\n \tBRANCH_COLOR_LOCAL = 3,\n \tBRANCH_COLOR_CURRENT = 4,\n-\tBRANCH_COLOR_UPSTREAM = 5\n+\tBRANCH_COLOR_UPSTREAM = 5,\n+\tBRANCH_COLOR_WORKTREE = 6\n };\n \n static const char *color_branch_slots[] = {\n@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {\n \t[BRANCH_COLOR_LOCAL]\t= \"local\",\n \t[BRANCH_COLOR_CURRENT]\t= \"current\",\n \t[BRANCH_COLOR_UPSTREAM] = \"upstream\",\n+\t[BRANCH_COLOR_WORKTREE] = \"worktree\",\n };\n \n static struct string_list output = STRING_LIST_INIT_DUP;\n@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \tstruct strbuf local = STRBUF_INIT;\n \tstruct strbuf remote = STRBUF_INIT;\n \n-\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)\",\n-\t\t    branch_get_color(BRANCH_COLOR_CURRENT),\n-\t\t    branch_get_color(BRANCH_COLOR_LOCAL));\n+\tstrbuf_addf(&local, \"%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)\",\n+\t\t\tbranch_get_color(BRANCH_COLOR_CURRENT),\n+\t\t\tbranch_get_color(BRANCH_COLOR_WORKTREE),\n+\t\t\tbranch_get_color(BRANCH_COLOR_LOCAL));\n \tstrbuf_addf(&remote, \"  %s\",\n \t\t    branch_get_color(BRANCH_COLOR_REMOTE));\n \ndiff --git a/t/t3200-branch.sh b/t/t3200-branch.sh\nindex 478b82cf9b..88719cc02c 100755\n--- a/t/t3200-branch.sh\n+++ b/t/t3200-branch.sh\n@@ -202,18 +202,22 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou\n \tgit worktree add -f bazdir2 baz &&\n \tgit branch -M baz bam &&\n \ttest $(git -C bazdir rev-parse --abbrev-ref HEAD) = bam &&\n-\ttest $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam\n+\ttest $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&\n+\trm -r bazdir bazdir2 &&\n+\tgit worktree prune\n '\n \n test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '\n \tgit checkout -b baz &&\n-\tgit worktree add -f bazdir3 baz &&\n+\tgit worktree add -f bazdir baz &&\n \t(\n-\t\tcd bazdir3 &&\n+\t\tcd bazdir &&\n \t\tgit branch -M baz bam &&\n \t\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n \t) &&\n-\ttest $(git rev-parse --abbrev-ref HEAD) = bam\n+\ttest $(git rev-parse --abbrev-ref HEAD) = bam &&\n+\trm -r bazdir &&\n+\tgit worktree prune\n '\n \n test_expect_success 'git branch -M master should work when master is checked out' '\n@@ -774,7 +778,9 @@ test_expect_success 'test deleting branch without config' '\n test_expect_success 'deleting currently checked out branch fails' '\n \tgit worktree add -b my7 my7 &&\n \ttest_must_fail git -C my7 branch -d my7 &&\n-\ttest_must_fail git branch -d my7\n+\ttest_must_fail git branch -d my7 &&\n+\trm -r my7 &&\n+\tgit worktree prune\n '\n \n test_expect_success 'test --track without .fetch entries' '\ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex be55148930..a3436bf25a 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -136,11 +136,13 @@ test_expect_success 'git branch `--show-current` works properly with worktrees'\n \tbranch-two\n \tEOF\n \tgit checkout branch-one &&\n-\tgit worktree add worktree branch-two &&\n+\tgit worktree add worktree_dir branch-two &&\n \t{\n \t\tgit branch --show-current &&\n-\t\tgit -C worktree branch --show-current\n+\t\tgit -C worktree_dir branch --show-current\n \t} >actual &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n \ttest_cmp expect actual\n '\n \n@@ -284,6 +286,24 @@ test_expect_success 'git branch --format option' '\n \ttest_i18ncmp expect actual\n '\n \n+test_expect_success 'worktree colors correct' '\n+\tcat >expect <<-EOF &&\n+\t* <GREEN>(HEAD detached from fromtag)<RESET>\n+\t  ambiguous<RESET>\n+\t  branch-one<RESET>\n+\t+ <CYAN>branch-two<RESET>\n+\t  master<RESET>\n+\t  ref-to-branch<RESET> -> branch-one\n+\t  ref-to-remote<RESET> -> origin/branch-one\n+\tEOF\n+\tgit worktree add worktree_dir branch-two &&\n+\tgit branch --color >actual.raw &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n+\ttest_decode_color <actual.raw >actual &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_expect_success \"set up color tests\" '\n \techo \"<RED>master<RESET>\" >expect.color &&\n \techo \"master\" >expect.bare &&\n-- \n2.14.2\n\n"},{"id":"374619","messageId":"20190429051944.77164-4-nbelakovski@gmail.com","threadId":"49438","inReplyTo":"20190429051944.77164-1-nbelakovski@gmail.com","subject":"[PATCH v10 3/3] branch: add worktree info on verbose output","fromName":"","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-04-29T05:19:44Z","receivedAt":"2019-04-29T05:20:08Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"From: Nickolai Belakovski <nbelakovski@gmail.com>\n\nTo display worktree path for refs checked out in a linked worktree\n\nSigned-off-by: Nickolai Belakovski <nbelakovski@gmail.com>\n---\n Documentation/git-branch.txt |  6 ++++--\n builtin/branch.c             |  4 ++++\n t/t3203-branch-output.sh     | 19 +++++++++++++++++++\n 3 files changed, 27 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt\nindex 7d18dffc4b..d11d00583a 100644\n--- a/Documentation/git-branch.txt\n+++ b/Documentation/git-branch.txt\n@@ -172,8 +172,10 @@ This option is only applicable in non-verbose mode.\n \tWhen in list mode,\n \tshow sha1 and commit subject line for each head, along with\n \trelationship to upstream branch (if any). If given twice, print\n-\tthe name of the upstream branch, as well (see also `git remote\n-\tshow <remote>`).\n+\tthe path of the linked worktree (if any) and the name of the upstream\n+\tbranch, as well (see also `git remote show <remote>`).  Note that the\n+\tcurrent worktree's HEAD will not have its path printed (it will always\n+\tbe your current directory).\n \n -q::\n --quiet::\ndiff --git a/builtin/branch.c b/builtin/branch.c\nindex a295380f45..2cb45e42e1 100644\n--- a/builtin/branch.c\n+++ b/builtin/branch.c\n@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r\n \t\tstrbuf_addf(&local, \" %s \", obname.buf);\n \n \t\tif (filter->verbose > 1)\n+\t\t{\n+\t\t\tstrbuf_addf(&local, \"%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)\",\n+\t\t\t\t    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)\"\n \t\t\t\t    \"%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)\",\n \t\t\t\t    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));\n+\t\t}\n \t\telse\n \t\t\tstrbuf_addf(&local, \"%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)\");\n \ndiff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh\nindex a3436bf25a..4bef8c7569 100755\n--- a/t/t3203-branch-output.sh\n+++ b/t/t3203-branch-output.sh\n@@ -328,4 +328,23 @@ test_expect_success '--color overrides auto-color' '\n \ttest_cmp expect.color actual\n '\n \n+test_expect_success 'verbose output lists worktree path' '\n+\tone=$(git rev-parse --short HEAD) &&\n+\ttwo=$(git rev-parse --short master) &&\n+\tcat >expect <<-EOF &&\n+\t* (HEAD detached from fromtag) $one one\n+\t  ambiguous                    $one one\n+\t  branch-one                   $two two\n+\t+ branch-two                   $one ($(pwd)/worktree_dir) one\n+\t  master                       $two two\n+\t  ref-to-branch                $two two\n+\t  ref-to-remote                $two two\n+\tEOF\n+\tgit worktree add worktree_dir branch-two &&\n+\tgit branch -vv >actual &&\n+\trm -r worktree_dir &&\n+\tgit worktree prune &&\n+\ttest_i18ncmp expect actual\n+'\n+\n test_done\n-- \n2.14.2\n\n"},{"id":"374641","messageId":"20190429141224.GA9286@szeder.dev","threadId":"49438","inReplyTo":"20190429051944.77164-1-nbelakovski@gmail.com","subject":"Re: [PATCH v10 0/3]","fromName":"SZEDER Gábor","fromEmail":"szeder.dev@gmail.com","sentAt":"2019-04-29T14:12:24Z","receivedAt":"2019-04-29T14:12:34Z","isPatch":true,"sender":{"key":"szeder.dev@gmail.com","avatar":"https://avatars.githubusercontent.com/u/116324?v=4"},"body":"On Sun, Apr 28, 2019 at 10:19:41PM -0700, nbelakovski@gmail.com wrote:\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n> \n> Added test_i18ncmp per instructions from Szeder\n> \n> Is there some other part of the infrastructure that's testing for this? Because it did not fail in any of my Travis CI builds.\n> \n> Travis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210\n\nTesting with GETTEXT_POISON was broken since 6cdccfce (i18n: make\nGETTEXT_POISON a runtime option, 2018-11-08), and didn't catch any of\nthese issues.  See:\n\n  https://public-inbox.org/git/xmqqlg0bvppc.fsf_-_@gitster-ct.c.googlers.com/T/#u\n\nThe fix f88b9cb603 (gettext tests: export the restored\nGIT_TEST_GETTEXT_POISON, 2019-04-15) was merged to master just last\nweek.\n\n"},{"id":"374651","messageId":"CAC05387vvSWD8Y-ufFU9VXkrtLWEDXCL+DP95UkGf3wWhytgsA@mail.gmail.com","threadId":"49438","inReplyTo":"20190429141224.GA9286@szeder.dev","subject":"Re: [PATCH v10 0/3]","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-04-29T19:27:12Z","receivedAt":"2019-04-29T19:27:40Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"> Testing with GETTEXT_POISON was broken since 6cdccfce (i18n: make\n> GETTEXT_POISON a runtime option, 2018-11-08), and didn't catch any of\n> these issues.  See:\n>\n>   https://public-inbox.org/git/xmqqlg0bvppc.fsf_-_@gitster-ct.c.googlers.com/T/#u\n>\n> The fix f88b9cb603 (gettext tests: export the restored\n> GIT_TEST_GETTEXT_POISON, 2019-04-15) was merged to master just last\n> week.\n>\n\nAh I see, thanks for the info.\n"},{"id":"374665","messageId":"nycvar.QRO.7.76.6.1904291656550.45@tvgsbejvaqbjf.bet","threadId":"49438","inReplyTo":"20190429051944.77164-1-nbelakovski@gmail.com","subject":"Re: [PATCH v10 0/3]","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-04-29T20:57:48Z","receivedAt":"2019-04-29T20:57:48Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nam I the only person who is puzzled every time this patch series with a\ncompletely empty subject and without any further explanation about the\nintent in the mail body is sent?\n\nCiao,\nJohannes\n\n\nOn Sun, 28 Apr 2019, nbelakovski@gmail.com wrote:\n\n> From: Nickolai Belakovski <nbelakovski@gmail.com>\n>\n> Added test_i18ncmp per instructions from Szeder\n>\n> Is there some other part of the infrastructure that's testing for this? Because it did not fail in any of my Travis CI builds.\n>\n> Travis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210\n>\n> Nickolai Belakovski (3):\n>   ref-filter: add worktreepath atom\n>   branch: update output to include worktree info\n>   branch: add worktree info on verbose output\n>\n>  Documentation/git-branch.txt       | 12 ++++--\n>  Documentation/git-for-each-ref.txt |  5 +++\n>  builtin/branch.c                   | 16 ++++++--\n>  ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n>  t/t3200-branch.sh                  | 16 +++++---\n>  t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-\n>  t/t6302-for-each-ref-filter.sh     | 13 +++++++\n>  7 files changed, 168 insertions(+), 15 deletions(-)\n>\n> --\n> 2.14.2\n>\n>\n"},{"id":"374669","messageId":"CAC05384E9Unm8qzjbXAsvn01xzbAPqg84vC=V90AGscA2cPOog@mail.gmail.com","threadId":"49438","inReplyTo":"nycvar.QRO.7.76.6.1904291656550.45@tvgsbejvaqbjf.bet","subject":"Re: [PATCH v10 0/3]","fromName":"Nickolai Belakovski","fromEmail":"nbelakovski@gmail.com","sentAt":"2019-04-29T21:33:37Z","receivedAt":"2019-04-29T21:34:06Z","isPatch":true,"sender":{"key":"nbelakovski@gmail.com","avatar":"https://avatars.githubusercontent.com/u/864630?v=4"},"body":"Sorry, I'm not very accustomed to mailing list development. I had\nassumed that this was being threaded with the other messages in the\nseries, hence leaving the subject blank and only putting new info in\nthe body.\n\nIn the future I'll add in an appropriate subject and brief re-hash in\nthe body. Thanks for bringing it up.\n\nNickolai\n\nOn Mon, Apr 29, 2019 at 1:57 PM Johannes Schindelin\n<Johannes.Schindelin@gmx.de> wrote:\n>\n> Hi,\n>\n> am I the only person who is puzzled every time this patch series with a\n> completely empty subject and without any further explanation about the\n> intent in the mail body is sent?\n>\n> Ciao,\n> Johannes\n>\n>\n> On Sun, 28 Apr 2019, nbelakovski@gmail.com wrote:\n>\n> > From: Nickolai Belakovski <nbelakovski@gmail.com>\n> >\n> > Added test_i18ncmp per instructions from Szeder\n> >\n> > Is there some other part of the infrastructure that's testing for this? Because it did not fail in any of my Travis CI builds.\n> >\n> > Travis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210\n> >\n> > Nickolai Belakovski (3):\n> >   ref-filter: add worktreepath atom\n> >   branch: update output to include worktree info\n> >   branch: add worktree info on verbose output\n> >\n> >  Documentation/git-branch.txt       | 12 ++++--\n> >  Documentation/git-for-each-ref.txt |  5 +++\n> >  builtin/branch.c                   | 16 ++++++--\n> >  ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++\n> >  t/t3200-branch.sh                  | 16 +++++---\n> >  t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-\n> >  t/t6302-for-each-ref-filter.sh     | 13 +++++++\n> >  7 files changed, 168 insertions(+), 15 deletions(-)\n> >\n> > --\n> > 2.14.2\n> >\n> >\n"},{"id":"374718","messageId":"nycvar.QRO.7.76.6.1904301740070.45@tvgsbejvaqbjf.bet","threadId":"49438","inReplyTo":"CAC05385Mc7pqiCd5mb+1c4WM+v7K=h=GMHuvkw9xizhRFJXXBA@mail.gmail.com","subject":"Re: [PATCH v10 0/3]","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2019-04-30T21:46:34Z","receivedAt":"2019-04-30T21:46:40Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi Nickolai,\n\nOn Mon, 29 Apr 2019, Nickolai Belakovski wrote:\n\n> Sorry, I'm not very accustomed to mailing list development. I had assumed\n> that this was being threaded with the other messages in the series, hence\n> leaving the subject blank and only putting new info in the body.\n\nThe openness of a mailing list-centric development is that everybody with\nan email address can participate [*1*].\n\nThe downside is that *anybody* with *any* mail program can be a reader, so\nyou cannot assume *anything* about how people will read your mails. Some\nwill read it in a mail program that color-codes levels of quotation.\nOthers will not have any color whatsoever. Some thread. Some don't. In\nmost mail programs, you cannot even search for a Message-ID. Which can be\nnon-unique.\n\nSo the perceived benefits of this way to run a project come at a price.\n\n> In the future I'll add in an appropriate subject and brief re-hash in the\n> body. Thanks for bringing it up.\n\nThank you,\nJohannes\n\nFootnote *1*: Of course, it is not *all* that open. If you cannot convince\nyour mail program to send mails in plain text only, and to stop\nreformatting mails e.g. to make them look better on cell phones (refusing\nthis is the price of requiring patches to be sent in whitespace-preserving\nplain text emails), then you're not invited to the party. This is why I\nsometimes say, not altogether without reason, that you can use *any*\nmail program to participate in the Git project as long as it is `mutt`.\n"}]}