git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
@ 2018-09-27 15:13 ` Nickolai Belakovski
  2018-09-27 15:33   ` Ævar Arnfjörð Bjarmason
                     ` (11 more replies)
  0 siblings, 12 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2018-09-27 15:13 UTC (permalink / raw)
  To: git

In order to more clearly display which branches are active, the output
of git branch is modified to colorize branches checked out in any linked
worktrees with the same color as the current branch.

This is meant to simplify workflows related to worktree, particularly
due to the limitations of not being able to check out the same branch in
two worktrees and the inability to delete a branch checked out in a
worktree. When performing branch operations like checkout and delete, it
would be useful to know more readily if the branches in which the user
is interested are already checked out in a worktree.

The git worktree list command contains the relevant information, however
this is a much less frquently used command than git branch.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---

Notes:
    Travis CI results: https://travis-ci.org/nbelakovski/git/builds/432320949

 builtin/branch.c         | 35 ++++++++++++++++++++++++++++++-----
 t/t3203-branch-output.sh | 21 +++++++++++++++++++++
 2 files changed, 51 insertions(+), 5 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 4fc55c350..65b58ff7c 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -334,11 +334,36 @@ static char *build_format(struct ref_filter
*filter, int maxwidth, const char *r
        struct strbuf local = STRBUF_INIT;
        struct strbuf remote = STRBUF_INIT;

-       strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-                   branch_get_color(BRANCH_COLOR_CURRENT),
-                   branch_get_color(BRANCH_COLOR_LOCAL));
-       strbuf_addf(&remote, "  %s",
-                   branch_get_color(BRANCH_COLOR_REMOTE));
+       // Prepend the current branch of this worktree with "* " and
all other branches with "  "
+       strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %%(else)  %%(end)");
+       // Prepend remote branches with two spaces
+       strbuf_addstr(&remote, "  ");
+       if(want_color(branch_use_color)) {
+               // Create a nested if statement to evaluate if the
current ref is equal to a HEAD ref from either
+               // the main or any linked worktrees. If so, color it
CURRENT, otherwise color it LOCAL
+               struct strbuf color = STRBUF_INIT;
+               struct worktree **worktrees = get_worktrees(0);
+               int i;
+               for (i = 0; worktrees[i]; ++i) {
+                       strbuf_addf(&color,
"%%(if:equals=%s)%%(refname)%%(then)%s%%(else)",
+                                   worktrees[i]->head_ref,
+                                   branch_get_color(BRANCH_COLOR_CURRENT));
+               }
+               // add one more check in the nested if-else to cover
the detached HEAD state
+               strbuf_addf(&color, "%%(if)%%(HEAD)%%(then)%s%%(else)%s%%(end)",
+                           branch_get_color(BRANCH_COLOR_CURRENT),
+                           branch_get_color(BRANCH_COLOR_LOCAL));
+               // close up the nested if-else
+               for (; i > 0; --i) {
+                       strbuf_addf(&color, "%%(end)");
+               }
+               free_worktrees(worktrees);
+               strbuf_addbuf(&local, &color);
+               strbuf_release(&color);
+
+               strbuf_addf(&remote, "%s",
+                           branch_get_color(BRANCH_COLOR_REMOTE));
+    }

        if (filter->verbose) {
                struct strbuf obname = STRBUF_INIT;
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614..369a156c0 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
        test_i18ncmp expect actual
 '

+test_expect_success '"add" a worktree' '
+       mkdir worktree_dir &&
+       git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
+  <GREEN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+       test_terminal git branch >actual.raw &&
+       test_decode_color <actual.raw >actual &&
+       test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
        echo "<RED>master<RESET>" >expect.color &&
        echo "master" >expect.bare &&

-- 
2.14.2

^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
@ 2018-09-27 15:33   ` Ævar Arnfjörð Bjarmason
  2018-09-27 17:46     ` Nickolai Belakovski
       [not found]     ` <CAC05387S9P+w8yqqcjkQDnURYSgQmqtukxS4KvqJu-kDA+_o0g@mail.gmail.com>
  2018-09-27 17:58   ` Duy Nguyen
                     ` (10 subsequent siblings)
  11 siblings, 2 replies; 125+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-09-27 15:33 UTC (permalink / raw)
  To: Nickolai Belakovski; +Cc: git


On Thu, Sep 27 2018, Nickolai Belakovski wrote:

> In order to more clearly display which branches are active, the output
> of git branch is modified to colorize branches checked out in any linked
> worktrees with the same color as the current branch.
>
> This is meant to simplify workflows related to worktree, particularly
> due to the limitations of not being able to check out the same branch in
> two worktrees and the inability to delete a branch checked out in a
> worktree. When performing branch operations like checkout and delete, it
> would be useful to know more readily if the branches in which the user
> is interested are already checked out in a worktree.
>
> The git worktree list command contains the relevant information, however
> this is a much less frquently used command than git branch.
>
> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>

Sounds cool, b.t.w. would be neat-o to have some screenshot uploaded to
imgur or whatever just to skim what it looks like before/after.

> diff --git a/builtin/branch.c b/builtin/branch.c
> index 4fc55c350..65b58ff7c 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter
> *filter, int maxwidth, const char *r
>         struct strbuf local = STRBUF_INIT;
>         struct strbuf remote = STRBUF_INIT;
>
> -       strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
> -                   branch_get_color(BRANCH_COLOR_CURRENT),
> -                   branch_get_color(BRANCH_COLOR_LOCAL));
> -       strbuf_addf(&remote, "  %s",
> -                   branch_get_color(BRANCH_COLOR_REMOTE));
> +       // Prepend the current branch of this worktree with "* " and
> all other branches with "  "


We use /* ... */ C comments, not C++-style // (well, it's in C now, but
not the ancient versions we need to support).

It also seems all of this patch was copy/pasted into GMail or something,
it has wrapping and doesn't apply with "git am".

Also most/all of these comments I'd say we could better do without,
i.e. the ones explaining basic code flow that's easy to see from the
code itself.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 15:33   ` Ævar Arnfjörð Bjarmason
@ 2018-09-27 17:46     ` Nickolai Belakovski
       [not found]     ` <CAC05387S9P+w8yqqcjkQDnURYSgQmqtukxS4KvqJu-kDA+_o0g@mail.gmail.com>
  1 sibling, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2018-09-27 17:46 UTC (permalink / raw)
  To: avarab; +Cc: git

Will do re: screenshot when I get home, although it's pretty easy to
imagine, the git branch output will have one other branch colored in
green, bit without the asterisk (for one linked worktree) :)

Also will do re: changing comments to /**/ (didn't know // was from
C++, TIL) and I'll clean up the comments to remove some of the more
obvious ones, but I'll try to keep a comment explaining the basic flow
of creating a nest if statement to evaluate worktree refs for color.

And yes, I copy/pasted into gmail. I was having trouble setting up
send-email, but I think I may have it figured out now. Should I create
a new thread with send-email? Or maybe reply to this one (I can do
that by specifying the Message-ID to reply to right? This is my first
time using this workflow, so I appreciate your patience :) )?

Thanks for the feedback!

On Thu, Sep 27, 2018 at 8:33 AM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
>
> On Thu, Sep 27 2018, Nickolai Belakovski wrote:
>
> > In order to more clearly display which branches are active, the output
> > of git branch is modified to colorize branches checked out in any linked
> > worktrees with the same color as the current branch.
> >
> > This is meant to simplify workflows related to worktree, particularly
> > due to the limitations of not being able to check out the same branch in
> > two worktrees and the inability to delete a branch checked out in a
> > worktree. When performing branch operations like checkout and delete, it
> > would be useful to know more readily if the branches in which the user
> > is interested are already checked out in a worktree.
> >
> > The git worktree list command contains the relevant information, however
> > this is a much less frquently used command than git branch.
> >
> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
>
> Sounds cool, b.t.w. would be neat-o to have some screenshot uploaded to
> imgur or whatever just to skim what it looks like before/after.
>
> > diff --git a/builtin/branch.c b/builtin/branch.c
> > index 4fc55c350..65b58ff7c 100644
> > --- a/builtin/branch.c
> > +++ b/builtin/branch.c
> > @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter
> > *filter, int maxwidth, const char *r
> >         struct strbuf local = STRBUF_INIT;
> >         struct strbuf remote = STRBUF_INIT;
> >
> > -       strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
> > -                   branch_get_color(BRANCH_COLOR_CURRENT),
> > -                   branch_get_color(BRANCH_COLOR_LOCAL));
> > -       strbuf_addf(&remote, "  %s",
> > -                   branch_get_color(BRANCH_COLOR_REMOTE));
> > +       // Prepend the current branch of this worktree with "* " and
> > all other branches with "  "
>
>
> We use /* ... */ C comments, not C++-style // (well, it's in C now, but
> not the ancient versions we need to support).
>
> It also seems all of this patch was copy/pasted into GMail or something,
> it has wrapping and doesn't apply with "git am".
>
> Also most/all of these comments I'd say we could better do without,
> i.e. the ones explaining basic code flow that's easy to see from the
> code itself.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
  2018-09-27 15:33   ` Ævar Arnfjörð Bjarmason
@ 2018-09-27 17:58   ` Duy Nguyen
  2018-09-27 18:17   ` Jeff King
                     ` (9 subsequent siblings)
  11 siblings, 0 replies; 125+ messages in thread
From: Duy Nguyen @ 2018-09-27 17:58 UTC (permalink / raw)
  To: nbelakovski; +Cc: Git Mailing List

On Thu, Sep 27, 2018 at 5:15 PM Nickolai Belakovski
<nbelakovski@gmail.com> wrote:
>
> In order to more clearly display which branches are active, the output
> of git branch is modified to colorize branches checked out in any linked
> worktrees with the same color as the current branch.

My first thought was "how do I know which branch I'm on then if they
are all green?" but then the current worktree's branch would have a
"*" in front while other worktree's do not. Perhaps worth mentioning
in the commit message.

It may be better though to have a different color code for other
worktree's branch, we can still default the color to green, but people
who rely on colors rather than "*" can choose a different color.
-- 
Duy

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
       [not found]     ` <CAC05387S9P+w8yqqcjkQDnURYSgQmqtukxS4KvqJu-kDA+_o0g@mail.gmail.com>
@ 2018-09-27 17:59       ` Ævar Arnfjörð Bjarmason
  2018-10-02 20:41         ` Johannes Schindelin
  0 siblings, 1 reply; 125+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-09-27 17:59 UTC (permalink / raw)
  To: Nickolai Belakovski; +Cc: git, Johannes Schindelin, Derrick Stolee


On Thu, Sep 27 2018, Nickolai Belakovski wrote:

> Will do re: screenshot when I get home, although it's pretty easy to
> imagine, the git branch output will have one other branch colored in green,
> bit without the asterisk (for one linked worktree) :)
>
> Also will do re: changing comments to /**/ (didn't know // was from C++,
> TIL) and I'll clean up the comments to remove some of the more obvious
> ones, but I'll try to keep a comment explaining the basic flow of creating
> a nest if statement to evaluate worktree refs for color.
>
> And yes, I copy/pasted into gmail. I was having trouble setting up
> send-email, but I think I may have it figured out now. Should I create a
> new thread with send-email? Or maybe reply to this one (I can do that by
> specifying the Message-ID to reply to right?

You'd run git format-patch master..your-topic with
--subject-prefix="PATCH v2" and
--in-reply-to="<CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com>". Then
it'll show up in reply to your v1.

You can also for an easier experience do this via GitGitGadget, see
https://github.com/gitgitgadget/gitgitgadget looking at its code it
seems to have some way to reference a Message-ID, but I don't know how
to trigger that.

> This is my first time using this workflow, so I appreciate your
> patience :) )?

No worries, happy to help.

> On Thu, Sep 27, 2018 at 8:33 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> wrote:
>
>>
>> On Thu, Sep 27 2018, Nickolai Belakovski wrote:
>>
>> > In order to more clearly display which branches are active, the output
>> > of git branch is modified to colorize branches checked out in any linked
>> > worktrees with the same color as the current branch.
>> >
>> > This is meant to simplify workflows related to worktree, particularly
>> > due to the limitations of not being able to check out the same branch in
>> > two worktrees and the inability to delete a branch checked out in a
>> > worktree. When performing branch operations like checkout and delete, it
>> > would be useful to know more readily if the branches in which the user
>> > is interested are already checked out in a worktree.
>> >
>> > The git worktree list command contains the relevant information, however
>> > this is a much less frquently used command than git branch.
>> >
>> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
>>
>> Sounds cool, b.t.w. would be neat-o to have some screenshot uploaded to
>> imgur or whatever just to skim what it looks like before/after.
>>
>> > diff --git a/builtin/branch.c b/builtin/branch.c
>> > index 4fc55c350..65b58ff7c 100644
>> > --- a/builtin/branch.c
>> > +++ b/builtin/branch.c
>> > @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter
>> > *filter, int maxwidth, const char *r
>> >         struct strbuf local = STRBUF_INIT;
>> >         struct strbuf remote = STRBUF_INIT;
>> >
>> > -       strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)
>> %s%%(end)",
>> > -                   branch_get_color(BRANCH_COLOR_CURRENT),
>> > -                   branch_get_color(BRANCH_COLOR_LOCAL));
>> > -       strbuf_addf(&remote, "  %s",
>> > -                   branch_get_color(BRANCH_COLOR_REMOTE));
>> > +       // Prepend the current branch of this worktree with "* " and
>> > all other branches with "  "
>>
>>
>> We use /* ... */ C comments, not C++-style // (well, it's in C now, but
>> not the ancient versions we need to support).
>>
>> It also seems all of this patch was copy/pasted into GMail or something,
>> it has wrapping and doesn't apply with "git am".
>>
>> Also most/all of these comments I'd say we could better do without,
>> i.e. the ones explaining basic code flow that's easy to see from the
>> code itself.
>>

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
  2018-09-27 15:33   ` Ævar Arnfjörð Bjarmason
  2018-09-27 17:58   ` Duy Nguyen
@ 2018-09-27 18:17   ` Jeff King
  2018-09-27 18:39     ` Nickolai Belakovski
  2018-09-27 19:28     ` Rafael Ascensão
  2019-01-06  0:26   ` [PATCH v5 0/3] nbelakovski
                     ` (8 subsequent siblings)
  11 siblings, 2 replies; 125+ messages in thread
From: Jeff King @ 2018-09-27 18:17 UTC (permalink / raw)
  To: Nickolai Belakovski; +Cc: git

On Thu, Sep 27, 2018 at 08:13:13AM -0700, Nickolai Belakovski wrote:

> In order to more clearly display which branches are active, the output
> of git branch is modified to colorize branches checked out in any linked
> worktrees with the same color as the current branch.

I think the goal makes sense.

Do we want to limit this to git-branch, though? Ideally any output you
get from git-branch could be replicated with for-each-ref (or with
a custom "branch --format").

I.e., could we have a format in ref-filter that matches HEAD, but
returns a distinct symbol for a worktree HEAD? That would allow a few
things:

  - custom --formats for for-each-ref and branch could reuse the logic

  - we could show the symbol (in place of "*") even when color is not
    enabled

  - it should be much faster if there are a lot of worktrees; your patch
    does a linear if/else chain to look at each worktree, and it does it
    in the format-language, which is much slower than actual C. :)

Something like the patch below. I just picked "+" arbitrarily, but any
character would do (I avoided "*" just to make it visually distinct from
the current-worktree HEAD). I've left plugging this into git-branch's
default format as an exercise for the reader. ;)

---
diff --git a/ref-filter.c b/ref-filter.c
index e1bcb4ca8a..b17eefed0d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,7 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -114,6 +115,7 @@ static struct used_atom {
 		} objectname;
 		struct refname_atom refname;
 		char *head;
+		struct string_list worktree_heads;
 	} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
@@ -420,6 +422,29 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
 	return 0;
 }
 
+static int worktree_head_atom_parser(const struct ref_format *format,
+				     struct used_atom *atom,
+				     const char *arg,
+				     struct strbuf *unused_err)
+{
+	struct worktree **worktrees = get_worktrees(0);
+	int i;
+
+	string_list_init(&atom->u.worktree_heads, 1);
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref)
+			string_list_append(&atom->u.worktree_heads,
+					   worktrees[i]->head_ref);
+	}
+
+	string_list_sort(&atom->u.worktree_heads);
+
+	free_worktrees(worktrees);
+	return 0;
+
+}
+
 static struct {
 	const char *name;
 	info_source source;
@@ -460,6 +485,7 @@ static struct {
 	{ "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
+	{ "worktree", SOURCE_NONE, FIELD_STR, worktree_head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
@@ -1588,6 +1614,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 			else
 				v->s = " ";
 			continue;
+		} else if (!strcmp(name, "worktree")) {
+			if (string_list_has_string(&atom->u.worktree_heads,
+						   ref->refname))
+				v->s = "+";
+			else
+				v->s = " ";
+			continue;
 		} else if (starts_with(name, "align")) {
 			v->handler = align_atom_handler;
 			v->s = "";

^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 18:17   ` Jeff King
@ 2018-09-27 18:39     ` Nickolai Belakovski
  2018-09-27 18:51       ` Jeff King
  2018-09-27 19:28     ` Rafael Ascensão
  1 sibling, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2018-09-27 18:39 UTC (permalink / raw)
  To: Jeff King; +Cc: git

Thanks for the feedback Peff. I actually agree with all your points.
I'd considered an approach like what you proposed, but rejected it for
the first iteration in an effort to keep scope limited and see what
kind of feedback I'd get overall (like would people even want this?).
This is a much better approach, and also gives a path for listing the
worktree path in the verbose output.

@Duy yea we can use a different color, maybe a darker shade of green.
I saw plenty to choose from in the color list so I'll play around with
it. It would definitely make it easier to distinguish at a glance
which branch is checked out in the current worktree vs others.
On Thu, Sep 27, 2018 at 11:17 AM Jeff King <peff@peff.net> wrote:
>
> On Thu, Sep 27, 2018 at 08:13:13AM -0700, Nickolai Belakovski wrote:
>
> > In order to more clearly display which branches are active, the output
> > of git branch is modified to colorize branches checked out in any linked
> > worktrees with the same color as the current branch.
>
> I think the goal makes sense.
>
> Do we want to limit this to git-branch, though? Ideally any output you
> get from git-branch could be replicated with for-each-ref (or with
> a custom "branch --format").
>
> I.e., could we have a format in ref-filter that matches HEAD, but
> returns a distinct symbol for a worktree HEAD? That would allow a few
> things:
>
>   - custom --formats for for-each-ref and branch could reuse the logic
>
>   - we could show the symbol (in place of "*") even when color is not
>     enabled
>
>   - it should be much faster if there are a lot of worktrees; your patch
>     does a linear if/else chain to look at each worktree, and it does it
>     in the format-language, which is much slower than actual C. :)
>
> Something like the patch below. I just picked "+" arbitrarily, but any
> character would do (I avoided "*" just to make it visually distinct from
> the current-worktree HEAD). I've left plugging this into git-branch's
> default format as an exercise for the reader. ;)
>
> ---
> diff --git a/ref-filter.c b/ref-filter.c
> index e1bcb4ca8a..b17eefed0d 100644
> --- a/ref-filter.c
> +++ b/ref-filter.c
> @@ -20,6 +20,7 @@
>  #include "commit-slab.h"
>  #include "commit-graph.h"
>  #include "commit-reach.h"
> +#include "worktree.h"
>
>  static struct ref_msg {
>         const char *gone;
> @@ -114,6 +115,7 @@ static struct used_atom {
>                 } objectname;
>                 struct refname_atom refname;
>                 char *head;
> +               struct string_list worktree_heads;
>         } u;
>  } *used_atom;
>  static int used_atom_cnt, need_tagged, need_symref;
> @@ -420,6 +422,29 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
>         return 0;
>  }
>
> +static int worktree_head_atom_parser(const struct ref_format *format,
> +                                    struct used_atom *atom,
> +                                    const char *arg,
> +                                    struct strbuf *unused_err)
> +{
> +       struct worktree **worktrees = get_worktrees(0);
> +       int i;
> +
> +       string_list_init(&atom->u.worktree_heads, 1);
> +
> +       for (i = 0; worktrees[i]; i++) {
> +               if (worktrees[i]->head_ref)
> +                       string_list_append(&atom->u.worktree_heads,
> +                                          worktrees[i]->head_ref);
> +       }
> +
> +       string_list_sort(&atom->u.worktree_heads);
> +
> +       free_worktrees(worktrees);
> +       return 0;
> +
> +}
> +
>  static struct {
>         const char *name;
>         info_source source;
> @@ -460,6 +485,7 @@ static struct {
>         { "symref", SOURCE_NONE, FIELD_STR, refname_atom_parser },
>         { "flag", SOURCE_NONE },
>         { "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
> +       { "worktree", SOURCE_NONE, FIELD_STR, worktree_head_atom_parser },
>         { "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
>         { "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
>         { "end", SOURCE_NONE },
> @@ -1588,6 +1614,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
>                         else
>                                 v->s = " ";
>                         continue;
> +               } else if (!strcmp(name, "worktree")) {
> +                       if (string_list_has_string(&atom->u.worktree_heads,
> +                                                  ref->refname))
> +                               v->s = "+";
> +                       else
> +                               v->s = " ";
> +                       continue;
>                 } else if (starts_with(name, "align")) {
>                         v->handler = align_atom_handler;
>                         v->s = "";

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 18:39     ` Nickolai Belakovski
@ 2018-09-27 18:51       ` Jeff King
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2018-09-27 18:51 UTC (permalink / raw)
  To: Nickolai Belakovski; +Cc: git

On Thu, Sep 27, 2018 at 11:39:26AM -0700, Nickolai Belakovski wrote:

> Thanks for the feedback Peff. I actually agree with all your points.
> I'd considered an approach like what you proposed, but rejected it for
> the first iteration in an effort to keep scope limited and see what
> kind of feedback I'd get overall (like would people even want this?).
> This is a much better approach, and also gives a path for listing the
> worktree path in the verbose output.

Great. If you go that route, feel free to use whatever bits of my patch
are useful. I tested it only by running "for-each-ref" once, so it might
need some more help. Definitely tests and documentation at the least. :)

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 18:17   ` Jeff King
  2018-09-27 18:39     ` Nickolai Belakovski
@ 2018-09-27 19:28     ` Rafael Ascensão
  2018-09-27 19:35       ` Jeff King
  2018-09-27 20:02       ` Ævar Arnfjörð Bjarmason
  1 sibling, 2 replies; 125+ messages in thread
From: Rafael Ascensão @ 2018-09-27 19:28 UTC (permalink / raw)
  To: Jeff King; +Cc: Nickolai Belakovski, git

On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:
> Do we want to limit this to git-branch, though? Ideally any output you
> get from git-branch could be replicated with for-each-ref (or with
> a custom "branch --format").
> 
> I.e., could we have a format in ref-filter that matches HEAD, but
> returns a distinct symbol for a worktree HEAD? That would allow a few
> things:

I was going to suggest using dim green and green for elsewhere and here
respectively, in a similar way how range-diff uses it to show different
versions of the same diff.

But if we're open to change how branches are displayed maybe a config
option like branch.format (probably not the best name choice) that can
be set to the 'for-each-ref --format' syntax would be way more flexible.

e.g.
    branch.format='%(if:equals=+)...'

I think the different symbol and dimmed color would be a nice addition,
but I am leaning towards giving the user the ultimate choice on how they
want to format their output. (Maybe with dimmed plus symbol as default).

--
Cheers,
Rafael Ascensão

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 19:28     ` Rafael Ascensão
@ 2018-09-27 19:35       ` Jeff King
  2018-09-27 19:41         ` Jeff King
  2018-09-27 21:35         ` Rafael Ascensão
  2018-09-27 20:02       ` Ævar Arnfjörð Bjarmason
  1 sibling, 2 replies; 125+ messages in thread
From: Jeff King @ 2018-09-27 19:35 UTC (permalink / raw)
  To: Rafael Ascensão; +Cc: Nickolai Belakovski, git

On Thu, Sep 27, 2018 at 08:28:04PM +0100, Rafael Ascensão wrote:

> On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:
> > Do we want to limit this to git-branch, though? Ideally any output you
> > get from git-branch could be replicated with for-each-ref (or with
> > a custom "branch --format").
> > 
> > I.e., could we have a format in ref-filter that matches HEAD, but
> > returns a distinct symbol for a worktree HEAD? That would allow a few
> > things:
> 
> I was going to suggest using dim green and green for elsewhere and here
> respectively, in a similar way how range-diff uses it to show different
> versions of the same diff.

Yeah, I think that's reasonable, and would be enabled by the %(worktree)
placeholder I showed. Just like we do something like:

  %(if)%(HEAD)%(then)* %(color:green)%(else)  %(end)

now, we could do:

  %(if)%(HEAD)%(then)* %(color:bold green)
  %(else)%(if)%(worktree)%(then)+ %(color:green)
  %(else)  %(end)%(end)

(respecting the user's color config, of course, rather than hard-coded
colors).

Trying that out, though, I'm not sure if we properly support nested
if's. That might be a bug we have to fix first.

> But if we're open to change how branches are displayed maybe a config
> option like branch.format (probably not the best name choice) that can
> be set to the 'for-each-ref --format' syntax would be way more flexible.

We have that already, don't we?

> I think the different symbol and dimmed color would be a nice addition,
> but I am leaning towards giving the user the ultimate choice on how they
> want to format their output. (Maybe with dimmed plus symbol as default).

Definitely.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 19:35       ` Jeff King
@ 2018-09-27 19:41         ` Jeff King
  2018-09-27 21:22           ` Junio C Hamano
  2018-09-27 21:35         ` Rafael Ascensão
  1 sibling, 1 reply; 125+ messages in thread
From: Jeff King @ 2018-09-27 19:41 UTC (permalink / raw)
  To: Rafael Ascensão; +Cc: Nickolai Belakovski, git

On Thu, Sep 27, 2018 at 03:35:59PM -0400, Jeff King wrote:

> now, we could do:
> 
>   %(if)%(HEAD)%(then)* %(color:bold green)
>   %(else)%(if)%(worktree)%(then)+ %(color:green)
>   %(else)  %(end)%(end)
> 
> (respecting the user's color config, of course, rather than hard-coded
> colors).
> 
> Trying that out, though, I'm not sure if we properly support nested
> if's. That might be a bug we have to fix first.

Sorry, false alarm. I just had a typo in my format.

This seems to work with the patch I posted earlier:

  git for-each-ref \
    --format='%(if)%(HEAD)%(then)* %(color:bold green)%(else)%(if)%(worktree)%(then)+ %(color:green)%(else) %(end)%(end)%(refname)' \
  refs/heads

It sure would be nice if there was a way to insert line breaks without
impacting the output. ;)

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 19:28     ` Rafael Ascensão
  2018-09-27 19:35       ` Jeff King
@ 2018-09-27 20:02       ` Ævar Arnfjörð Bjarmason
  2018-09-27 20:16         ` Nickolai Belakovski
  1 sibling, 1 reply; 125+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-09-27 20:02 UTC (permalink / raw)
  To: Rafael Ascensão; +Cc: Jeff King, Nickolai Belakovski, git


On Thu, Sep 27 2018, Rafael Ascensão wrote:

> On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:
>> Do we want to limit this to git-branch, though? Ideally any output you
>> get from git-branch could be replicated with for-each-ref (or with
>> a custom "branch --format").
>>
>> I.e., could we have a format in ref-filter that matches HEAD, but
>> returns a distinct symbol for a worktree HEAD? That would allow a few
>> things:
>
> I was going to suggest using dim green and green for elsewhere and here
> respectively, in a similar way how range-diff uses it to show different
> versions of the same diff.

It would be really useful to (just via E-Mail to start) itemize the
colors we use in various places and what they mean.

E.g. I thought green here made sense because in "diff" we show the
old/new as red/green, so the branch you're on is "new" in the same
sense, i.e. it's what your current state is.

But maybe there's cases where that doesn't "rhyme" as it were.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 20:02       ` Ævar Arnfjörð Bjarmason
@ 2018-09-27 20:16         ` Nickolai Belakovski
  2018-09-27 20:40           ` Rafael Ascensão
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2018-09-27 20:16 UTC (permalink / raw)
  To: avarab; +Cc: rafa.almas, Jeff King, git

Not to hijack my own thread, but FWIW git branch -r shows remote
branches in red, but old/new status of a remote branch is ambiguous
(could have new stuff, could be out of date). Also, git branch -vv
shows remote tracking branches in blue. One could argue it should be
red since git branch -r is in red.

But yea, probably best to take this topic to its own thread.
On Thu, Sep 27, 2018 at 1:02 PM Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
>
> On Thu, Sep 27 2018, Rafael Ascensão wrote:
>
> > On Thu, Sep 27, 2018 at 02:17:08PM -0400, Jeff King wrote:
> >> Do we want to limit this to git-branch, though? Ideally any output you
> >> get from git-branch could be replicated with for-each-ref (or with
> >> a custom "branch --format").
> >>
> >> I.e., could we have a format in ref-filter that matches HEAD, but
> >> returns a distinct symbol for a worktree HEAD? That would allow a few
> >> things:
> >
> > I was going to suggest using dim green and green for elsewhere and here
> > respectively, in a similar way how range-diff uses it to show different
> > versions of the same diff.
>
> It would be really useful to (just via E-Mail to start) itemize the
> colors we use in various places and what they mean.
>
> E.g. I thought green here made sense because in "diff" we show the
> old/new as red/green, so the branch you're on is "new" in the same
> sense, i.e. it's what your current state is.
>
> But maybe there's cases where that doesn't "rhyme" as it were.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 20:16         ` Nickolai Belakovski
@ 2018-09-27 20:40           ` Rafael Ascensão
  2018-11-11 23:58             ` [PATCH v2 0/2] refactoring branch colorization to ref-filter nbelakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Rafael Ascensão @ 2018-09-27 20:40 UTC (permalink / raw)
  To: Nickolai Belakovski; +Cc: avarab, Jeff King, git

On Thu, Sep 27, 2018 at 01:16:19PM -0700, Nickolai Belakovski wrote:
>
> Not to hijack my own thread, but FWIW git branch -r shows remote
> branches in red, but old/new status of a remote branch is ambiguous
> (could have new stuff, could be out of date). Also, git branch -vv
> shows remote tracking branches in blue. One could argue it should be
> red since git branch -r is in red.
>

For me remote branches being red means: they're here but you cannot
write to them. They are like 'read-only/disabled' branches. Under this
interpretation red makes sense.


On Thu, Sep 27, 2018 at 9:02 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:
>
> E.g. I thought green here made sense because in "diff" we show the
> old/new as red/green, so the branch you're on is "new" in the same
> sense, i.e. it's what your current state is.
>

I still defend using green and dim green for this case. Because all
these worktrees are in a sense active. They're checked out in some
place. It's just the case that the particular one that we are in is
probably more relevant than the others.

--
Cheers
Rafael Ascensão

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 19:41         ` Jeff King
@ 2018-09-27 21:22           ` Junio C Hamano
  2018-09-28  1:05             ` Jeff King
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2018-09-27 21:22 UTC (permalink / raw)
  To: Jeff King; +Cc: Rafael Ascensão, Nickolai Belakovski, git

Jeff King <peff@peff.net> writes:

> On Thu, Sep 27, 2018 at 03:35:59PM -0400, Jeff King wrote:
>
>> now, we could do:
>> 
>>   %(if)%(HEAD)%(then)* %(color:bold green)
>>   %(else)%(if)%(worktree)%(then)+ %(color:green)
>>   %(else)  %(end)%(end)
>> 
>> (respecting the user's color config, of course, rather than hard-coded
>> colors).
>> 
>> Trying that out, though, I'm not sure if we properly support nested
>> if's. That might be a bug we have to fix first.
>
> Sorry, false alarm. I just had a typo in my format.
>
> This seems to work with the patch I posted earlier:
>
>   git for-each-ref \
>     --format='%(if)%(HEAD)%(then)* %(color:bold green)%(else)%(if)%(worktree)%(then)+ %(color:green)%(else) %(end)%(end)%(refname)' \
>   refs/heads
>
> It sure would be nice if there was a way to insert line breaks without
> impacting the output. ;)
>
> -Peff

I envy all of you who seem to have had a lot of fun while I was
doing something else (which were rather boring but still needed
precision--my least favorite kind of task X-<).

The only comment I have is that I strongly suspect we will regret if
we used an overly bland "worktree" to a rather narrrow "is this ref
checked out in any worktree?" when we notice we want to learn other
things that are related to "worktree".  Other than that, very nicely
done.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 19:35       ` Jeff King
  2018-09-27 19:41         ` Jeff King
@ 2018-09-27 21:35         ` Rafael Ascensão
  2018-09-28  1:07           ` Jeff King
  1 sibling, 1 reply; 125+ messages in thread
From: Rafael Ascensão @ 2018-09-27 21:35 UTC (permalink / raw)
  To: Jeff King; +Cc: Nickolai Belakovski, git

On Thu, Sep 27, 2018 at 03:35:59PM -0400, Jeff King wrote:
> On Thu, Sep 27, 2018 at 08:28:04PM +0100, Rafael Ascensão wrote:
> > But if we're open to change how branches are displayed maybe a config
> > option like branch.format (probably not the best name choice) that can
> > be set to the 'for-each-ref --format' syntax would be way more flexible.
> 
> We have that already, don't we?
>

git branch has --format, but there's no way (at least to my knowledge)
to define a value in gitconfig to be used by $git branch.

Having branch --format available, making an alias is a possible route.
(Either by wrapping branch --format or for-each-ref itself). But I was
referring to changing the output of the default $git branch;


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 21:22           ` Junio C Hamano
@ 2018-09-28  1:05             ` Jeff King
  2018-09-28  1:28               ` Junio C Hamano
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2018-09-28  1:05 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Rafael Ascensão, Nickolai Belakovski, git

On Thu, Sep 27, 2018 at 02:22:49PM -0700, Junio C Hamano wrote:

> The only comment I have is that I strongly suspect we will regret if
> we used an overly bland "worktree" to a rather narrrow "is this ref
> checked out in any worktree?" when we notice we want to learn other
> things that are related to "worktree".  Other than that, very nicely
> done.

Yeah, I should have mentioned that. %(worktree) was just a placeholder.
Perhaps something like %(worktree-HEAD) would make more sense (the idea
is that it is an extension of the existing %(HEAD) placeholder).

Alternatively, %(HEAD) could return "*" or "+" depending on whether it's
the current worktree head. That would mildly break an existing format
like:

  %(if)%(HEAD)%(then) *%(color:green)%(end)%(refname)

since it would start coloring worktree HEADs the same way. It would be
rewritten as:

  %(if:equals=*)%(HEAD)%(then)...real HEAD...
  %(else)%(if:equals=+)%(HEAD)%(then)...worktree HEAD...
  %(else)...regular ref...
  %(end)%(end)

I think that's perhaps nicer, but I'm not sure we want even such a minor
regression.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 21:35         ` Rafael Ascensão
@ 2018-09-28  1:07           ` Jeff King
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2018-09-28  1:07 UTC (permalink / raw)
  To: Rafael Ascensão; +Cc: Nickolai Belakovski, git

On Thu, Sep 27, 2018 at 10:35:11PM +0100, Rafael Ascensão wrote:

> git branch has --format, but there's no way (at least to my knowledge)
> to define a value in gitconfig to be used by $git branch.

Oh, you're right. I was thinking of the branch.sort we just added in
v2.19.

I agree that having branch.format (and a matching tag.format) would be
useful.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-28  1:05             ` Jeff King
@ 2018-09-28  1:28               ` Junio C Hamano
  0 siblings, 0 replies; 125+ messages in thread
From: Junio C Hamano @ 2018-09-28  1:28 UTC (permalink / raw)
  To: Jeff King; +Cc: Rafael Ascensão, Nickolai Belakovski, git

Jeff King <peff@peff.net> writes:

> Alternatively, %(HEAD) could return "*" or "+" depending on whether it's
> the current worktree head. That would mildly break an existing format
> like:
>
>   %(if)%(HEAD)%(then) *%(color:green)%(end)%(refname)
>
> since it would start coloring worktree HEADs the same way. It would be
> rewritten as:
>
>   %(if:equals=*)%(HEAD)%(then)...real HEAD...
>   %(else)%(if:equals=+)%(HEAD)%(then)...worktree HEAD...
>   %(else)...regular ref...
>   %(end)%(end)
>
> I think that's perhaps nicer, but I'm not sure we want even such a minor
> regression.

I tend to think it is not worth having to worry about it by changing
the meaning of %(HEAD) marking to save the effort to find a new
token to fill that placeholder.  Your %(worktreeHEAD) is good
enough, I would think.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized
  2018-09-27 17:59       ` Ævar Arnfjörð Bjarmason
@ 2018-10-02 20:41         ` Johannes Schindelin
  0 siblings, 0 replies; 125+ messages in thread
From: Johannes Schindelin @ 2018-10-02 20:41 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Nickolai Belakovski, git, Derrick Stolee

[-- Attachment #1: Type: text/plain, Size: 4674 bytes --]

Hi Ævar,

On Thu, 27 Sep 2018, Ævar Arnfjörð Bjarmason wrote:

> On Thu, Sep 27 2018, Nickolai Belakovski wrote:
> 
> > Will do re: screenshot when I get home, although it's pretty easy to
> > imagine, the git branch output will have one other branch colored in green,
> > bit without the asterisk (for one linked worktree) :)
> >
> > Also will do re: changing comments to /**/ (didn't know // was from C++,
> > TIL) and I'll clean up the comments to remove some of the more obvious
> > ones, but I'll try to keep a comment explaining the basic flow of creating
> > a nest if statement to evaluate worktree refs for color.
> >
> > And yes, I copy/pasted into gmail. I was having trouble setting up
> > send-email, but I think I may have it figured out now. Should I create a
> > new thread with send-email? Or maybe reply to this one (I can do that by
> > specifying the Message-ID to reply to right?
> 
> You'd run git format-patch master..your-topic with
> --subject-prefix="PATCH v2" and
> --in-reply-to="<CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com>". Then
> it'll show up in reply to your v1.

There is also a nice tutorial in
https://github.com/git-for-windows/git/blob/master/CONTRIBUTING.md#submit-your-patch
(which, contrary to the location, is useful for non-Windows developers,
too.)

> You can also for an easier experience do this via GitGitGadget, see
> https://github.com/gitgitgadget/gitgitgadget looking at its code it
> seems to have some way to reference a Message-ID, but I don't know how
> to trigger that.

IIRC GitGitGadget has no facility yet to reply to any mail it did not
generate itself (i.e. if you did not generate v1 using GitGitGadget, then
it cannot generate a v2 that replies to the previous iteration).

This might change at some stage, but I have other priorities for now.
(Which should not stop any contributor from opening a PR to scratch their
own favorite itch.)

Ciao,
Johannes

> 
> > This is my first time using this workflow, so I appreciate your
> > patience :) )?
> 
> No worries, happy to help.
> 
> > On Thu, Sep 27, 2018 at 8:33 AM Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> > wrote:
> >
> >>
> >> On Thu, Sep 27 2018, Nickolai Belakovski wrote:
> >>
> >> > In order to more clearly display which branches are active, the output
> >> > of git branch is modified to colorize branches checked out in any linked
> >> > worktrees with the same color as the current branch.
> >> >
> >> > This is meant to simplify workflows related to worktree, particularly
> >> > due to the limitations of not being able to check out the same branch in
> >> > two worktrees and the inability to delete a branch checked out in a
> >> > worktree. When performing branch operations like checkout and delete, it
> >> > would be useful to know more readily if the branches in which the user
> >> > is interested are already checked out in a worktree.
> >> >
> >> > The git worktree list command contains the relevant information, however
> >> > this is a much less frquently used command than git branch.
> >> >
> >> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
> >>
> >> Sounds cool, b.t.w. would be neat-o to have some screenshot uploaded to
> >> imgur or whatever just to skim what it looks like before/after.
> >>
> >> > diff --git a/builtin/branch.c b/builtin/branch.c
> >> > index 4fc55c350..65b58ff7c 100644
> >> > --- a/builtin/branch.c
> >> > +++ b/builtin/branch.c
> >> > @@ -334,11 +334,36 @@ static char *build_format(struct ref_filter
> >> > *filter, int maxwidth, const char *r
> >> >         struct strbuf local = STRBUF_INIT;
> >> >         struct strbuf remote = STRBUF_INIT;
> >> >
> >> > -       strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)
> >> %s%%(end)",
> >> > -                   branch_get_color(BRANCH_COLOR_CURRENT),
> >> > -                   branch_get_color(BRANCH_COLOR_LOCAL));
> >> > -       strbuf_addf(&remote, "  %s",
> >> > -                   branch_get_color(BRANCH_COLOR_REMOTE));
> >> > +       // Prepend the current branch of this worktree with "* " and
> >> > all other branches with "  "
> >>
> >>
> >> We use /* ... */ C comments, not C++-style // (well, it's in C now, but
> >> not the ancient versions we need to support).
> >>
> >> It also seems all of this patch was copy/pasted into GMail or something,
> >> it has wrapping and doesn't apply with "git am".
> >>
> >> Also most/all of these comments I'd say we could better do without,
> >> i.e. the ones explaining basic code flow that's easy to see from the
> >> code itself.
> >>
> 

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v2 0/2] refactoring branch colorization to ref-filter
  2018-09-27 20:40           ` Rafael Ascensão
@ 2018-11-11 23:58             ` nbelakovski
  2018-11-11 23:58               ` [PATCH v2 1/2] ref-filter: add worktree atom nbelakovski
                                 ` (2 more replies)
  0 siblings, 3 replies; 125+ messages in thread
From: nbelakovski @ 2018-11-11 23:58 UTC (permalink / raw)
  To: rafa.almas; +Cc: avarab, git, nbelakovski, peff

From: Nickolai Belakovski <nbelakovski@gmail.com>

Finally found some time to follow up on this :)

I decided to take the approach suggested by Peff for simplicity. I have
another version which uses a hash map to store *all* of the information
returned by get_worktrees, information which can then be accessed in
the fashion %(workree:path) or %(worktree:is_detached), but it seemed
like a lot of code to add and there was no use case to justify the
addition of a hash map at this time. If there's interest though, I can
make a separate patch after this one to introduce those changes. They
build directly off of the changes introduced here.

I've split this work into two commits since the items are logically
separate.

CI results: https://travis-ci.org/nbelakovski/git/builds/453723727

Nickolai Belakovski (2):
  ref-filter: add worktree atom
  branch: Mark and colorize a branch differently if it is checked out in
    a linked worktree

 builtin/branch.c               | 22 +++++++++++++---------
 color.h                        | 18 ++++++++++++++++++
 ref-filter.c                   | 31 +++++++++++++++++++++++++++++++
 t/t3200-branch.sh              |  8 ++++----
 t/t3203-branch-output.sh       | 21 +++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh | 15 +++++++++++++++
 t/test-lib-functions.sh        |  6 ++++++
 7 files changed, 108 insertions(+), 13 deletions(-)

-- 
2.14.2


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v2 1/2] ref-filter: add worktree atom
  2018-11-11 23:58             ` [PATCH v2 0/2] refactoring branch colorization to ref-filter nbelakovski
@ 2018-11-11 23:58               ` nbelakovski
  2018-11-12 10:11                 ` Junio C Hamano
  2018-11-12 12:23                 ` Jeff King
  2018-11-11 23:58               ` [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree nbelakovski
  2018-12-16 21:57               ` [PATCH v3 0/3] nbelakovski
  2 siblings, 2 replies; 125+ messages in thread
From: nbelakovski @ 2018-11-11 23:58 UTC (permalink / raw)
  To: rafa.almas; +Cc: avarab, git, nbelakovski, peff

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom expressing whether the particular ref is checked out in a
linked worktree.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 ref-filter.c                   | 31 +++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh | 15 +++++++++++++++
 2 files changed, 46 insertions(+)

diff --git a/ref-filter.c b/ref-filter.c
index 0c45ed9d94..53e2504f5d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,7 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -114,6 +115,7 @@ static struct used_atom {
 		} objectname;
 		struct refname_atom refname;
 		char *head;
+		struct string_list worktree_heads;
 	} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
@@ -420,6 +422,28 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
 	return 0;
 }
 
+static int worktree_head_atom_parser(const struct ref_format *format,
+									 struct used_atom *atom,
+									 const char *arg,
+									 struct strbuf *unused_err)
+{
+	struct worktree **worktrees = get_worktrees(0);
+	int i;
+
+	string_list_init(&atom->u.worktree_heads, 1);
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref)
+			string_list_append(&atom->u.worktree_heads,
+							   worktrees[i]->head_ref);
+	}
+
+	string_list_sort(&atom->u.worktree_heads);
+
+	free_worktrees(worktrees);
+	return 0;
+}
+
 static struct {
 	const char *name;
 	info_source source;
@@ -461,6 +485,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktree", SOURCE_NONE, FIELD_STR, worktree_head_atom_parser },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1594,6 +1619,12 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 			else
 				v->s = xstrdup(" ");
 			continue;
+		} else if (!strcmp(name, "worktree")) {
+			if (string_list_has_string(&atom->u.worktree_heads, ref->refname))
+				v->s = xstrdup("+");
+			else
+				v->s = xstrdup(" ");
+			continue;
 		} else if (starts_with(name, "align")) {
 			v->handler = align_atom_handler;
 			v->s = xstrdup("");
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..5e6d249d4c 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-\EOF &&
+	master: checked out in a worktree
+	master_worktree: checked out in a worktree
+	side: not checked out in a worktree
+EOF
+    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 &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree
  2018-11-11 23:58             ` [PATCH v2 0/2] refactoring branch colorization to ref-filter nbelakovski
  2018-11-11 23:58               ` [PATCH v2 1/2] ref-filter: add worktree atom nbelakovski
@ 2018-11-11 23:58               ` nbelakovski
  2018-11-12 10:20                 ` Junio C Hamano
  2018-12-16 21:57               ` [PATCH v3 0/3] nbelakovski
  2 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2018-11-11 23:58 UTC (permalink / raw)
  To: rafa.almas; +Cc: avarab, git, nbelakovski, peff

From: Nickolai Belakovski <nbelakovski@gmail.com>

In order to more clearly display which branches are active, the output
of git branch is modified to mark branches checkout out in a linked
worktree with a "+" and color them in a faint light green (in contrast
to the current branch, which will still be denoted with a "*" and
colored in green)

This is meant to simplify workflows related to worktree, particularly
due to the limitations of not being able to check out the same branch in
two worktrees and the inability to delete a branch checked out in a
worktree. When performing branch operations like checkout and delete, it
would be useful to know more readily if the branches in which the user
is interested are already checked out in a worktree.

The git worktree list command contains the relevant information, however
this is a much less frquently used command than git branch.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 builtin/branch.c         | 22 +++++++++++++---------
 color.h                  | 18 ++++++++++++++++++
 t/t3200-branch.sh        |  8 ++++----
 t/t3203-branch-output.sh | 21 +++++++++++++++++++++
 t/test-lib-functions.sh  |  6 ++++++
 5 files changed, 62 insertions(+), 13 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0c55f7f065..34f44c82d7 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -42,11 +42,12 @@ static struct object_id head_oid;
 static int branch_use_color = -1;
 static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_RESET,
-	GIT_COLOR_NORMAL,       /* PLAIN */
-	GIT_COLOR_RED,          /* REMOTE */
-	GIT_COLOR_NORMAL,       /* LOCAL */
-	GIT_COLOR_GREEN,        /* CURRENT */
-	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_NORMAL,             /* PLAIN */
+	GIT_COLOR_RED,                /* REMOTE */
+	GIT_COLOR_NORMAL,             /* LOCAL */
+	GIT_COLOR_GREEN,              /* CURRENT */
+	GIT_COLOR_BLUE,               /* UPSTREAM */
+	GIT_COLOR_FAINT_LIGHT_GREEN,  /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktree)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/color.h b/color.h
index 98894d6a17..857653df73 100644
--- a/color.h
+++ b/color.h
@@ -42,6 +42,24 @@ struct strbuf;
 #define GIT_COLOR_FAINT_BLUE	"\033[2;34m"
 #define GIT_COLOR_FAINT_MAGENTA	"\033[2;35m"
 #define GIT_COLOR_FAINT_CYAN	"\033[2;36m"
+#define GIT_COLOR_LIGHT_RED	"\033[91m"
+#define GIT_COLOR_LIGHT_GREEN	"\033[92m"
+#define GIT_COLOR_LIGHT_YELLOW	"\033[93m"
+#define GIT_COLOR_LIGHT_BLUE	"\033[94m"
+#define GIT_COLOR_LIGHT_MAGENTA	"\033[95m"
+#define GIT_COLOR_LIGHT_CYAN	"\033[96m"
+#define GIT_COLOR_BOLD_LIGHT_RED	"\033[1;91m"
+#define GIT_COLOR_BOLD_LIGHT_GREEN	"\033[1;92m"
+#define GIT_COLOR_BOLD_LIGHT_YELLOW	"\033[1;93m"
+#define GIT_COLOR_BOLD_LIGHT_BLUE	"\033[1;94m"
+#define GIT_COLOR_BOLD_LIGHT_MAGENTA	"\033[1;95m"
+#define GIT_COLOR_BOLD_LIGHT_CYAN	"\033[1;96m"
+#define GIT_COLOR_FAINT_LIGHT_RED	"\033[2;91m"
+#define GIT_COLOR_FAINT_LIGHT_GREEN	"\033[2;92m"
+#define GIT_COLOR_FAINT_LIGHT_YELLOW	"\033[2;93m"
+#define GIT_COLOR_FAINT_LIGHT_BLUE	"\033[2;94m"
+#define GIT_COLOR_FAINT_LIGHT_MAGENTA	"\033[2;95m"
+#define GIT_COLOR_FAINT_LIGHT_CYAN	"\033[2;96m"
 #define GIT_COLOR_BG_RED	"\033[41m"
 #define GIT_COLOR_BG_GREEN	"\033[42m"
 #define GIT_COLOR_BG_YELLOW	"\033[43m"
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..e404f6e23c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '
 test_expect_success 'git branch --column' '
 	COLUMNS=81 git branch --column=column >actual &&
 	cat >expected <<\EOF &&
-  a/b/c     bam       foo       l       * master    n         o/p       r
+  a/b/c   + bam       foo       l       * master    n         o/p       r
   abc       bar       j/k       m/m       master2   o/o       q
 EOF
 	test_cmp expected actual
@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
 	cat >expected <<EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '
 	git config --unset column.branch &&
 	git config --unset column.ui &&
 	cat >expected <<\EOF &&
-  a/b/c   bam   foo   l   * master    n     o/p   r
+  a/b/c + bam   foo   l   * master    n     o/p   r
   abc     bar   j/k   m/m   master2   o/o   q
 EOF
 	test_cmp expected actual
@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
 	cat >expected <<\EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614c..06771fac64 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
++ <FAINT;LGREEN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+	test_terminal git branch >actual.raw &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh
index 78d8c3783b..2831a42a88 100644
--- a/t/test-lib-functions.sh
+++ b/t/test-lib-functions.sh
@@ -61,6 +61,12 @@ test_decode_color () {
 			if (n == 45) return "BMAGENTA";
 			if (n == 46) return "BCYAN";
 			if (n == 47) return "BWHITE";
+			if (n == 91) return "LRED";
+			if (n == 92) return "LGREEN";
+			if (n == 93) return "LYELLOW";
+			if (n == 94) return "LBLUE";
+			if (n == 95) return "LMAGENTA";
+			if (n == 96) return "LCYAN";
 		}
 		{
 			while (match($0, /\033\[[0-9;]*m/) != 0) {
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 1/2] ref-filter: add worktree atom
  2018-11-11 23:58               ` [PATCH v2 1/2] ref-filter: add worktree atom nbelakovski
@ 2018-11-12 10:11                 ` Junio C Hamano
  2018-11-12 12:22                   ` Jeff King
  2018-11-12 12:23                 ` Jeff King
  1 sibling, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2018-11-12 10:11 UTC (permalink / raw)
  To: nbelakovski; +Cc: rafa.almas, avarab, git, peff

nbelakovski@gmail.com writes:

>  
> +static int worktree_head_atom_parser(const struct ref_format *format,
> +									 struct used_atom *atom,
> +									 const char *arg,
> +									 struct strbuf *unused_err)

This and ...

> +{
> +	struct worktree **worktrees = get_worktrees(0);
> +	int i;
> +
> +	string_list_init(&atom->u.worktree_heads, 1);
> +
> +	for (i = 0; worktrees[i]; i++) {
> +		if (worktrees[i]->head_ref)
> +			string_list_append(&atom->u.worktree_heads,
> +							   worktrees[i]->head_ref);

... this makes me suspect that you are using tabstop != 8 and that
is causing you to indent these lines overly deeply.

Please don't, while working on this codebase.


> +	}
> +
> +	string_list_sort(&atom->u.worktree_heads);
> +
> +	free_worktrees(worktrees);
> +	return 0;
> +}

So..., this function collects any and all branches that are checked
out in some worktree, and sort them _without_ dedup.  The user of
the resulting information (i.e. atom->u.worktree_heads) cannot tell
where each of the listed branches is checked out.

I wonder if "The worktree at /local/src/wt1 has this branch checked
out" is something the user of %(worktree) atom, or a variant thereof
e.g. "%(worktree:detailed)", may want to learn, but because that
information is lost when this function returns, such an enhancement
cannot be done without fixing this funciton.

Also, I am not sure if this "list of some info on worktrees" really
belongs to an individual atom.  For one thing, if a format includes
more than one instance of %(worktree) atoms, you'd iterate over the
worktrees as many times as the number of these atoms you have.  Is
there another existing atom that "caches" expensive piece of
information per used_atom[] element like this one?  Essentially I am
trying to convince myself that the approach taken by the patch is a
sane one by finding a precedent.

> +		} else if (!strcmp(name, "worktree")) {
> +			if (string_list_has_string(&atom->u.worktree_heads, ref->refname))

I thought we were moving towards killing the use of string_list as a
look-up table, as we do not want to see thoughtless copy&paste such
a code from parts of the code that are not performance critical to a
part.  Not very satisfying.

	I think we can let this pass, and later add a wrapper around
	hashmap that is meant to only be used to replace string-list
	used for this exact purpose, i.e. key is a string, and there
	is no need to iterate over the existing elements in any
	sorted order.  Optionally, we can limit the look up to only
	checking for existence, if it makes the code for the wrapper
	simpler.

> +				v->s = xstrdup("+");
> +			else
> +				v->s = xstrdup(" ");
> +			continue;
>  		} else if (starts_with(name, "align")) {
>  			v->handler = align_atom_handler;
>  			v->s = xstrdup("");
> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
> index fc067ed672..5e6d249d4c 100755
> --- a/t/t6302-for-each-ref-filter.sh
> +++ b/t/t6302-for-each-ref-filter.sh
> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
>  	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
>  '
>  
> +test_expect_success '"add" a worktree' '
> +	mkdir worktree_dir &&
> +	git worktree add -b master_worktree worktree_dir master
> +'
> +
> +test_expect_success 'validate worktree atom' '
> +	cat >expect <<-\EOF &&
> +	master: checked out in a worktree
> +	master_worktree: checked out in a worktree
> +	side: not checked out in a worktree

As you started the here-doc with <<-, the next line EOF does not
have to be flushed to the left.  Indent it just the same way with a
tab.

> +EOF

The following line begins with a broken indentation, it seems.

> +    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 &&
> +	test_cmp expect actual
> +'
> +
>  test_done

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree
  2018-11-11 23:58               ` [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree nbelakovski
@ 2018-11-12 10:20                 ` Junio C Hamano
  2018-11-12 12:14                   ` Jeff King
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2018-11-12 10:20 UTC (permalink / raw)
  To: nbelakovski; +Cc: rafa.almas, avarab, git, peff

nbelakovski@gmail.com writes:

> diff --git a/color.h b/color.h
> index 98894d6a17..857653df73 100644
> --- a/color.h
> +++ b/color.h
> @@ -42,6 +42,24 @@ struct strbuf;
>  #define GIT_COLOR_FAINT_BLUE	"\033[2;34m"
>  #define GIT_COLOR_FAINT_MAGENTA	"\033[2;35m"
>  #define GIT_COLOR_FAINT_CYAN	"\033[2;36m"
> +#define GIT_COLOR_LIGHT_RED	"\033[91m"
> +#define GIT_COLOR_LIGHT_GREEN	"\033[92m"
> +#define GIT_COLOR_LIGHT_YELLOW	"\033[93m"
> +#define GIT_COLOR_LIGHT_BLUE	"\033[94m"
> +#define GIT_COLOR_LIGHT_MAGENTA	"\033[95m"
> +#define GIT_COLOR_LIGHT_CYAN	"\033[96m"
> +#define GIT_COLOR_BOLD_LIGHT_RED	"\033[1;91m"
> +#define GIT_COLOR_BOLD_LIGHT_GREEN	"\033[1;92m"
> +#define GIT_COLOR_BOLD_LIGHT_YELLOW	"\033[1;93m"
> +#define GIT_COLOR_BOLD_LIGHT_BLUE	"\033[1;94m"
> +#define GIT_COLOR_BOLD_LIGHT_MAGENTA	"\033[1;95m"
> +#define GIT_COLOR_BOLD_LIGHT_CYAN	"\033[1;96m"
> +#define GIT_COLOR_FAINT_LIGHT_RED	"\033[2;91m"
> +#define GIT_COLOR_FAINT_LIGHT_GREEN	"\033[2;92m"
> +#define GIT_COLOR_FAINT_LIGHT_YELLOW	"\033[2;93m"
> +#define GIT_COLOR_FAINT_LIGHT_BLUE	"\033[2;94m"
> +#define GIT_COLOR_FAINT_LIGHT_MAGENTA	"\033[2;95m"
> +#define GIT_COLOR_FAINT_LIGHT_CYAN	"\033[2;96m"

Hopefully you made sure that there is no other topic in-flight that
touch this area before doing this change?  Otherwise you'd be
creating pointless merge conflict by futzing with spaces.

Ditto for an earlier hunk of this patch.

Thanks.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree
  2018-11-12 10:20                 ` Junio C Hamano
@ 2018-11-12 12:14                   ` Jeff King
  2018-11-12 18:07                     ` Rafael Ascensão
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2018-11-12 12:14 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: nbelakovski, rafa.almas, avarab, git

On Mon, Nov 12, 2018 at 07:20:28PM +0900, Junio C Hamano wrote:

> nbelakovski@gmail.com writes:
> 
> > diff --git a/color.h b/color.h
> > index 98894d6a17..857653df73 100644
> > --- a/color.h
> > +++ b/color.h
> > @@ -42,6 +42,24 @@ struct strbuf;
> >  #define GIT_COLOR_FAINT_BLUE	"\033[2;34m"
> >  #define GIT_COLOR_FAINT_MAGENTA	"\033[2;35m"
> >  #define GIT_COLOR_FAINT_CYAN	"\033[2;36m"
> > +#define GIT_COLOR_LIGHT_RED	"\033[91m"
> > +#define GIT_COLOR_LIGHT_GREEN	"\033[92m"
> > +#define GIT_COLOR_LIGHT_YELLOW	"\033[93m"
> > +#define GIT_COLOR_LIGHT_BLUE	"\033[94m"
> > +#define GIT_COLOR_LIGHT_MAGENTA	"\033[95m"
> > +#define GIT_COLOR_LIGHT_CYAN	"\033[96m"
> > +#define GIT_COLOR_BOLD_LIGHT_RED	"\033[1;91m"
> > +#define GIT_COLOR_BOLD_LIGHT_GREEN	"\033[1;92m"
> > +#define GIT_COLOR_BOLD_LIGHT_YELLOW	"\033[1;93m"
> > +#define GIT_COLOR_BOLD_LIGHT_BLUE	"\033[1;94m"
> > +#define GIT_COLOR_BOLD_LIGHT_MAGENTA	"\033[1;95m"
> > +#define GIT_COLOR_BOLD_LIGHT_CYAN	"\033[1;96m"
> > +#define GIT_COLOR_FAINT_LIGHT_RED	"\033[2;91m"
> > +#define GIT_COLOR_FAINT_LIGHT_GREEN	"\033[2;92m"
> > +#define GIT_COLOR_FAINT_LIGHT_YELLOW	"\033[2;93m"
> > +#define GIT_COLOR_FAINT_LIGHT_BLUE	"\033[2;94m"
> > +#define GIT_COLOR_FAINT_LIGHT_MAGENTA	"\033[2;95m"
> > +#define GIT_COLOR_FAINT_LIGHT_CYAN	"\033[2;96m"
> 
> Hopefully you made sure that there is no other topic in-flight that
> touch this area before doing this change?  Otherwise you'd be
> creating pointless merge conflict by futzing with spaces.

This hunk confused me for a minute, too. It's not changing spaces, but
just adding a bunch of color variants. It would be nice if we could just
do this with a run-time parse_color("bold red") or whatever, but we use
these as static initializers.

We don't strictly need anything more than FAINT_LIGHT_GREEN here. I
don't have a strong opinion on adding just what we need versus
being more complete.

> Ditto for an earlier hunk of this patch.

Yeah, I think this does apply to the earlier hunk that defines
branch_colors[].

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 1/2] ref-filter: add worktree atom
  2018-11-12 10:11                 ` Junio C Hamano
@ 2018-11-12 12:22                   ` Jeff King
  2018-11-13  1:38                     ` Junio C Hamano
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2018-11-12 12:22 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: nbelakovski, rafa.almas, avarab, git

On Mon, Nov 12, 2018 at 07:11:23PM +0900, Junio C Hamano wrote:

> > +	}
> > +
> > +	string_list_sort(&atom->u.worktree_heads);
> > +
> > +	free_worktrees(worktrees);
> > +	return 0;
> > +}
> 
> So..., this function collects any and all branches that are checked
> out in some worktree, and sort them _without_ dedup.  The user of
> the resulting information (i.e. atom->u.worktree_heads) cannot tell
> where each of the listed branches is checked out.
> 
> I wonder if "The worktree at /local/src/wt1 has this branch checked
> out" is something the user of %(worktree) atom, or a variant thereof
> e.g. "%(worktree:detailed)", may want to learn, but because that
> information is lost when this function returns, such an enhancement
> cannot be done without fixing this funciton.

Hmm. I think for the purposes of this series we could jump straight to
converting %(worktree) to mean "the path of the worktree for which this
branch is HEAD, or the empty string otherwise".

Then the caller from git-branch (or anybody wanting to emulate it) could
still do:

  %(if)%(worktree)%(then)+ %(refname)%(end)

As a bonus, the decision to use "+" becomes a lot easier. It is no
longer a part of the format language that we must promise forever, but
simply a porcelain decision by git-branch.

> Also, I am not sure if this "list of some info on worktrees" really
> belongs to an individual atom.  For one thing, if a format includes
> more than one instance of %(worktree) atoms, you'd iterate over the
> worktrees as many times as the number of these atoms you have.  Is
> there another existing atom that "caches" expensive piece of
> information per used_atom[] element like this one?  Essentially I am
> trying to convince myself that the approach taken by the patch is a
> sane one by finding a precedent.

Yes, we faced this a bit with Olga's cat-file conversion patches (where
we had a shared struct object_info). There probably should just be a
file-global data-structure storing the worktree info once (in an ideal
world, it would be part of a "struct ref_format" that uses no global
variables, but that is not how the code is structured today).

> > +		} else if (!strcmp(name, "worktree")) {
> > +			if (string_list_has_string(&atom->u.worktree_heads, ref->refname))
> 
> I thought we were moving towards killing the use of string_list as a
> look-up table, as we do not want to see thoughtless copy&paste such
> a code from parts of the code that are not performance critical to a
> part.  Not very satisfying.
> 
> 	I think we can let this pass, and later add a wrapper around
> 	hashmap that is meant to only be used to replace string-list
> 	used for this exact purpose, i.e. key is a string, and there
> 	is no need to iterate over the existing elements in any
> 	sorted order.  Optionally, we can limit the look up to only
> 	checking for existence, if it makes the code for the wrapper
> 	simpler.

This came up over in another thread yesterday, too. So yeah, perhaps we
should move on that (I am OK punting on it for this series and
converting it later, though).

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 1/2] ref-filter: add worktree atom
  2018-11-11 23:58               ` [PATCH v2 1/2] ref-filter: add worktree atom nbelakovski
  2018-11-12 10:11                 ` Junio C Hamano
@ 2018-11-12 12:23                 ` Jeff King
  1 sibling, 0 replies; 125+ messages in thread
From: Jeff King @ 2018-11-12 12:23 UTC (permalink / raw)
  To: nbelakovski; +Cc: rafa.almas, avarab, git

On Sun, Nov 11, 2018 at 03:58:30PM -0800, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> Add an atom expressing whether the particular ref is checked out in a
> linked worktree.
> 
> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
> ---
>  ref-filter.c                   | 31 +++++++++++++++++++++++++++++++
>  t/t6302-for-each-ref-filter.sh | 15 +++++++++++++++
>  2 files changed, 46 insertions(+)

I left some more comments elsewhere in the thread, but one more thing to
note: this probably needs to touch Documentation/git-for-each-ref.txt to
describe the new placeholder.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree
  2018-11-12 12:14                   ` Jeff King
@ 2018-11-12 18:07                     ` Rafael Ascensão
  2018-11-13  1:45                       ` Junio C Hamano
  2018-11-13 14:49                       ` Jeff King
  0 siblings, 2 replies; 125+ messages in thread
From: Rafael Ascensão @ 2018-11-12 18:07 UTC (permalink / raw)
  To: Jeff King; +Cc: Junio C Hamano, nbelakovski, avarab, git

On Mon, Nov 12, 2018 at 07:14:23AM -0500, Jeff King wrote:
> just adding a bunch of color variants. It would be nice if we could just
> do this with a run-time parse_color("bold red") or whatever, but we use
> these as static initializers.

I suggested those colors, but now, I think this needs to be
configurable.

I suggested using green and dim green as the obvious theoretical choice
but after using it for a while I found out that both shades are way too
similar, making it really hard to tell by glancing at the output,
especially when they're not side by side.

If we continue with two dual green approach, current branch needs to be
at least bold. But I'm not sure if it's enough.

I've been trying some other colors, and cyan feels neutral-ish.

I think:

    GIT_COLOR_BOLD_GREEN  /* CURRENT */
    GIT_COLOR_CYAN        /* WORKTREE */

makes an ok combination.

But I can see where personal preference starts to play a role here, as
the logical solution isn't good enough. Which makes the case for being
able to configure a bit stronger.

Cheers,
Rafael Ascensão

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 1/2] ref-filter: add worktree atom
  2018-11-12 12:22                   ` Jeff King
@ 2018-11-13  1:38                     ` Junio C Hamano
  2018-11-21 14:05                       ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2018-11-13  1:38 UTC (permalink / raw)
  To: Jeff King; +Cc: nbelakovski, rafa.almas, avarab, git

Jeff King <peff@peff.net> writes:

>> I wonder if "The worktree at /local/src/wt1 has this branch checked
>> out" is something the user of %(worktree) atom, or a variant thereof
>> e.g. "%(worktree:detailed)", may want to learn, but because that
>> information is lost when this function returns, such an enhancement
>> cannot be done without fixing this funciton.
>
> Hmm. I think for the purposes of this series we could jump straight to
> converting %(worktree) to mean "the path of the worktree for which this
> branch is HEAD, or the empty string otherwise".
>
> Then the caller from git-branch (or anybody wanting to emulate it) could
> still do:
>
>   %(if)%(worktree)%(then)+ %(refname)%(end)
>
> As a bonus, the decision to use "+" becomes a lot easier. It is no
> longer a part of the format language that we must promise forever, but
> simply a porcelain decision by git-branch.

Yeah, thanks for following through the thought process to the
logical conclusion.  If a branch is multply checked out, which is a
condition "git worktree" and "git checkout" ought to prevent from
happening, we could leave the result unspecified but a non-empty
string, or something like that.

> file-global data-structure storing the worktree info once (in an ideal
> world, it would be part of a "struct ref_format" that uses no global
> variables, but that is not how the code is structured today).

Yes, I agree that would be the ideal longer-term direction to move
this code in.

>> > +		} else if (!strcmp(name, "worktree")) {
>> > +			if (string_list_has_string(&atom->u.worktree_heads, ref->refname))
>> 
>> I thought we were moving towards killing the use of string_list as a
>> look-up table, as we do not want to see thoughtless copy&paste such
>> a code from parts of the code that are not performance critical to a
>> part.  Not very satisfying.
>> 
>> 	I think we can let this pass, and later add a wrapper around
>> 	hashmap that is meant to only be used to replace string-list
>> 	used for this exact purpose, i.e. key is a string, and there
>> 	is no need to iterate over the existing elements in any
>> 	sorted order.  Optionally, we can limit the look up to only
>> 	checking for existence, if it makes the code for the wrapper
>> 	simpler.
>
> This came up over in another thread yesterday, too. So yeah, perhaps we
> should move on that (I am OK punting on it for this series and
> converting it later, though).

FWIW, I am OK punting and leaving, too.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree
  2018-11-12 18:07                     ` Rafael Ascensão
@ 2018-11-13  1:45                       ` Junio C Hamano
  2018-11-13 14:49                       ` Jeff King
  1 sibling, 0 replies; 125+ messages in thread
From: Junio C Hamano @ 2018-11-13  1:45 UTC (permalink / raw)
  To: Rafael Ascensão; +Cc: Jeff King, nbelakovski, avarab, git

Rafael Ascensão <rafa.almas@gmail.com> writes:

> But I can see where personal preference starts to play a role here, as
> the logical solution isn't good enough. Which makes the case for being
> able to configure a bit stronger.

Yeah, our preference over time has always been "do not add to our
default color palette to make the default output too colourful;
instead allow the user to specify their choice".  If this feature
can be added like that, that would be preferrable, and if cyan
(which usuallly is used to present "less interesting" piece of
information and in our default palette) works well enough, maybe we
should use that?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree
  2018-11-12 18:07                     ` Rafael Ascensão
  2018-11-13  1:45                       ` Junio C Hamano
@ 2018-11-13 14:49                       ` Jeff King
  2018-11-21 14:07                         ` Nickolai Belakovski
  1 sibling, 1 reply; 125+ messages in thread
From: Jeff King @ 2018-11-13 14:49 UTC (permalink / raw)
  To: Rafael Ascensão; +Cc: Junio C Hamano, nbelakovski, avarab, git

On Mon, Nov 12, 2018 at 06:07:18PM +0000, Rafael Ascensão wrote:

> On Mon, Nov 12, 2018 at 07:14:23AM -0500, Jeff King wrote:
> > just adding a bunch of color variants. It would be nice if we could just
> > do this with a run-time parse_color("bold red") or whatever, but we use
> > these as static initializers.
> 
> I suggested those colors, but now, I think this needs to be
> configurable.

I think they are configurable in that patch, since it provides
"worktree" as a n entry in color_branch_slots. But yeah, every color we
add needs to be configurable, and this is really just about defaults.

> I suggested using green and dim green as the obvious theoretical choice
> but after using it for a while I found out that both shades are way too
> similar, making it really hard to tell by glancing at the output,
> especially when they're not side by side.
> 
> If we continue with two dual green approach, current branch needs to be
> at least bold. But I'm not sure if it's enough.
> 
> I've been trying some other colors, and cyan feels neutral-ish.

Yeah, cyan seems pretty reasonable to me.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 1/2] ref-filter: add worktree atom
  2018-11-13  1:38                     ` Junio C Hamano
@ 2018-11-21 14:05                       ` Nickolai Belakovski
  2018-11-21 14:08                         ` Jeff King
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2018-11-21 14:05 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason, git

I think if we move to making this atom just store worktree path, that
needs to be implemented as a hashmap of refname->wtpath, which would
also solve this string_list issue, correct? Just making sure I'm not
missing something before I submit another patch.
On Tue, Nov 13, 2018 at 2:38 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> Jeff King <peff@peff.net> writes:
>
> >> I wonder if "The worktree at /local/src/wt1 has this branch checked
> >> out" is something the user of %(worktree) atom, or a variant thereof
> >> e.g. "%(worktree:detailed)", may want to learn, but because that
> >> information is lost when this function returns, such an enhancement
> >> cannot be done without fixing this funciton.
> >
> > Hmm. I think for the purposes of this series we could jump straight to
> > converting %(worktree) to mean "the path of the worktree for which this
> > branch is HEAD, or the empty string otherwise".
> >
> > Then the caller from git-branch (or anybody wanting to emulate it) could
> > still do:
> >
> >   %(if)%(worktree)%(then)+ %(refname)%(end)
> >
> > As a bonus, the decision to use "+" becomes a lot easier. It is no
> > longer a part of the format language that we must promise forever, but
> > simply a porcelain decision by git-branch.
>
> Yeah, thanks for following through the thought process to the
> logical conclusion.  If a branch is multply checked out, which is a
> condition "git worktree" and "git checkout" ought to prevent from
> happening, we could leave the result unspecified but a non-empty
> string, or something like that.
>
> > file-global data-structure storing the worktree info once (in an ideal
> > world, it would be part of a "struct ref_format" that uses no global
> > variables, but that is not how the code is structured today).
>
> Yes, I agree that would be the ideal longer-term direction to move
> this code in.
>
> >> > +          } else if (!strcmp(name, "worktree")) {
> >> > +                  if (string_list_has_string(&atom->u.worktree_heads, ref->refname))
> >>
> >> I thought we were moving towards killing the use of string_list as a
> >> look-up table, as we do not want to see thoughtless copy&paste such
> >> a code from parts of the code that are not performance critical to a
> >> part.  Not very satisfying.
> >>
> >>      I think we can let this pass, and later add a wrapper around
> >>      hashmap that is meant to only be used to replace string-list
> >>      used for this exact purpose, i.e. key is a string, and there
> >>      is no need to iterate over the existing elements in any
> >>      sorted order.  Optionally, we can limit the look up to only
> >>      checking for existence, if it makes the code for the wrapper
> >>      simpler.
> >
> > This came up over in another thread yesterday, too. So yeah, perhaps we
> > should move on that (I am OK punting on it for this series and
> > converting it later, though).
>
> FWIW, I am OK punting and leaving, too.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree
  2018-11-13 14:49                       ` Jeff King
@ 2018-11-21 14:07                         ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2018-11-21 14:07 UTC (permalink / raw)
  To: Jeff King
  Cc: Rafael Ascensão, Junio C Hamano,
	Ævar Arnfjörð Bjarmason, git

OK, I see 3 votes for cyan and 4-5 people participating in the thread,
so I'll make it cyan in the next revision.
On Tue, Nov 13, 2018 at 3:49 PM Jeff King <peff@peff.net> wrote:
>
> On Mon, Nov 12, 2018 at 06:07:18PM +0000, Rafael Ascensão wrote:
>
> > On Mon, Nov 12, 2018 at 07:14:23AM -0500, Jeff King wrote:
> > > just adding a bunch of color variants. It would be nice if we could just
> > > do this with a run-time parse_color("bold red") or whatever, but we use
> > > these as static initializers.
> >
> > I suggested those colors, but now, I think this needs to be
> > configurable.
>
> I think they are configurable in that patch, since it provides
> "worktree" as a n entry in color_branch_slots. But yeah, every color we
> add needs to be configurable, and this is really just about defaults.
>
> > I suggested using green and dim green as the obvious theoretical choice
> > but after using it for a while I found out that both shades are way too
> > similar, making it really hard to tell by glancing at the output,
> > especially when they're not side by side.
> >
> > If we continue with two dual green approach, current branch needs to be
> > at least bold. But I'm not sure if it's enough.
> >
> > I've been trying some other colors, and cyan feels neutral-ish.
>
> Yeah, cyan seems pretty reasonable to me.
>
> -Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v2 1/2] ref-filter: add worktree atom
  2018-11-21 14:05                       ` Nickolai Belakovski
@ 2018-11-21 14:08                         ` Jeff King
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2018-11-21 14:08 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Junio C Hamano, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason, git

On Wed, Nov 21, 2018 at 03:05:04PM +0100, Nickolai Belakovski wrote:

> I think if we move to making this atom just store worktree path, that
> needs to be implemented as a hashmap of refname->wtpath, which would
> also solve this string_list issue, correct? Just making sure I'm not
> missing something before I submit another patch.

string_list has a "util" field, so you actually _can_ use it to create
a mapping. I do think a hashmap is a little more obvious.

OTOH, the hashmap API is a little tricky; if we are going to add a
"strmap" API soon, it may be simpler to just use a string_list now and
convert to strmap when it is a available.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v3 0/3]
  2018-11-11 23:58             ` [PATCH v2 0/2] refactoring branch colorization to ref-filter nbelakovski
  2018-11-11 23:58               ` [PATCH v2 1/2] ref-filter: add worktree atom nbelakovski
  2018-11-11 23:58               ` [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree nbelakovski
@ 2018-12-16 21:57               ` nbelakovski
  2018-12-16 21:57                 ` [PATCH v3 1/3] ref-filter: add worktreepath atom nbelakovski
                                   ` (3 more replies)
  2 siblings, 4 replies; 125+ messages in thread
From: nbelakovski @ 2018-12-16 21:57 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Finally got around to submitting latest changes.

I think this addresses all the feedback

The atom now returns the worktree path instead of '+'

I stuck to cyan for the coloring, since it seemed most popular

I added one more change to display the worktree path in cyan for git branch -vvv
Not sure if it's in the best place, but it seemed like it would be nice to add
the path in the same color so that there's some visibility as to why a particular
branch is colored in cyan. If it proves to be controversial, I wouldn't want it to
hold up this series, we can skip it and I can move discussion to a separate thread
(or just forget it, as the case may be)

Travis CI results: https://travis-ci.org/nbelakovski/git/builds/468569102

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: Mark and color a branch differently if it is checked out in a
    linked worktree
  branch: Add an extra verbose output displaying worktree path for refs
    checked out in a linked worktree

 Documentation/git-for-each-ref.txt |  4 +++
 builtin/branch.c                   | 16 ++++++---
 ref-filter.c                       | 70 ++++++++++++++++++++++++++++++++++++++
 t/t3200-branch.sh                  |  8 ++---
 t/t3203-branch-output.sh           | 21 ++++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 6 files changed, 126 insertions(+), 8 deletions(-)

-- 
2.14.2


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v3 1/3] ref-filter: add worktreepath atom
  2018-12-16 21:57               ` [PATCH v3 0/3] nbelakovski
@ 2018-12-16 21:57                 ` nbelakovski
  2018-12-18 17:22                   ` Jeff King
  2018-12-16 21:57                 ` [PATCH v3 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
                                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2018-12-16 21:57 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom proving the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.
---
 Documentation/git-for-each-ref.txt |  4 +++
 ref-filter.c                       | 70 ++++++++++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 3 files changed, 89 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 901faef1bf..9590f7beab 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -209,6 +209,10 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. ' ' otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 5de616befe..e8713484a1 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -34,6 +36,8 @@ static struct ref_msg {
 	"ahead %d, behind %d"
 };
 
+static struct worktree ** worktrees;
+
 void setup_ref_filter_porcelain_msg(void)
 {
 	msgs.gone = _("gone");
@@ -75,6 +79,12 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct reftoworktreeinfo_entry {
+    struct hashmap_entry ent; // must be the first member!
+    char * ref; // key into map
+    struct worktree * wt;
+};
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -114,6 +124,7 @@ static struct used_atom {
 		} objectname;
 		struct refname_atom refname;
 		char *head;
+		struct hashmap reftoworktreeinfo_map;
 	} u;
 } *used_atom;
 static int used_atom_cnt, need_tagged, need_symref;
@@ -420,6 +431,31 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
 	return 0;
 }
 
+static int worktree_atom_parser(const struct ref_format *format,
+				struct used_atom *atom,
+				const char *arg,
+				struct strbuf *unused_err)
+{
+	int i;
+	worktrees = get_worktrees(0);
+
+	hashmap_init(&(atom->u.reftoworktreeinfo_map), NULL, NULL, 0);
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct reftoworktreeinfo_entry *entry;
+			FLEXPTR_ALLOC_STR(entry, ref, worktrees[i]->head_ref);
+			hashmap_entry_init(entry, strhash(entry->ref));
+
+			entry->wt = worktrees[i];
+
+			hashmap_add(&(atom->u.reftoworktreeinfo_map), entry);
+		}
+	}
+
+	return 0;
+}
+
 static struct {
 	const char *name;
 	info_source source;
@@ -461,6 +497,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE, FIELD_STR, worktree_atom_parser },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1500,6 +1537,28 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static const char * get_worktree_info(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct strbuf val = STRBUF_INIT;
+	struct reftoworktreeinfo_entry * entry;
+	struct reftoworktreeinfo_entry * lookup_result;
+
+	FLEXPTR_ALLOC_STR(entry, ref, ref->refname);
+	hashmap_entry_init(entry, strhash(entry->ref));
+	lookup_result = hashmap_get(&(atom->u.reftoworktreeinfo_map), entry, NULL);
+	free(entry);
+
+	if (lookup_result)
+	{
+		if (!strncmp(atom->name, "worktreepath", strlen(atom->name)))
+			strbuf_addstr(&val, lookup_result->wt->path);
+	}
+	else
+		strbuf_addstr(&val, " ");
+
+	return strbuf_detach(&val, NULL);
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1537,6 +1596,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (starts_with(name, "worktreepath")) {
+			v->s = get_worktree_info(atom, ref);
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2013,7 +2076,14 @@ void ref_array_clear(struct ref_array *array)
 	int i;
 
 	for (i = 0; i < used_atom_cnt; i++)
+	{
+		if (!strncmp(used_atom[i].name, "worktreepath", strlen("worktreepath")))
+		{
+			hashmap_free(&(used_atom[i].u.reftoworktreeinfo_map), 1);
+			free_worktrees(worktrees);
+		}
 		free((char *)used_atom[i].name);
+	}
 	FREE_AND_NULL(used_atom);
 	used_atom_cnt = 0;
 	for (i = 0; i < array->nr; i++)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..add70a4c3e 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-\EOF &&
+	master: checked out in a worktree
+	master_worktree: checked out in a worktree
+	side: not checked out in a worktree
+	EOF
+	git 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 &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v3 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2018-12-16 21:57               ` [PATCH v3 0/3] nbelakovski
  2018-12-16 21:57                 ` [PATCH v3 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2018-12-16 21:57                 ` nbelakovski
  2018-12-16 21:57                 ` [PATCH v3 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
  2018-12-18 17:25                 ` [PATCH v3 0/3] Jeff King
  3 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2018-12-16 21:57 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

In order to more clearly display which branches are active, the output
of git branch is modified to mark branches checkout out in a linked
worktree with a "+" and color them in cyan (in contrast to the current
branch, which will still be denoted with a "*" and colored in green)

This is meant to simplify workflows related to worktree, particularly
due to the limitations of not being able to check out the same branch in
two worktrees and the inability to delete a branch checked out in a
worktree. When performing branch operations like checkout and delete, it
would be useful to know more readily if the branches in which the user
is interested are already checked out in a worktree.

The git worktree list command contains the relevant information, however
this is a much less frquently used command than git branch.
---
 builtin/branch.c         | 12 ++++++++----
 t/t3200-branch.sh        |  8 ++++----
 t/t3203-branch-output.sh | 21 +++++++++++++++++++++
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0c55f7f065..2a24153b78 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..e404f6e23c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '
 test_expect_success 'git branch --column' '
 	COLUMNS=81 git branch --column=column >actual &&
 	cat >expected <<\EOF &&
-  a/b/c     bam       foo       l       * master    n         o/p       r
+  a/b/c   + bam       foo       l       * master    n         o/p       r
   abc       bar       j/k       m/m       master2   o/o       q
 EOF
 	test_cmp expected actual
@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
 	cat >expected <<EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '
 	git config --unset column.branch &&
 	git config --unset column.ui &&
 	cat >expected <<\EOF &&
-  a/b/c   bam   foo   l   * master    n     o/p   r
+  a/b/c + bam   foo   l   * master    n     o/p   r
   abc     bar   j/k   m/m   master2   o/o   q
 EOF
 	test_cmp expected actual
@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
 	cat >expected <<\EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614c..94ab05ad59 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
++ <CYAN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+	test_terminal git branch >actual.raw &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v3 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2018-12-16 21:57               ` [PATCH v3 0/3] nbelakovski
  2018-12-16 21:57                 ` [PATCH v3 1/3] ref-filter: add worktreepath atom nbelakovski
  2018-12-16 21:57                 ` [PATCH v3 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
@ 2018-12-16 21:57                 ` nbelakovski
  2018-12-18 17:25                 ` [PATCH v3 0/3] Jeff King
  3 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2018-12-16 21:57 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

---
 builtin/branch.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/builtin/branch.c b/builtin/branch.c
index 2a24153b78..56589a3684 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));
 		strbuf_addf(&local, " %s ", obname.buf);
 
+		if (filter->verbose > 2)
+			strbuf_addf(&local, "%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
+
 		if (filter->verbose > 1)
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v3 1/3] ref-filter: add worktreepath atom
  2018-12-16 21:57                 ` [PATCH v3 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2018-12-18 17:22                   ` Jeff King
  2018-12-20  7:09                     ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2018-12-18 17:22 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Sun, Dec 16, 2018 at 01:57:57PM -0800, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> Add an atom proving the path of the linked worktree where this ref is
> checked out, if it is checked out in any linked worktrees, and empty
> string otherwise.

I stumbled over the word "proving" here. Maybe "showing" would be more
clear?

> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
> index 901faef1bf..9590f7beab 100644
> --- a/Documentation/git-for-each-ref.txt
> +++ b/Documentation/git-for-each-ref.txt
> @@ -209,6 +209,10 @@ symref::
>  	`:lstrip` and `:rstrip` options in the same way as `refname`
>  	above.
>  
> +worktreepath::
> +	The absolute path to the worktree in which the ref is checked
> +	out, if it is checked out in any linked worktree. ' ' otherwise.
> +

Normally single-quotes are used in asciidoc to emphasize text, and the
quotes aren't passed through. Asciidoc (and asciidoctor) do seem to
render the literal quotes here, which is good. I wonder if it would be
more clear to just write it out, though, like:

  ...any linked worktree. Otherwise, replaced with a single space.

Also, why are we replacing it with a single space? Wouldn't the empty
string be more customary (and work with the other "if empty, then do
this" formatting options)?

> @@ -34,6 +36,8 @@ static struct ref_msg {
>  	"ahead %d, behind %d"
>  };
>  
> +static struct worktree ** worktrees;

Minor style nit: we put the "*" in a pointer declaration next to the
variable name, without intervening whitespace. Like:

  static struct worktree **worktrees;

> @@ -75,6 +79,12 @@ static struct expand_data {
>  	struct object_info info;
>  } oi, oi_deref;
>  
> +struct reftoworktreeinfo_entry {
> +    struct hashmap_entry ent; // must be the first member!
> +    char * ref; // key into map
> +    struct worktree * wt;
> +};

A few style nits:

  - the "*" space thing from above (it's in other places below, too, but
    I won't point out each)

  - we prefer "/* */" comments, even for single-liners

  - since we do all-lowercase identifiers, use more underscores to break
    things up. E.g., ref_to_worktree_entry.

Here we store the refname as a separate variable, but then point to the
worktree itself to access wt->path. Why do we treat these differently?
I.e., I'd expect to see either:

  1. Each entry holding a single worktree object, and using its head_ref
     and path fields, like:

       struct ref_to_worktree_entry {
               struct hashmap_entry ent; /* must be first */
	       struct worktree *wt;
       };
       ....
       entry = xmalloc(sizeof(*entry));
       entry->wt = wt;
       hashmap_entry_init(entry, strhash(wt->head_ref));
       ...
       strbuf_addstr(&out, result->wt->path);


  2. Each entry containing just the bits it needs, like:

       struct ref_to_worktree_entry {
               struct hashmap_entry ent; /* must be first */
	       char *ref;
	       char *path;
       };
       ...
       /*
        * We could use FLEXPTR_ALLOC_STR() here, but it doesn't actually
	* support holding _two_ strings. Separate allocations probably
	* aren't a huge deal here, since there are only a handful of
	* worktrees.
	*/
       entry = xmalloc(sizeof(*entry));
       entry->ref = wt->head_ref;
       entry->path = wt->path;
       hashmap_entry_init(entry, strhash(entry->ref));
       ...
       strbuf_addstr(&out, result->path);


I think the first one is strictly preferable unless we're worried about
the lifetime of the "struct worktree" going away. I don't think that's
an issue, though; they are ours until we call free_worktrees().

> @@ -114,6 +124,7 @@ static struct used_atom {
>  		} objectname;
>  		struct refname_atom refname;
>  		char *head;
> +		struct hashmap reftoworktreeinfo_map;
>  	} u;
>  } *used_atom;

This uses one map for each %(worktree) we use. But won't they all be the
same? It would ideally be associated with the ref-filter.  There's no
ref-filter context struct to hold this kind of data, just static globals
in ref-filter.c (including this used_atom struct!). That's something
we'll probably need to fix in the long run, but I think it would be
reasonable to just have:

  static struct hashmap ref_to_worktree_map;

next to the declaration of used_atom_cnt, need_symref, etc. And then
those can all eventually get moved into a struct together.

> @@ -461,6 +497,7 @@ static struct {
>  	{ "flag", SOURCE_NONE },
>  	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
>  	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
> +	{ "worktreepath", SOURCE_NONE, FIELD_STR, worktree_atom_parser },
>  	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
>  	{ "end", SOURCE_NONE },
>  	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },

Marking as SOURCE_NONE makes sense.

> +static const char * get_worktree_info(const struct used_atom *atom, const struct ref_array_item *ref)
> +{
> +	struct strbuf val = STRBUF_INIT;
> +	struct reftoworktreeinfo_entry * entry;
> +	struct reftoworktreeinfo_entry * lookup_result;
> +
> +	FLEXPTR_ALLOC_STR(entry, ref, ref->refname);
> +	hashmap_entry_init(entry, strhash(entry->ref));
> +	lookup_result = hashmap_get(&(atom->u.reftoworktreeinfo_map), entry, NULL);
> +	free(entry);

We shouldn't need to do an allocation just for a lookup. That's what the
extra "keydata" parameter is for in the comparison function. And I guess
this is what led you to have "char *ref" in the struct, rather than
reusing wt->head_ref (because you don't have a "struct worktree" here).

You should be able to do it like this:

  struct hashmap_entry entry;
  struct ref_to_worktree_entry *result;

  hashmap_entry_init(entry, strhash(ref->refname));
  result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname));
  ...

and then your comparison function would look like this:

  int ref_to_worktree_hashcmp(const void *data,
                              const void *entry,
			      const void *entry_or_key,
			      const void *keydata)
  {
          const struct ref_to_worktree_entry *a = entry;
          const struct ref_to_worktree_entry *b = entry;
	  if (keydata)
	          return strcmp(a->wt->head_ref, keydata);
	  else
	          return strcmp(a->wt->head_ref, b->wt->head_ref);
  }

If you're thinking that this API is totally confusing and hard to figure
out, I agree. It's optimized to avoid extra allocations. I wish we had a
better one for simple cases (especially string->string mappings like
this).

Speaking of comparison functions, I didn't see one in your patch. Don't
you need to pass one to hashmap_init?

> +	if (lookup_result)
> +	{
> +		if (!strncmp(atom->name, "worktreepath", strlen(atom->name)))
> +			strbuf_addstr(&val, lookup_result->wt->path);
> +	}
> +	else
> +		strbuf_addstr(&val, " ");

What's this extra strncmp about? If we're _not_ a worktreepath atom,
we'd still do the lookup only to put nothing in the string?

I think we'd only call this function when populate_value() sees a
worktreepath atom, though:

> @@ -1537,6 +1596,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
>  
>  		if (starts_with(name, "refname"))
>  			refname = get_refname(atom, ref);
> +		else if (starts_with(name, "worktreepath")) {
> +			v->s = get_worktree_info(atom, ref);
> +			continue;
> +		}

So it would be OK to drop the check of atom->name again inside
get_worktree_info().

> @@ -2013,7 +2076,14 @@ void ref_array_clear(struct ref_array *array)
>  	int i;
>  
>  	for (i = 0; i < used_atom_cnt; i++)
> +	{
> +		if (!strncmp(used_atom[i].name, "worktreepath", strlen("worktreepath")))
> +		{
> +			hashmap_free(&(used_atom[i].u.reftoworktreeinfo_map), 1);
> +			free_worktrees(worktrees);
> +		}

And if we move the mapping out to a static global, then this only has to
be done once, not once per atom. In fact, I think this could double-free
"worktrees" with your current patch if you have two "%(worktree)"
placeholders, since "worktrees" already is a global.

> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
> index fc067ed672..add70a4c3e 100755
> --- a/t/t6302-for-each-ref-filter.sh
> +++ b/t/t6302-for-each-ref-filter.sh
> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
>  	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
>  '
>  
> +test_expect_success '"add" a worktree' '
> +	mkdir worktree_dir &&
> +	git worktree add -b master_worktree worktree_dir master
> +'
> +
> +test_expect_success 'validate worktree atom' '
> +	cat >expect <<-\EOF &&
> +	master: checked out in a worktree
> +	master_worktree: checked out in a worktree
> +	side: not checked out in a worktree
> +	EOF
> +	git 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 &&
> +	test_cmp expect actual
> +'

It's probably worth testing that the path we get is actually sane, too.
I.e., expect something more like:

   cat >expect <<-\EOF
   master: $PWD
   master: $PWD/worktree
   side: not checked out
   EOF
   git for-each-ref \
     --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked %out%(end)

(I wish there was a way to avoid that really long line, but I don't
think there is).

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v3 0/3]
  2018-12-16 21:57               ` [PATCH v3 0/3] nbelakovski
                                   ` (2 preceding siblings ...)
  2018-12-16 21:57                 ` [PATCH v3 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
@ 2018-12-18 17:25                 ` Jeff King
  3 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2018-12-18 17:25 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Sun, Dec 16, 2018 at 01:57:56PM -0800, nbelakovski@gmail.com wrote:

> Finally got around to submitting latest changes.
> 
> I think this addresses all the feedback
> 
> The atom now returns the worktree path instead of '+'

Thanks, I think patch 1 is definitely going in the right direction.
There are a few issues I found in its implementation, but they should be
easy to fix (and won't affect the other patches).

I don't really have a strong opinion on the behavior of the other
patches.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v3 1/3] ref-filter: add worktreepath atom
  2018-12-18 17:22                   ` Jeff King
@ 2018-12-20  7:09                     ` Nickolai Belakovski
  2018-12-20 14:59                       ` Jeff King
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2018-12-20  7:09 UTC (permalink / raw)
  To: Jeff King
  Cc: git, Rafael Ascensão, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Tue, Dec 18, 2018 at 9:22 AM Jeff King <peff@peff.net> wrote:
>
> On Sun, Dec 16, 2018 at 01:57:57PM -0800, nbelakovski@gmail.com wrote:
>
> > From: Nickolai Belakovski <nbelakovski@gmail.com>
> >
> > Add an atom proving the path of the linked worktree where this ref is
> > checked out, if it is checked out in any linked worktrees, and empty
> > string otherwise.
>
> I stumbled over the word "proving" here. Maybe "showing" would be more
> clear?

Oops, providing

> > +worktreepath::
> > +     The absolute path to the worktree in which the ref is checked
> > +     out, if it is checked out in any linked worktree. ' ' otherwise.
> > +
>
> Also, why are we replacing it with a single space? Wouldn't the empty
> string be more customary (and work with the other "if empty, then do
> this" formatting options)?

I was just following what was done for HEAD, but overall I agree that
empty is preferable to single space, will change.

> Minor style nit: we put the "*" in a pointer declaration next to the
> variable name, without intervening whitespace. Like:
>
>   static struct worktree **worktrees;

Gotcha, will do, thanks for pointing it out.


To sum up the hashmap comments:
-I hadn't thought to re-use the head_ref of worktree as the key.
That's clever. I like the readability of having separate entries for
key and value, but I can see the benefit of not having to do an extra
allocation. I can make up for the readability hit with a comment.
-Actually, for any valid use case there will only be one instance of
the map since the entries of used_atom are cached, but regardless it
makes sense to keep per-atom info in used_atom and global context
somewhere else, so I'll make that change to make it a static variable
outside of used_atom.
-Will change the lookup logic to remove the extra allocation. Since
I'm letting the hashmap use its internal comparison function on the
hash, I don't need to provide a comparison function.

> What's this extra strncmp about? If we're _not_ a worktreepath atom,
> we'd still do the lookup only to put nothing in the string?

Leftover from an earlier iteration where I was going to support
getting more info out of the worktree struct. I decided to limit scope
to just the info I really needed for the branch change. I left it like
this because I thought it would make the code more readable for
someone who wanted to come in and add that extra info, but I think
you're right that it ends up just reading kind of awkwardly.

>
> > @@ -2013,7 +2076,14 @@ void ref_array_clear(struct ref_array *array)
> >       int i;
> >
> >       for (i = 0; i < used_atom_cnt; i++)
> > +     {
> > +             if (!strncmp(used_atom[i].name, "worktreepath", strlen("worktreepath")))
> > +             {
> > +                     hashmap_free(&(used_atom[i].u.reftoworktreeinfo_map), 1);
> > +                     free_worktrees(worktrees);
> > +             }
>
> And if we move the mapping out to a static global, then this only has to
> be done once, not once per atom. In fact, I think this could double-free
> "worktrees" with your current patch if you have two "%(worktree)"
> placeholders, since "worktrees" already is a global.

Only if someone put a colon on one of the %(worktree) atoms, otherwise
they're all cached, but as you say moot point anyway if the map is
moved outside the used_atom structure.

>
> It's probably worth testing that the path we get is actually sane, too.
> I.e., expect something more like:
>
>    cat >expect <<-\EOF
>    master: $PWD
>    master: $PWD/worktree
>    side: not checked out
>    EOF
>    git for-each-ref \
>      --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked %out%(end)
>
> (I wish there was a way to avoid that really long line, but I don't
> think there is).
>

Yea good call, can do.

Thanks for all the feedback, will try to turn these around quickly.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v3 1/3] ref-filter: add worktreepath atom
  2018-12-20  7:09                     ` Nickolai Belakovski
@ 2018-12-20 14:59                       ` Jeff King
  2018-12-24  8:47                         ` [PATCH v4 0/3] nbelakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2018-12-20 14:59 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: git, Rafael Ascensão, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Wed, Dec 19, 2018 at 11:09:59PM -0800, Nickolai Belakovski wrote:

> > Also, why are we replacing it with a single space? Wouldn't the empty
> > string be more customary (and work with the other "if empty, then do
> > this" formatting options)?
> 
> I was just following what was done for HEAD, but overall I agree that
> empty is preferable to single space, will change.

Ah, right, that makes more sense. I do still think for %(HEAD) it's a
little different because it is "+" or a single space, so always one
character.  Here we have some value or not, and in the "not" case for
such things we usually give an empty string (e.g., for %(push),
%(upstream), etc).

> To sum up the hashmap comments:
> -I hadn't thought to re-use the head_ref of worktree as the key.
> That's clever. I like the readability of having separate entries for
> key and value, but I can see the benefit of not having to do an extra
> allocation. I can make up for the readability hit with a comment.

Thanks, that makes sense.

> -Actually, for any valid use case there will only be one instance of
> the map since the entries of used_atom are cached, but regardless it
> makes sense to keep per-atom info in used_atom and global context
> somewhere else, so I'll make that change to make it a static variable
> outside of used_atom.

Ah, right, I forgot there was some magic around used_atom. I do still
agree that the separate static global makes things a little simpler.

> -Will change the lookup logic to remove the extra allocation. Since
> I'm letting the hashmap use its internal comparison function on the
> hash, I don't need to provide a comparison function.

I don't think that works. The default function is always_equal(), which
will treat two entries equal if they have the same hash value. I.e., any
collisions would be considered a match.

> Thanks for all the feedback, will try to turn these around quickly.

Great, thanks! I'll be on vacation for the next two weeks, so I may be
very slow to look at the next iteration. :)

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v4 0/3]
  2018-12-20 14:59                       ` Jeff King
@ 2018-12-24  8:47                         ` nbelakovski
  2018-12-24  8:47                           ` [PATCH v4 1/3] ref-filter: add worktreepath atom nbelakovski
                                             ` (3 more replies)
  0 siblings, 4 replies; 125+ messages in thread
From: nbelakovski @ 2018-12-24  8:47 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

> I don't think that works. The default function is always_equal(), which
> will treat two entries equal if they have the same hash value. I.e., any
> collisions would be considered a match.

You're absolutely right. I've added a compare function, but I left out the
functionality for it to work with an entry passed in as a key. Doing so would
mean the user would have to allocate a worktree struct, which just seems silly
when the ref is all that's needed (and also defeats the purpose of avoiding
extra allocations).

And while most of the hashmap API seems OK, yea, this is definitely awful. It
feels like it should just be able to take a key and return either an entry or
NULL, and do away with entry_or_key and equals_function_data.

Travis-CI results: https://travis-ci.org/nbelakovski/git/builds/471787317

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: Mark and color a branch differently if it is checked out in a
    linked worktree
  branch: Add an extra verbose output displaying worktree path for refs
    checked out in a linked worktree

 Documentation/git-for-each-ref.txt |  5 +++
 builtin/branch.c                   | 16 ++++++---
 ref-filter.c                       | 72 +++++++++++++++++++++++++++++++++++++-
 t/t3200-branch.sh                  |  8 ++---
 t/t3203-branch-output.sh           | 21 +++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 6 files changed, 128 insertions(+), 9 deletions(-)

-- 
2.14.2

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v4 1/3] ref-filter: add worktreepath atom
  2018-12-24  8:47                         ` [PATCH v4 0/3] nbelakovski
@ 2018-12-24  8:47                           ` nbelakovski
  2019-01-03  5:40                             ` Jeff King
  2018-12-24  8:47                           ` [PATCH v4 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
                                             ` (2 subsequent siblings)
  3 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2018-12-24  8:47 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom providing the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.
---
 Documentation/git-for-each-ref.txt |  5 +++
 ref-filter.c                       | 72 +++++++++++++++++++++++++++++++++++++-
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 3 files changed, 91 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 901faef1bf..caba1c23b8 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -209,6 +209,11 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 5de616befe..240e7b80f8 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -34,6 +36,8 @@ static struct ref_msg {
 	"ahead %d, behind %d"
 };
 
+static struct worktree **worktrees;
+
 void setup_ref_filter_porcelain_msg(void)
 {
 	msgs.gone = _("gone");
@@ -75,6 +79,11 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct ref_to_worktree_entry {
+    struct hashmap_entry ent; /* must be the first member! */
+    struct worktree *wt; /* key is wt->head_ref */
+};
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -116,7 +125,8 @@ static struct used_atom {
 		char *head;
 	} u;
 } *used_atom;
-static int used_atom_cnt, need_tagged, need_symref;
+static int used_atom_cnt, need_tagged, need_symref, has_worktree;
+static struct hashmap ref_to_worktree_map;
 
 /*
  * Expand string, append it to strbuf *sb, then return error code ret.
@@ -420,6 +430,42 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
 	return 0;
 }
 
+static int worktree_hashmap_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,
+				   const void *unused_key, const void *keydata_aka_refname)
+{
+	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+	return strcmp(e->wt->head_ref, keydata_aka_refname);
+}
+
+static int worktree_atom_parser(const struct ref_format *format,
+				struct used_atom *atom,
+				const char *arg,
+				struct strbuf *unused_err)
+{
+	int i;
+	if (has_worktree)
+		return 0;
+
+	worktrees = get_worktrees(0);
+
+	hashmap_init(&ref_to_worktree_map, worktree_hashmap_cmpfnc, NULL, 0);
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct ref_to_worktree_entry *entry;
+			entry = xmalloc(sizeof(*entry));
+			entry->wt = worktrees[i];
+			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+			hashmap_add(&ref_to_worktree_map, entry);
+		}
+	}
+
+	has_worktree = 1;
+
+	return 0;
+}
+
 static struct {
 	const char *name;
 	info_source source;
@@ -461,6 +507,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE, FIELD_STR, worktree_atom_parser },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1500,6 +1547,20 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static const char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct strbuf val = STRBUF_INIT;
+	struct hashmap_entry entry;
+	struct ref_to_worktree_entry *lookup_result;
+
+	hashmap_entry_init(&entry, strhash(ref->refname));
+	lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);
+
+	strbuf_addstr(&val, lookup_result ? lookup_result->wt->path : "");
+
+	return strbuf_detach(&val, NULL);
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1537,6 +1598,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (starts_with(name, "worktreepath")) {
+			v->s = get_worktree_path(atom, ref);
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2020,6 +2085,11 @@ void ref_array_clear(struct ref_array *array)
 		free_array_item(array->items[i]);
 	FREE_AND_NULL(array->items);
 	array->nr = array->alloc = 0;
+	if (has_worktree)
+	{
+		hashmap_free(&ref_to_worktree_map, 1);
+		free_worktrees(worktrees);
+	}
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..d70517a6ae 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+test_expect_success 'validate worktree atom' '
+	{
+	echo master: $PWD &&
+	echo master_worktree: $PWD/worktree_dir &&
+	echo side: not checked out
+	} > expect &&
+	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v4 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2018-12-24  8:47                         ` [PATCH v4 0/3] nbelakovski
  2018-12-24  8:47                           ` [PATCH v4 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2018-12-24  8:47                           ` nbelakovski
  2018-12-24  8:47                           ` [PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
  2019-01-03  5:22                           ` [PATCH v4 0/3] Jeff King
  3 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2018-12-24  8:47 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

In order to more clearly display which branches are active, the output
of git branch is modified to mark branches checkout out in a linked
worktree with a "+" and color them in cyan (in contrast to the current
branch, which will still be denoted with a "*" and colored in green)

This is meant to simplify workflows related to worktree, particularly
due to the limitations of not being able to check out the same branch in
two worktrees and the inability to delete a branch checked out in a
worktree. When performing branch operations like checkout and delete, it
would be useful to know more readily if the branches in which the user
is interested are already checked out in a worktree.

The git worktree list command contains the relevant information, however
this is a much less frquently used command than git branch.
---
 builtin/branch.c         | 12 ++++++++----
 t/t3200-branch.sh        |  8 ++++----
 t/t3203-branch-output.sh | 21 +++++++++++++++++++++
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/builtin/branch.c b/builtin/branch.c
index 0c55f7f065..2a24153b78 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..e404f6e23c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '
 test_expect_success 'git branch --column' '
 	COLUMNS=81 git branch --column=column >actual &&
 	cat >expected <<\EOF &&
-  a/b/c     bam       foo       l       * master    n         o/p       r
+  a/b/c   + bam       foo       l       * master    n         o/p       r
   abc       bar       j/k       m/m       master2   o/o       q
 EOF
 	test_cmp expected actual
@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
 	cat >expected <<EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '
 	git config --unset column.branch &&
 	git config --unset column.ui &&
 	cat >expected <<\EOF &&
-  a/b/c   bam   foo   l   * master    n     o/p   r
+  a/b/c + bam   foo   l   * master    n     o/p   r
   abc     bar   j/k   m/m   master2   o/o   q
 EOF
 	test_cmp expected actual
@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
 	cat >expected <<\EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614c..94ab05ad59 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
++ <CYAN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+	test_terminal git branch >actual.raw &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2018-12-24  8:47                         ` [PATCH v4 0/3] nbelakovski
  2018-12-24  8:47                           ` [PATCH v4 1/3] ref-filter: add worktreepath atom nbelakovski
  2018-12-24  8:47                           ` [PATCH v4 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
@ 2018-12-24  8:47                           ` nbelakovski
  2019-01-03  5:42                             ` Jeff King
  2019-01-03  5:22                           ` [PATCH v4 0/3] Jeff King
  3 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2018-12-24  8:47 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

---
 builtin/branch.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/builtin/branch.c b/builtin/branch.c
index 2a24153b78..56589a3684 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));
 		strbuf_addf(&local, " %s ", obname.buf);
 
+		if (filter->verbose > 2)
+			strbuf_addf(&local, "%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
+
 		if (filter->verbose > 1)
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v4 0/3]
  2018-12-24  8:47                         ` [PATCH v4 0/3] nbelakovski
                                             ` (2 preceding siblings ...)
  2018-12-24  8:47                           ` [PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
@ 2019-01-03  5:22                           ` Jeff King
  3 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2019-01-03  5:22 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Mon, Dec 24, 2018 at 12:47:53AM -0800, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> > I don't think that works. The default function is always_equal(), which
> > will treat two entries equal if they have the same hash value. I.e., any
> > collisions would be considered a match.
> 
> You're absolutely right. I've added a compare function, but I left out the
> functionality for it to work with an entry passed in as a key. Doing so would
> mean the user would have to allocate a worktree struct, which just seems silly
> when the ref is all that's needed (and also defeats the purpose of avoiding
> extra allocations).

Unfortunately, that doesn't quite work. :)

Your compare function has to handle _both_ cases: two keys, or one key
and a keydata.

The former may be called when the hashmap has to compare two entries
internally (e.g., when it has to re-bucket all of the entries after a
resize). Your tests likely wouldn't run into this case in practice,
since you'd only have a handful of worktrees. But if you added, say,
thousands of worktrees and we had to grow the hash midway through the
process, it would segfault.  So you do need to handle the case when your
keydata is NULL.

In theory it would also be used for comparisons if we used a more clever
data structure to hold entries within a bucket. But since we just use a
linked list and linear search for now, we don't.

> And while most of the hashmap API seems OK, yea, this is definitely awful. It
> feels like it should just be able to take a key and return either an entry or
> NULL, and do away with entry_or_key and equals_function_data.

In your case, yeah, equals_function_data is not used at all (but there
are a few call-sites which need it to avoid relying on global data).

But the entry_or_key (coupled with keydata) is the magic that lets the
same function be used for both lookups as well as internal entry
comparisons.

I think having two separate comparison functions would make this a lot
more clear, though likely at the cost of having more boilerplate.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v4 1/3] ref-filter: add worktreepath atom
  2018-12-24  8:47                           ` [PATCH v4 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-01-03  5:40                             ` Jeff King
  2019-01-03  9:31                               ` Eric Sunshine
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2019-01-03  5:40 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Mon, Dec 24, 2018 at 12:47:54AM -0800, nbelakovski@gmail.com wrote:

> [...]

Thanks for keeping with this.  I think we're getting quite close, though
I did find a few small-ish issues.

> @@ -34,6 +36,8 @@ static struct ref_msg {
>  	"ahead %d, behind %d"
>  };
>  
> +static struct worktree **worktrees;
> +

Maybe define this near "struct hashmap ref_to_worktree_map" so it's
more obvious that the two are related?

> @@ -75,6 +79,11 @@ static struct expand_data {
>  	struct object_info info;
>  } oi, oi_deref;
>  
> +struct ref_to_worktree_entry {
> +    struct hashmap_entry ent; /* must be the first member! */
> +    struct worktree *wt; /* key is wt->head_ref */
> +};

Indent with spaces?

> -static int used_atom_cnt, need_tagged, need_symref;
> +static int used_atom_cnt, need_tagged, need_symref, has_worktree;
> +static struct hashmap ref_to_worktree_map;

Makes sense. I thought at first has_worktree was a flag that we might
care about between parsing and formatting, but it's really just a flag
to say "we lazy-loaded the worktree list".

> +static int worktree_hashmap_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,
> +				   const void *unused_key, const void *keydata_aka_refname)
> +{
> +	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
> +	return strcmp(e->wt->head_ref, keydata_aka_refname);
> +}

So from the discussion in the cover letter, this needs to be more like:

  static int worktree_hashmap_cmpfnc(const void *unused_lookupdata,
                                     const void *ve1, const void *ve2,
				     const void *keydata_aka_refname)
  {
	const struct ref_to_worktree_entry *e1 = ve1, *e2 = ve2;
	return strcmp(e1->wt->head_ref, keydata_aka_refname ?
		                        keydata_aka_refname :
					e2->wt->head_ref);
  }

> +static int worktree_atom_parser(const struct ref_format *format,
> +				struct used_atom *atom,
> +				const char *arg,
> +				struct strbuf *unused_err)
> +{
> +	int i;
> +	if (has_worktree)
> +		return 0;

Minor style nit, but please put a space between the declarations and the
start of the code (not strictly necessary for a short function which has
no other linebreaks, like the cmpfunc above, but here I think it's
confusing not to).

> +	worktrees = get_worktrees(0);
> +
> +	hashmap_init(&ref_to_worktree_map, worktree_hashmap_cmpfnc, NULL, 0);
> +
> +	for (i = 0; worktrees[i]; i++) {
> +		if (worktrees[i]->head_ref) {
> +			struct ref_to_worktree_entry *entry;
> +			entry = xmalloc(sizeof(*entry));
> +			entry->wt = worktrees[i];
> +			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
> +
> +			hashmap_add(&ref_to_worktree_map, entry);
> +		}
> +	}

Makes sense to load the map.

> +static const char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
> +{
> +	struct strbuf val = STRBUF_INIT;
> +	struct hashmap_entry entry;
> +	struct ref_to_worktree_entry *lookup_result;
> +
> +	hashmap_entry_init(&entry, strhash(ref->refname));
> +	lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);
> +
> +	strbuf_addstr(&val, lookup_result ? lookup_result->wt->path : "");
> +
> +	return strbuf_detach(&val, NULL);
> +}

And that makes sense to look up an item in it. Good.

Adding an empty string to a strbuf is a noop, so that part might more
clearly be written as just:

  if (lookup_result)
	strbuf_addstr(&val, lookup_result->wt->path);

We return a "const char *" here, but the result is always allocated. Do
we leak the result? Or should this return a "char *"?

I think there are a lot of other atoms that leak currently, but that is
being fixed in another topic that is currently in pu.

> @@ -2020,6 +2085,11 @@ void ref_array_clear(struct ref_array *array)
>  		free_array_item(array->items[i]);
>  	FREE_AND_NULL(array->items);
>  	array->nr = array->alloc = 0;
> +	if (has_worktree)
> +	{
> +		hashmap_free(&ref_to_worktree_map, 1);
> +		free_worktrees(worktrees);
> +	}

Here we free everything, but we don't unset has_worktree. So anybody
trying to format more refs afterward would see our freed worktree list.

We probably want:

  has_worktree = 0;

here. Or simpler still, I think get_worktrees() will always return a
non-NULL list (even if it is empty). So you could just drop has_worktree
entirely, and use:

  if (worktrees)
	return; /* already loaded */;

in the loading function, and:

  free_worktrees(worktrees);
  worktrees = NULL;

here.

> +test_expect_success '"add" a worktree' '
> +	mkdir worktree_dir &&
> +	git worktree add -b master_worktree worktree_dir master
> +'
> +
> +test_expect_success 'validate worktree atom' '
> +	{
> +	echo master: $PWD &&
> +	echo master_worktree: $PWD/worktree_dir &&
> +	echo side: not checked out
> +	} > expect &&

Minor style nit: use "} >expect" without the extra space.

This checks the actual directories. Good. I can never remember the rules
for when to use $PWD versus $(pwd) on Windows. We may run afoul of the
distinction here.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2018-12-24  8:47                           ` [PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
@ 2019-01-03  5:42                             ` Jeff King
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2019-01-03  5:42 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Mon, Dec 24, 2018 at 12:47:56AM -0800, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> ---
>  builtin/branch.c | 4 ++++
>  1 file changed, 4 insertions(+)

This patch should describe the new behavior in Documentation/git-branch.txt,
I'd think.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v4 1/3] ref-filter: add worktreepath atom
  2019-01-03  5:40                             ` Jeff King
@ 2019-01-03  9:31                               ` Eric Sunshine
  0 siblings, 0 replies; 125+ messages in thread
From: Eric Sunshine @ 2019-01-03  9:31 UTC (permalink / raw)
  To: Jeff King
  Cc: Nickolai Belakovski, Git List, Rafael Ascensao, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Thu, Jan 3, 2019 at 12:40 AM Jeff King <peff@peff.net> wrote:
> On Mon, Dec 24, 2018 at 12:47:54AM -0800, nbelakovski@gmail.com wrote:
> > +test_expect_success 'validate worktree atom' '
> > +     {
> > +     echo master: $PWD &&
> > +     echo master_worktree: $PWD/worktree_dir &&
> > +     echo side: not checked out
> > +     } > expect &&
>
> Minor style nit: use "} >expect" without the extra space.

An interpolating here-doc would be even more natural:

    cat >expect <-EOF &&
    master: $(pwd)
    master_worktree: $(pwd)/worktree_dir
    side: not checked out
    EOF

> This checks the actual directories. Good. I can never remember the rules
> for when to use $PWD versus $(pwd) on Windows. We may run afoul of the
> distinction here.

As I understand it, this is exactly a case in which you would need to
use $(pwd); namely, when coming up with an "expect" value. t/README
talks about it.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v5 0/3]
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (2 preceding siblings ...)
  2018-09-27 18:17   ` Jeff King
@ 2019-01-06  0:26   ` nbelakovski
  2019-01-06  0:26     ` [PATCH v5 1/3] ref-filter: add worktreepath atom nbelakovski
                       ` (2 more replies)
  2019-01-22 23:22   ` [PATCH v6 0/3] nbelakovski
                     ` (7 subsequent siblings)
  11 siblings, 3 replies; 125+ messages in thread
From: nbelakovski @ 2019-01-06  0:26 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Replying to my original email to try to clean up the email chain

> Thanks for keeping with this.  I think we're getting quite close

Thanks to you as well for continuing to review the change set and provide feedback!
It does feel rather close, I'm getting exciting about following it through, even if
we just end up merging the worktreepath commit and not the ones to modify the branch
output, since I can always just make a local alias that uses the worktreepath atom.

The last set of changes all made sense, very non-controversial, so I've simply implemented
them. Beyond that, I moved where the structures for the ref<->worktree map are defined now
that they're no longer associated with used_atom. They still feel a little awkwardly
placed to me; I couldn't quite find a way I liked of arranging them together while also
sticking to the style in the rest of the code but I think it's a little better that
all of the relevant structs and the cmpfnc are all in the same place.

Travis-CI results: https://travis-ci.org/nbelakovski/git/builds/475825245

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: Mark and color a branch differently if it is checked out in a
    linked worktree
  branch: Add an extra verbose output displaying worktree path for refs
    checked out in a linked worktree

 Documentation/git-branch.txt       | 20 ++++++-----
 Documentation/git-for-each-ref.txt |  5 +++
 builtin/branch.c                   | 16 ++++++---
 ref-filter.c                       | 71 ++++++++++++++++++++++++++++++++++++++
 t/t3200-branch.sh                  |  8 ++---
 t/t3203-branch-output.sh           | 21 +++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 7 files changed, 140 insertions(+), 16 deletions(-)

-- 
2.14.2


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v5 1/3] ref-filter: add worktreepath atom
  2019-01-06  0:26   ` [PATCH v5 0/3] nbelakovski
@ 2019-01-06  0:26     ` nbelakovski
  2019-01-07 18:20       ` Junio C Hamano
  2019-01-06  0:26     ` [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
  2019-01-06  0:26     ` [PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
  2 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-01-06  0:26 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom providing the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.
---
 Documentation/git-for-each-ref.txt |  5 +++
 ref-filter.c                       | 71 ++++++++++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 3 files changed, 91 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 901faef1bf..caba1c23b8 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -209,6 +209,11 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 5de616befe..e7ca45f39b 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -75,6 +77,22 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct ref_to_worktree_entry {
+	struct hashmap_entry ent; /* must be the first member! */
+	struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,
+				   const void *key, const void *keydata_aka_refname)
+{
+	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+	const struct ref_to_worktree_entry *k = key;
+	return strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct hashmap ref_to_worktree_map;
+static struct worktree **worktrees = NULL;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -420,6 +438,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
 	return 0;
 }
 
+static int worktree_atom_parser(const struct ref_format *format,
+				struct used_atom *atom,
+				const char *arg,
+				struct strbuf *unused_err)
+{
+	int i;
+
+	if (worktrees)
+		return 0;
+
+	worktrees = get_worktrees(0);
+
+	hashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct ref_to_worktree_entry *entry;
+			entry = xmalloc(sizeof(*entry));
+			entry->wt = worktrees[i];
+			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+			hashmap_add(&ref_to_worktree_map, entry);
+		}
+	}
+
+	return 0;
+}
+
 static struct {
 	const char *name;
 	info_source source;
@@ -461,6 +507,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE, FIELD_STR, worktree_atom_parser },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1500,6 +1547,21 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct strbuf val = STRBUF_INIT;
+	struct hashmap_entry entry;
+	struct ref_to_worktree_entry *lookup_result;
+
+	hashmap_entry_init(&entry, strhash(ref->refname));
+	lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);
+
+	if (lookup_result)
+		strbuf_addstr(&val, lookup_result->wt->path);
+
+	return strbuf_detach(&val, NULL);
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1537,6 +1599,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (starts_with(name, "worktreepath")) {
+			v->s = get_worktree_path(atom, ref);
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2020,6 +2086,11 @@ void ref_array_clear(struct ref_array *array)
 		free_array_item(array->items[i]);
 	FREE_AND_NULL(array->items);
 	array->nr = array->alloc = 0;
+	if (worktrees)
+	{
+		hashmap_free(&ref_to_worktree_map, 1);
+		free_worktrees(worktrees);
+	}
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..87e0222ea1 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-EOF &&
+	master: $(pwd)
+	master_worktree: $(pwd)/worktree_dir
+	side: not checked out
+	EOF
+	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-01-06  0:26   ` [PATCH v5 0/3] nbelakovski
  2019-01-06  0:26     ` [PATCH v5 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-01-06  0:26     ` nbelakovski
  2019-01-07 19:04       ` Junio C Hamano
  2019-01-06  0:26     ` [PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
  2 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-01-06  0:26 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

In order to more clearly display which branches are active, the output
of git branch is modified to mark branches checkout out in a linked
worktree with a "+" and color them in cyan (in contrast to the current
branch, which will still be denoted with a "*" and colored in green)

This is meant to simplify workflows related to worktree, particularly
due to the limitations of not being able to check out the same branch in
two worktrees and the inability to delete a branch checked out in a
worktree. When performing branch operations like checkout and delete, it
would be useful to know more readily if the branches in which the user
is interested are already checked out in a worktree.

The git worktree list command contains the relevant information, however
this is a much less frquently used command than git branch.
---
 Documentation/git-branch.txt | 15 ++++++++-------
 builtin/branch.c             | 12 ++++++++----
 t/t3200-branch.sh            |  8 ++++----
 t/t3203-branch-output.sh     | 21 +++++++++++++++++++++
 4 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index bf5316ffa9..b3eca6ffdc 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -26,13 +26,14 @@ DESCRIPTION
 -----------
 
 If `--list` is given, or if there are no non-option arguments, existing
-branches are listed; the current branch will be highlighted with an
-asterisk.  Option `-r` causes the remote-tracking branches to be listed,
-and option `-a` shows both local and remote branches. If a `<pattern>`
-is given, it is used as a shell wildcard to restrict the output to
-matching branches. If multiple patterns are given, a branch is shown if
-it matches any of the patterns.  Note that when providing a
-`<pattern>`, you must use `--list`; otherwise the command is interpreted
+branches are listed; the current branch will be highlighted in green and
+marked with an asterisk.  Any branches checked out in linked worktrees will
+be highlighted in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed, and option `-a` shows both local and
+remote branches. If a `<pattern>` is given, it is used as a shell wildcard to
+restrict the output to matching branches. If multiple patterns are given, a
+branch is shown if it matches any of the patterns.  Note that when providing
+a `<pattern>`, you must use `--list`; otherwise the command is interpreted
 as branch creation.
 
 With `--contains`, shows only the branches that contain the named commit
diff --git a/builtin/branch.c b/builtin/branch.c
index 0c55f7f065..2a24153b78 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..e404f6e23c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '
 test_expect_success 'git branch --column' '
 	COLUMNS=81 git branch --column=column >actual &&
 	cat >expected <<\EOF &&
-  a/b/c     bam       foo       l       * master    n         o/p       r
+  a/b/c   + bam       foo       l       * master    n         o/p       r
   abc       bar       j/k       m/m       master2   o/o       q
 EOF
 	test_cmp expected actual
@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
 	cat >expected <<EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '
 	git config --unset column.branch &&
 	git config --unset column.ui &&
 	cat >expected <<\EOF &&
-  a/b/c   bam   foo   l   * master    n     o/p   r
+  a/b/c + bam   foo   l   * master    n     o/p   r
   abc     bar   j/k   m/m   master2   o/o   q
 EOF
 	test_cmp expected actual
@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
 	cat >expected <<\EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614c..94ab05ad59 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
++ <CYAN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+	test_terminal git branch >actual.raw &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2019-01-06  0:26   ` [PATCH v5 0/3] nbelakovski
  2019-01-06  0:26     ` [PATCH v5 1/3] ref-filter: add worktreepath atom nbelakovski
  2019-01-06  0:26     ` [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
@ 2019-01-06  0:26     ` nbelakovski
  2019-01-07 19:09       ` Junio C Hamano
  2 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-01-06  0:26 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

---
 Documentation/git-branch.txt | 5 ++++-
 builtin/branch.c             | 4 ++++
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index b3eca6ffdc..6d1fc59e32 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -163,12 +163,15 @@ This option is only applicable in non-verbose mode.
 
 -v::
 -vv::
+-vvv::
 --verbose::
 	When in list mode,
 	show sha1 and commit subject line for each head, along with
 	relationship to upstream branch (if any). If given twice, print
 	the name of the upstream branch, as well (see also `git remote
-	show <remote>`).
+	show <remote>`). If given 3 times, print the path of the linked
+	worktree, if applicable (not applicable for main worktree since
+	its path will be a subset of $PWD)
 
 -q::
 --quiet::
diff --git a/builtin/branch.c b/builtin/branch.c
index 2a24153b78..56589a3684 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));
 		strbuf_addf(&local, " %s ", obname.buf);
 
+		if (filter->verbose > 2)
+			strbuf_addf(&local, "%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
+
 		if (filter->verbose > 1)
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 1/3] ref-filter: add worktreepath atom
  2019-01-06  0:26     ` [PATCH v5 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-01-07 18:20       ` Junio C Hamano
  2019-01-18 22:17         ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-07 18:20 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

> +static struct hashmap ref_to_worktree_map;
> +static struct worktree **worktrees = NULL;
> +
>  /*
>   * An atom is a valid field atom listed below, possibly prefixed with
>   * a "*" to denote deref_tag().
> @@ -420,6 +438,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
>  	return 0;
>  }
>  
> +static int worktree_atom_parser(const struct ref_format *format,
> +				struct used_atom *atom,
> +				const char *arg,
> +				struct strbuf *unused_err)
> +{
> +	int i;
> +
> +	if (worktrees)
> +		return 0;

OK, so verify_ref_format() etc. will trigger this to be called via
valid_atom[].parser when "%(worktreepath)" is seen in the user
format, and then this grabs all the worktrees and record their paths
in the hashmap.  This if() statement makes sure that it happens only
once.

> +	worktrees = get_worktrees(0);
> +
> +	hashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);
> +
> +	for (i = 0; worktrees[i]; i++) {
> +		if (worktrees[i]->head_ref) {
> +			struct ref_to_worktree_entry *entry;
> +			entry = xmalloc(sizeof(*entry));
> +			entry->wt = worktrees[i];
> +			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
> +
> +			hashmap_add(&ref_to_worktree_map, entry);
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static struct {
>  	const char *name;
>  	info_source source;
> @@ -461,6 +507,7 @@ static struct {
>  	{ "flag", SOURCE_NONE },
>  	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
>  	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
> +	{ "worktreepath", SOURCE_NONE, FIELD_STR, worktree_atom_parser },
>  	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
>  	{ "end", SOURCE_NONE },
>  	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
> @@ -1500,6 +1547,21 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
>  	return 0;
>  }
>  
> +static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
> +{
> +	struct strbuf val = STRBUF_INIT;
> +	struct hashmap_entry entry;
> +	struct ref_to_worktree_entry *lookup_result;

And then this will be called from populate_value() for each of the
ref.  It looks up the worktree that has checked out this branch, if
any, from the hashmap, and yields the path to it.

When seeing a tag or note ref, by definition that's not something we
can have checked out in any worktree.  I wonder if it is worth to
optimize further by omitting this lookup when ref is not a local
branch?

IOW, with a typical number of worktrees and refs, how costly would ...

> +	hashmap_entry_init(&entry, strhash(ref->refname));
> +	lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);

... this sequence of calls be.

> +
> +	if (lookup_result)
> +		strbuf_addstr(&val, lookup_result->wt->path);
> +
> +	return strbuf_detach(&val, NULL);
> +}
> +
>  /*
>   * Parse the object referred by ref, and grab needed value.
>   */
> @@ -1537,6 +1599,10 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
>  
>  		if (starts_with(name, "refname"))
>  			refname = get_refname(atom, ref);
> +		else if (starts_with(name, "worktreepath")) {
> +			v->s = get_worktree_path(atom, ref);
> +			continue;
> +		}
>  		else if (starts_with(name, "symref"))
>  			refname = get_symref(atom, ref);
>  		else if (starts_with(name, "upstream")) {
> @@ -2020,6 +2086,11 @@ void ref_array_clear(struct ref_array *array)
>  		free_array_item(array->items[i]);
>  	FREE_AND_NULL(array->items);
>  	array->nr = array->alloc = 0;
> +	if (worktrees)
> +	{

Have this opening brace at the end of the previous line, i.e.

	if (worktrees) {

> +		hashmap_free(&ref_to_worktree_map, 1);
> +		free_worktrees(worktrees);
> +	}
>  }

What's the point of ref_array_clear()?  What does the caller of this
function really want?  Is it merely to release the resources
consumed?  If so, then this is good enough, but then the existing
calls to FREE_AND_NULL() for releasing resources in the function is
overkill.

Or is it envisioned that we are preparing a clean slate so that
another call, possibly after the external environment changed, can
be made into this machinery (i.e. imagine we lift ref-filter.c code
and link it to a long running service process; after serving one
for-each-ref request, a new worktree or a new branch may get
created, and then we may get another for-each-ref request)?  If that
is the case, then the added code breaks that hope, as it leaves a
dangling pointer in the worktrees variable.

>  static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
> index fc067ed672..87e0222ea1 100755
> --- a/t/t6302-for-each-ref-filter.sh
> +++ b/t/t6302-for-each-ref-filter.sh
> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
>  	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
>  '
>  
> +test_expect_success '"add" a worktree' '
> +	mkdir worktree_dir &&
> +	git worktree add -b master_worktree worktree_dir master
> +'
> +
> +test_expect_success 'validate worktree atom' '
> +	cat >expect <<-EOF &&
> +	master: $(pwd)
> +	master_worktree: $(pwd)/worktree_dir
> +	side: not checked out
> +	EOF
> +	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
> +	test_cmp expect actual
> +'
> +
>  test_done

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-01-06  0:26     ` [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
@ 2019-01-07 19:04       ` Junio C Hamano
  2019-01-10 21:42         ` Philip Oakley
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-07 19:04 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
>
> In order to more clearly display which branches are active, the output
> of git branch is modified to mark branches checkout out in a linked
> worktree with a "+" and color them in cyan (in contrast to the current
> branch, which will still be denoted with a "*" and colored in green)
>
> This is meant to simplify workflows related to worktree, particularly
> due to the limitations of not being able to check out the same branch in
> two worktrees and the inability to delete a branch checked out in a
> worktree. When performing branch operations like checkout and delete, it
> would be useful to know more readily if the branches in which the user
> is interested are already checked out in a worktree.

I do not think it is warranted to paint the safety features as
"limitations".

A branch that is checked out in another worktree cannot be checked
out to be worked on, as that will make the checkout of the other
worktree out of sync.  If you want to work on that branch, you can
either (1) go to that worktree that has a checkout of that branch
and work there, or (2) go to that worktree that has a checkout of
that branch, check out a different branch there, come back to the
worktree you want to work in and check out that branch.  Knowing
where that other worktree is is the first step in either case.

And a branch that is checked out in a worktree cannot be removed, as
it is a sign that it is still being worked on for a branch to have
been checked out somewhere.  If you do want to remove that branch,
you need to go to that worktree that has a checkout of that branch,
check out a different branch there, and then remove it.  Again,
knowing where that other worktree is is the fist thing you need to
know.

But then I am not sure if the feature being added by these patches
is a good match for that justification.

For one thing, it would be more direct and helpful way for

	git checkout one-branch
	git branch -d one-branch

to say "The branch `one-branch` is checked out in a worktree at
$DIRECTORY" when they refused to go ahead.  And that would eliminate
the need for this new feature to help these two use cases.

In fact, these two command already behave that way, so the paragraph
I just commented on is not a good justification for this new feature
at all.

Besides, showing "That branch is checked out somewhere" would not
help user to decide "ah, if I want to work on that branch, I need to
chdir to that directory" with the patch in question, as it only
shows "It is checked out _somewhere_" without saying where.

> The git worktree list command contains the relevant information, however
> this is a much less frquently used command than git branch.

It is not a good justification.  If the "relevant information" given
by the command is necessary one, the user can run that command.  If
the situation where that "relevant information" becomes necessary is
rare, the command is run much less frequently is not a problem---it
is expected.  And overloading a more frequently used command with
information that is less frequently wanted is actually not a great
design.

A more relevant justification may be that even though the
information can already be found in "worktree list" output, it would
give us flexibility in presentation to allow the custom format in
for-each-ref to show it.

So, I am between moderately Meh to fairly negative on this step; Meh
in the sense that "thanks to the previous step, we _could_ do this,
it does not give incorrect information, and it makes the output more
cheerful, but it does not add that much useful and actionable piece
of information".

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2019-01-06  0:26     ` [PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
@ 2019-01-07 19:09       ` Junio C Hamano
  0 siblings, 0 replies; 125+ messages in thread
From: Junio C Hamano @ 2019-01-07 19:09 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
>
> ---

All three patches lack sign off.

I am fairly negative on 2/3, but I think this one makes sense
without introducing a new verbosity level.  We do not promise
stability of Porcelain command output and update the UI if we
have useful information to give.  Just making

	git branch --list -v -v

show additional information should be sufficient.

> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
> index b3eca6ffdc..6d1fc59e32 100644
> --- a/Documentation/git-branch.txt
> +++ b/Documentation/git-branch.txt
> @@ -163,12 +163,15 @@ This option is only applicable in non-verbose mode.
>  
>  -v::
>  -vv::
> +-vvv::
>  --verbose::
>  	When in list mode,
>  	show sha1 and commit subject line for each head, along with
>  	relationship to upstream branch (if any). If given twice, print
>  	the name of the upstream branch, as well (see also `git remote
> -	show <remote>`).
> +	show <remote>`). If given 3 times, print the path of the linked
> +	worktree, if applicable (not applicable for main worktree since
> +	its path will be a subset of $PWD)
>  
>  -q::
>  --quiet::
> diff --git a/builtin/branch.c b/builtin/branch.c
> index 2a24153b78..56589a3684 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -366,6 +366,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
>  		strbuf_addstr(&local, branch_get_color(BRANCH_COLOR_RESET));
>  		strbuf_addf(&local, " %s ", obname.buf);
>  
> +		if (filter->verbose > 2)
> +			strbuf_addf(&local, "%s%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)%%(worktreepath) %%(end)%%(end)%s",
> +				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
> +
>  		if (filter->verbose > 1)
>  			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
>  				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-01-07 19:04       ` Junio C Hamano
@ 2019-01-10 21:42         ` Philip Oakley
  2019-01-13  1:41           ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Philip Oakley @ 2019-01-10 21:42 UTC (permalink / raw)
  To: Junio C Hamano, nbelakovski; +Cc: git, peff, rafa.almas, avarab

On 07/01/2019 19:04, Junio C Hamano wrote:
> nbelakovski@gmail.com writes:
>
>> From: Nickolai Belakovski <nbelakovski@gmail.com>
>>
>> In order to more clearly display which branches are active, the output
>> of git branch is modified to mark branches checkout out in a linked
>> worktree with a "+" and color them in cyan (in contrast to the current
>> branch, which will still be denoted with a "*" and colored in green)
>>
>> This is meant to simplify workflows related to worktree, particularly
>> due to the limitations of not being able to check out the same branch in
>> two worktrees and the inability to delete a branch checked out in a
>> worktree. When performing branch operations like checkout and delete, it
>> would be useful to know more readily if the branches in which the user
>> is interested are already checked out in a worktree.
> I do not think it is warranted to paint the safety features as
> "limitations".

Is this not just a case of needing to clarify that this is 'safety' 
related to the _users_ mental model (or lack of) relative to the limited 
information that was previously given by the branch command's list.

You are right that there is no data safety issue, but users make 
mistakes when they misunderstand the situation.

>
> A branch that is checked out in another worktree cannot be checked
> out to be worked on, as that will make the checkout of the other
> worktree out of sync.  If you want to work on that branch, you can
> either (1) go to that worktree that has a checkout of that branch
> and work there, or (2) go to that worktree that has a checkout of
> that branch, check out a different branch there, come back to the
> worktree you want to work in and check out that branch.  Knowing
> where that other worktree is is the first step in either case.
>
> And a branch that is checked out in a worktree cannot be removed, as
> it is a sign that it is still being worked on for a branch to have
> been checked out somewhere.

I'm not sure that all users will recognise the signs, which I think is 
one reason for the value of the patch.


>    If you do want to remove that branch,
> you need to go to that worktree that has a checkout of that branch,
> check out a different branch there, and then remove it.  Again,
> knowing where that other worktree is is the fist thing you need to
> know.
>
> But then I am not sure if the feature being added by these patches
> is a good match for that justification.
I'd agree that the justification needs clarified.
>
> For one thing, it would be more direct and helpful way for
>
> 	git checkout one-branch
> 	git branch -d one-branch
>
> to say "The branch `one-branch` is checked out in a worktree at
> $DIRECTORY" when they refused to go ahead.  And that would eliminate
> the need for this new feature to help these two use cases.
>
> In fact, these two command already behave that way, so the paragraph
> I just commented on is not a good justification for this new feature
> at all.
>
> Besides, showing "That branch is checked out somewhere" would not
> help user to decide "ah, if I want to work on that branch, I need to
> chdir to that directory" with the patch in question, as it only
> shows "It is checked out _somewhere_" without saying where.
>
>> The git worktree list command contains the relevant information, however
>> this is a much less frquently used command than git branch.
> It is not a good justification.  If the "relevant information" given
> by the command is necessary one, the user can run that command.  If
> the situation where that "relevant information" becomes necessary is
> rare, the command is run much less frequently is not a problem---it
> is expected.  And overloading a more frequently used command with
> information that is less frequently wanted is actually not a great
> design.
But leaving the older command unaware of the newer developments and the 
user unwise as to its missing info is equally a poor situation.
>
> A more relevant justification may be that even though the
> information can already be found in "worktree list" output, it would
> give us flexibility in presentation to allow the custom format in
> for-each-ref to show it.
>
> So, I am between moderately Meh to fairly negative on this step; Meh
> in the sense that "thanks to the previous step, we _could_ do this,
> it does not give incorrect information, and it makes the output more
> cheerful, but it does not add that much useful and actionable piece
> of information".

The patch did appear to me as being a proper update to the branch 
command to include the information about the branches in the other worktrees

Philip


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-01-10 21:42         ` Philip Oakley
@ 2019-01-13  1:41           ` Nickolai Belakovski
  2019-01-14 18:18             ` Junio C Hamano
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-01-13  1:41 UTC (permalink / raw)
  To: Philip Oakley
  Cc: Junio C Hamano, git, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Thu, Jan 10, 2019 at 1:43 PM Philip Oakley <philipoakley@iee.org> wrote:
>
> On 07/01/2019 19:04, Junio C Hamano wrote:
> > I do not think it is warranted to paint the safety features as
> > "limitations".
>
> Is this not just a case of needing to clarify that this is 'safety'
> related to the _users_ mental model (or lack of) relative to the limited
> information that was previously given by the branch command's list.
>
> You are right that there is no data safety issue, but users make
> mistakes when they misunderstand the situation.

Not trying to paint anything one way or another. I found that these
features got in the way of my workflows and didn't see any immediate
reason why they had to exist. Thinking about it a bit more, is it
unreasonable to delete a branch even if it's checked out in a worktree
as long as the user uses git branch --delete --force or -D? This would
leave the worktree in a detached head state, but all the data would be
untouched. The output of deletion could mention that the branch had
been checked out in a worktree so that the user is fully informed.

Checking out the same branch in two worktrees should be technically
possible to implement safely, but I don't see a use case for having
the same branch checked out in multiple worktrees anyway. Why use
multiple worktrees at that point? If a user really wants the same
contents in two directories they can work around this
limitation/safety feature by just making another branch pointing at
the same commit. But anyway I'm just explaining why I chose the word
'limitation'.


> >    If you do want to remove that branch,
> > you need to go to that worktree that has a checkout of that branch,
> > check out a different branch there, and then remove it.  Again,
> > knowing where that other worktree is is the fist thing you need to
> > know.

This just seems silly to me when git branch --delete has a --force
option. But that's off topic.

> >
> >> The git worktree list command contains the relevant information, however
> >> this is a much less frquently used command than git branch.
> > It is not a good justification.  If the "relevant information" given
> > by the command is necessary one, the user can run that command.  If
> > the situation where that "relevant information" becomes necessary is
> > rare, the command is run much less frequently is not a problem---it
> > is expected.  And overloading a more frequently used command with
> > information that is less frequently wanted is actually not a great
> > design.
> But leaving the older command unaware of the newer developments and the
> user unwise as to its missing info is equally a poor situation.
> >
> > A more relevant justification may be that even though the
> > information can already be found in "worktree list" output, it would
> > give us flexibility in presentation to allow the custom format in
> > for-each-ref to show it.
> >
> > So, I am between moderately Meh to fairly negative on this step; Meh
> > in the sense that "thanks to the previous step, we _could_ do this,
> > it does not give incorrect information, and it makes the output more
> > cheerful, but it does not add that much useful and actionable piece
> > of information".

Allow me to add some color to my original commit message. The point of
this patch is so that the user is not surprised when they see the
message that this branch is checked out in another worktree when
trying to delete it or check it out, since they have presumably run
git branch recently and seen the formatted output indicating that a
branch they may want to delete/checkout is checked out in a worktree.
This was my frustration that prompted me to dive into this in the
first place - I'm cleaning up my branches and all of a sudden git
decides it doesn't want to let me delete one because it's checked out
somewhere else, even though I know I don't care about it because I
know the branch has already been merged upstream, or is old, or
whatever. I thought, if git branch output could at least let me know
that it's going to treat some branches differently, I can be proactive
about things and go to my worktree and delete the branch, or skip
trying to clean it up or not check it out.

I'll pursue the above-mentioned topic of allowing git branch -D to
allow the user to delete branches checked out in a worktree
separately, but even if that goes through, I think this patch would
still be useful in that it tells me that I can't check out the
branches that are colored in cyan.

Does that make more sense?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-01-13  1:41           ` Nickolai Belakovski
@ 2019-01-14 18:18             ` Junio C Hamano
  2019-01-18 22:18               ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-14 18:18 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Philip Oakley, git, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

Nickolai Belakovski <nbelakovski@gmail.com> writes:

> Not trying to paint anything one way or another. I found that these
> features got in the way of my workflows and didn't see any immediate
> reason why they had to exist. Thinking about it a bit more, is it
> unreasonable to delete a branch even if it's checked out in a worktree
> as long as the user uses git branch --delete --force or -D?

[For ease of discussion, let's assume that our worktree has a
checkout of branch B, and you are mucking with that branch in
another worktree connected to the same repository]

It is probably a sane enhancement to allow but require --force to
delete branch B in the other worktree.  It is a different matter to
allow "git branch -m AnotherBranch B" run in the other worktree to
overwrite branch B--it will be a disaster if we allowed it and then
committed what we have in our worktree.

> This would
> leave the worktree in a detached head state,

It does not.  It will leave us on branch B that is unborn, and the
next commit will start that branch with a root commit.

> but all the data would be
> untouched. 

As far as the person, who is working in our worktree, is concerned,
she wanted to extend the history of branch B before you deleted it
in another worktree.  But because you deleted B while she was
looking the other way, she ended up creating a root commit, losing
all the history behind that branch.  I'd grant you that "--force"
will give us an excuse when she complains, though.

Most likely, you and she are the same person, but one big point in
the ability to work in multiple worktrees is to allow the user to
switch context and multi-task.  When she gives branch B its own
worktree, she does so because she wants to have a stable place to
work on it, without getting affected by other things she does to the
repository in other worktrees.


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 1/3] ref-filter: add worktreepath atom
  2019-01-07 18:20       ` Junio C Hamano
@ 2019-01-18 22:17         ` Nickolai Belakovski
  2019-01-18 22:20           ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-01-18 22:17 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Mon, Jan 7, 2019 at 10:20 AM Junio C Hamano <gitster@pobox.com> wrote:
> When seeing a tag or note ref, by definition that's not something we
> can have checked out in any worktree.  I wonder if it is worth to
> optimize further by omitting this lookup when ref is not a local
> branch?
>
> IOW, with a typical number of worktrees and refs, how costly would ...
>
> > +     hashmap_entry_init(&entry, strhash(ref->refname));
> > +     lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);
>
> ... this sequence of calls be.
>

It certainly wouldn't be free. Every check would compute the hash of
the refname and do a lookup into the hash table. If the bucket it
looked up was empty that'd be it, but if it were non-empty a few more
comparisons would happen.

I think avoiding this would be check, we can simply check ref->kind ==
FILTER_REFS_BRANCHES ahead of calling into get_worktree_path and
provide an empty string otherwise.

> >               free_array_item(array->items[i]);
> >       FREE_AND_NULL(array->items);
> >       array->nr = array->alloc = 0;
> > +     if (worktrees)
> > +     {
>
>
> What's the point of ref_array_clear()?  ...  If that
> is the case, then the added code breaks that hope, as it leaves a
> dangling pointer in the worktrees variable.
>

Discussion of the point of ref_array_clear would be out of scope of
this change, but your point is well taken that setting worktrees to
NULL would be consistent with the rest of the function. Will
implement.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-01-14 18:18             ` Junio C Hamano
@ 2019-01-18 22:18               ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-01-18 22:18 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Philip Oakley, git, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

I will start a separate thread containing these replies for the
potential change to allow deleting branches checked out in worktrees.

Getting back on track for this series, specifically this 2/3 patch,
how do you feel about it? As I pointed out the goal is to communicate
to the user that the branches marked/colored will behave differently
from the other branches if the user tries to delete them or check them
out.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v5 1/3] ref-filter: add worktreepath atom
  2019-01-18 22:17         ` Nickolai Belakovski
@ 2019-01-18 22:20           ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-01-18 22:20 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Fri, Jan 18, 2019 at 2:17 PM Nickolai Belakovski
<nbelakovski@gmail.com> wrote:
>
>
> I think avoiding this would be check, we can simply check ref->kind ==
> FILTER_REFS_BRANCHES ahead of calling into get_worktree_path and
> provide an empty string otherwise.
>

*would be check -> would be cheap

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v6 0/3]
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (3 preceding siblings ...)
  2019-01-06  0:26   ` [PATCH v5 0/3] nbelakovski
@ 2019-01-22 23:22   ` nbelakovski
  2019-01-22 23:22     ` [PATCH v6 1/3] ref-filter: add worktreepath atom nbelakovski
                       ` (2 more replies)
  2019-02-01 22:04   ` [PATCH v7 0/3] nbelakovski
                     ` (6 subsequent siblings)
  11 siblings, 3 replies; 125+ messages in thread
From: nbelakovski @ 2019-01-22 23:22 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

From the latest round of comments:
-Added a check in populate_value to only do the hashmap lookup for refs of type branch,
since other types would not be checked out in a worktree
-Reworded the commit message on 2/3 to make it clearer that the change in output is meant
to inform users that the colored/marked branches will behave differently from the others
upon attempts to delete or check out
-Removed the extra verbose check on 3/3 and added the worktree path to the output if it exists
-Set 'worktrees' variable to NULL after free-ing, to allow for ref-filter to be reentrant

Travis-CI results: https://travis-ci.org/nbelakovski/git/builds/483134182

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: Mark and color a branch differently if it is checked out in a
    linked worktree
  branch: Add an extra verbose output displaying worktree path for refs
    checked out in a linked worktree

 Documentation/git-branch.txt       | 22 +++++++-----
 Documentation/git-for-each-ref.txt |  5 +++
 builtin/branch.c                   | 16 ++++++---
 ref-filter.c                       | 74 ++++++++++++++++++++++++++++++++++++++
 t/t3200-branch.sh                  |  8 ++---
 t/t3203-branch-output.sh           | 21 +++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 7 files changed, 144 insertions(+), 17 deletions(-)

-- 
2.14.2


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-22 23:22   ` [PATCH v6 0/3] nbelakovski
@ 2019-01-22 23:22     ` nbelakovski
  2019-01-23 18:57       ` Junio C Hamano
  2019-01-22 23:23     ` [PATCH v6 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
  2019-01-22 23:23     ` [PATCH v6 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
  2 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-01-22 23:22 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom providing the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.
---
 Documentation/git-for-each-ref.txt |  5 +++
 ref-filter.c                       | 74 ++++++++++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 3 files changed, 94 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 774cecc7ed..6dcd39f6f6 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -214,6 +214,11 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 422a9c9ae3..3c056cc148 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -75,6 +77,22 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct ref_to_worktree_entry {
+	struct hashmap_entry ent; /* must be the first member! */
+	struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,
+				   const void *key, const void *keydata_aka_refname)
+{
+	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+	const struct ref_to_worktree_entry *k = key;
+	return strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct hashmap ref_to_worktree_map;
+static struct worktree **worktrees = NULL;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -438,6 +456,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
 	return 0;
 }
 
+static int worktree_atom_parser(const struct ref_format *format,
+				struct used_atom *atom,
+				const char *arg,
+				struct strbuf *unused_err)
+{
+	int i;
+
+	if (worktrees)
+		return 0;
+
+	worktrees = get_worktrees(0);
+
+	hashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct ref_to_worktree_entry *entry;
+			entry = xmalloc(sizeof(*entry));
+			entry->wt = worktrees[i];
+			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+			hashmap_add(&ref_to_worktree_map, entry);
+		}
+	}
+
+	return 0;
+}
+
 static struct {
 	const char *name;
 	info_source source;
@@ -480,6 +526,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE, FIELD_STR, worktree_atom_parser },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1525,6 +1572,21 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct strbuf val = STRBUF_INIT;
+	struct hashmap_entry entry;
+	struct ref_to_worktree_entry *lookup_result;
+
+	hashmap_entry_init(&entry, strhash(ref->refname));
+	lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);
+
+	if (lookup_result)
+		strbuf_addstr(&val, lookup_result->wt->path);
+
+	return strbuf_detach(&val, NULL);
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1562,6 +1624,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (starts_with(name, "worktreepath")) {
+			if (ref->kind == FILTER_REFS_BRANCHES)
+				v->s = get_worktree_path(atom, ref);
+			else
+				v->s = xstrdup("");
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2045,6 +2114,11 @@ void ref_array_clear(struct ref_array *array)
 		free_array_item(array->items[i]);
 	FREE_AND_NULL(array->items);
 	array->nr = array->alloc = 0;
+	if (worktrees) {
+		hashmap_free(&ref_to_worktree_map, 1);
+		free_worktrees(worktrees);
+		worktrees = NULL;
+	}
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..87e0222ea1 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-EOF &&
+	master: $(pwd)
+	master_worktree: $(pwd)/worktree_dir
+	side: not checked out
+	EOF
+	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v6 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-01-22 23:22   ` [PATCH v6 0/3] nbelakovski
  2019-01-22 23:22     ` [PATCH v6 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-01-22 23:23     ` nbelakovski
  2019-01-22 23:23     ` [PATCH v6 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
  2 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-01-22 23:23 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

The output of git branch is modified to mark branches checkout out in a
linked worktree with a "+" and color them in cyan (in contrast to the
current branch, which will still be denoted with a "*" and colored in green)

This is meant to communicate to the user that the branches that are
marked or colored will behave differently from other branches if the user
attempts to check them out or delete them, since branches checked out in
another worktree cannot be checked out or deleted.
---
 Documentation/git-branch.txt | 15 ++++++++-------
 builtin/branch.c             | 12 ++++++++----
 t/t3200-branch.sh            |  8 ++++----
 t/t3203-branch-output.sh     | 21 +++++++++++++++++++++
 4 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index bf5316ffa9..b3eca6ffdc 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -26,13 +26,14 @@ DESCRIPTION
 -----------
 
 If `--list` is given, or if there are no non-option arguments, existing
-branches are listed; the current branch will be highlighted with an
-asterisk.  Option `-r` causes the remote-tracking branches to be listed,
-and option `-a` shows both local and remote branches. If a `<pattern>`
-is given, it is used as a shell wildcard to restrict the output to
-matching branches. If multiple patterns are given, a branch is shown if
-it matches any of the patterns.  Note that when providing a
-`<pattern>`, you must use `--list`; otherwise the command is interpreted
+branches are listed; the current branch will be highlighted in green and
+marked with an asterisk.  Any branches checked out in linked worktrees will
+be highlighted in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed, and option `-a` shows both local and
+remote branches. If a `<pattern>` is given, it is used as a shell wildcard to
+restrict the output to matching branches. If multiple patterns are given, a
+branch is shown if it matches any of the patterns.  Note that when providing
+a `<pattern>`, you must use `--list`; otherwise the command is interpreted
 as branch creation.
 
 With `--contains`, shows only the branches that contain the named commit
diff --git a/builtin/branch.c b/builtin/branch.c
index 1be727209b..c2a86362bb 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..e404f6e23c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '
 test_expect_success 'git branch --column' '
 	COLUMNS=81 git branch --column=column >actual &&
 	cat >expected <<\EOF &&
-  a/b/c     bam       foo       l       * master    n         o/p       r
+  a/b/c   + bam       foo       l       * master    n         o/p       r
   abc       bar       j/k       m/m       master2   o/o       q
 EOF
 	test_cmp expected actual
@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
 	cat >expected <<EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '
 	git config --unset column.branch &&
 	git config --unset column.ui &&
 	cat >expected <<\EOF &&
-  a/b/c   bam   foo   l   * master    n     o/p   r
+  a/b/c + bam   foo   l   * master    n     o/p   r
   abc     bar   j/k   m/m   master2   o/o   q
 EOF
 	test_cmp expected actual
@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
 	cat >expected <<\EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614c..94ab05ad59 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
++ <CYAN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+	test_terminal git branch >actual.raw &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v6 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2019-01-22 23:22   ` [PATCH v6 0/3] nbelakovski
  2019-01-22 23:22     ` [PATCH v6 1/3] ref-filter: add worktreepath atom nbelakovski
  2019-01-22 23:23     ` [PATCH v6 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
@ 2019-01-22 23:23     ` nbelakovski
  2 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-01-22 23:23 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

---
 Documentation/git-branch.txt | 7 +++++--
 builtin/branch.c             | 4 ++++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index b3eca6ffdc..a1aef00af0 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -163,12 +163,15 @@ This option is only applicable in non-verbose mode.
 
 -v::
 -vv::
+-vvv::
 --verbose::
 	When in list mode,
 	show sha1 and commit subject line for each head, along with
 	relationship to upstream branch (if any). If given twice, print
-	the name of the upstream branch, as well (see also `git remote
-	show <remote>`).
+	the path of the linked worktree, if applicable (not applicable
+	for main worktree since user's path will already be in main
+	worktree) and the name of the upstream branch, as well (see also
+	`git remote show <remote>`).
 
 -q::
 --quiet::
diff --git a/builtin/branch.c b/builtin/branch.c
index c2a86362bb..0b8ba9e4c5 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addf(&local, " %s ", obname.buf);
 
 		if (filter->verbose > 1)
+		{
+			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
 				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+		}
 		else
 			strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
 
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-22 23:22     ` [PATCH v6 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-01-23 18:57       ` Junio C Hamano
  2019-01-23 23:34         ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-23 18:57 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
>
> Add an atom providing the path of the linked worktree where this ref is
> checked out, if it is checked out in any linked worktrees, and empty
> string otherwise.
> ---

Missing sign-off?

> +static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,
> +				   const void *key, const void *keydata_aka_refname)
> +{
> +	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
> +	const struct ref_to_worktree_entry *k = key;
> +	return strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);

Overlong line.

> +}


> +
> +static struct hashmap ref_to_worktree_map;
> +static struct worktree **worktrees = NULL;

No need to initialize static vars to 0/NULL.

> @@ -438,6 +456,34 @@ static int head_atom_parser(const struct ref_format *format, struct used_atom *a
>  	return 0;
>  }
>  
> +static int worktree_atom_parser(const struct ref_format *format,
> +				struct used_atom *atom,
> +				const char *arg,
> +				struct strbuf *unused_err)
> +{
> +	int i;
> +
> +	if (worktrees)
> +		return 0;
> +
> +	worktrees = get_worktrees(0);
> +
> +	hashmap_init(&ref_to_worktree_map, ref_to_worktree_map_cmpfnc, NULL, 0);
> +
> +	for (i = 0; worktrees[i]; i++) {
> +		if (worktrees[i]->head_ref) {
> +			struct ref_to_worktree_entry *entry;
> +			entry = xmalloc(sizeof(*entry));
> +			entry->wt = worktrees[i];
> +			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
> +
> +			hashmap_add(&ref_to_worktree_map, entry);
> +		}
> +	}
> +
> +	return 0;
> +}

It is kind of interesting that a function for parsing an "atom" in
"format" does not look at none of its arguments at all ;-)  The fact
that "%(worktreepath)" atom got noticed by verify_ref_format() alone
is of interest for this function.

The helper iterates over all worktrees, registers them in a hashmap
ref_to_worktree_map, indexed by the head reference.

OK.

> +static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
> +{
> +	struct strbuf val = STRBUF_INIT;
> +	struct hashmap_entry entry;
> +	struct ref_to_worktree_entry *lookup_result;
> +
> +	hashmap_entry_init(&entry, strhash(ref->refname));
> +	lookup_result = hashmap_get(&ref_to_worktree_map, &entry, ref->refname);
> +
> +	if (lookup_result)
> +		strbuf_addstr(&val, lookup_result->wt->path);
> +
> +	return strbuf_detach(&val, NULL);
> +}

We do not need a strbuf to do the above, do we?

	hashmap_entry_init(...);
	lookup_result = hashmap_get(...);
	if (lookup_result)
		return xstrdup(lookup_result->wt->path);
	else
		return xstrdup("");

or something like that, perhaps?

> @@ -1562,6 +1624,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
>  
>  		if (starts_with(name, "refname"))
>  			refname = get_refname(atom, ref);
> +		else if (starts_with(name, "worktreepath")) {
> +			if (ref->kind == FILTER_REFS_BRANCHES)
> +				v->s = get_worktree_path(atom, ref);
> +			else
> +				v->s = xstrdup("");
> +			continue;
> +		}

I am wondering if get_worktree_path() being called should be the
triggering event for lazy initialization worktree_atom_parser() is
doing in this patch, instead of verify_ref_format() seeing the
"%(worktreepath)" atom.  Is there any codepath that wants to make
sure the lazy initialization is done without/before populate_value()
sees a use of the "%(worktreepath)" atom?  If so, such a plan would
not work, but otherwise, we can do the following:

 - rename worktree_atom_parser() to lazy_init_worktrees() or
   something, and remove all of its unused parameters.

 - remove parser callback for "worktreepath" from valid_atom[].

 - call lazy_inti_worktrees() at the beginning of
   get_worktree_path().

Hmm?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-23 18:57       ` Junio C Hamano
@ 2019-01-23 23:34         ` Nickolai Belakovski
  2019-01-24 18:26           ` Junio C Hamano
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-01-23 23:34 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: git, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Wed, Jan 23, 2019 at 10:57 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> Missing sign-off?
>

My mistake, forgot -s on format-patch. Will remember to add it next go-around.

> > +static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata, const void *existing_hashmap_entry_to_test,
> > +                                const void *key, const void *keydata_aka_refname)
> > +{
> > +     const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
> > +     const struct ref_to_worktree_entry *k = key;
> > +     return strcmp(e->wt->head_ref, keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
>
> Overlong line.
>
> > +}
>

OK, should I shorten the function signature as well? Is it too long
because it's 101 characters and you're trying to stick to 100?

>
> > +
> > +static struct hashmap ref_to_worktree_map;
> > +static struct worktree **worktrees = NULL;
>
> No need to initialize static vars to 0/NULL.

OK

>
> We do not need a strbuf to do the above, do we?
>
>         hashmap_entry_init(...);
>         lookup_result = hashmap_get(...);
>         if (lookup_result)
>                 return xstrdup(lookup_result->wt->path);
>         else
>                 return xstrdup("");
>
> or something like that, perhaps?
>

Sure.

> > @@ -1562,6 +1624,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
> >
> >               if (starts_with(name, "refname"))
> >                       refname = get_refname(atom, ref);
> > +             else if (starts_with(name, "worktreepath")) {
> > +                     if (ref->kind == FILTER_REFS_BRANCHES)
> > +                             v->s = get_worktree_path(atom, ref);
> > +                     else
> > +                             v->s = xstrdup("");
> > +                     continue;
> > +             }
>
> I am wondering if get_worktree_path() being called should be the
> triggering event for lazy initialization worktree_atom_parser() is
> doing in this patch, instead of verify_ref_format() seeing the
> "%(worktreepath)" atom.  Is there any codepath that wants to make
> sure the lazy initialization is done without/before populate_value()
> sees a use of the "%(worktreepath)" atom?  If so, such a plan would
> not work, but otherwise, we can do the following:
>
>  - rename worktree_atom_parser() to lazy_init_worktrees() or
>    something, and remove all of its unused parameters.
>
>  - remove parser callback for "worktreepath" from valid_atom[].
>
>  - call lazy_inti_worktrees() at the beginning of
>    get_worktree_path().
>
> Hmm?

Yes, the parser used the atom argument in an earlier version of this
patch, but we since moved the map out of the atom since it only needs
to exist once globally. Even though we have a caching mechanism for
atoms it still seemed like a logical move to explicitly keep one
instance of the map globally. Will make the change, thanks for taking
a look at it through fresh eyes.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-23 23:34         ` Nickolai Belakovski
@ 2019-01-24 18:26           ` Junio C Hamano
  2019-01-24 18:32             ` Jeff King
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-24 18:26 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: git, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

Nickolai Belakovski <nbelakovski@gmail.com> writes:

> Yes, the parser used the atom argument in an earlier version of this
> patch, but we since moved the map out of the atom since it only needs
> to exist once globally. Even though we have a caching mechanism for
> atoms it still seemed like a logical move to explicitly keep one
> instance of the map globally.

I think that is a mistaken move from an earlier version to this
one.  The worktree-related stuff only becomes necessary and belongs
to the %(worktreepath) atom, so unless there is a compelling reason
not to, we should hang it there, instead of introducing a global.
When you have --format='%(worktreepath) %(worktreepath)', you'd have
only one shared instance of it in used_atom[] to ensure that we have
a singleton instance.

The object_info support in the file, which is relatively new, may be
what you borrowed the wrong idea of preferring globals from; I think
it should be taken as an anti-pattern.


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-24 18:26           ` Junio C Hamano
@ 2019-01-24 18:32             ` Jeff King
  2019-01-24 19:27               ` Junio C Hamano
  2019-01-24 19:30               ` Junio C Hamano
  0 siblings, 2 replies; 125+ messages in thread
From: Jeff King @ 2019-01-24 18:32 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Nickolai Belakovski, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Thu, Jan 24, 2019 at 10:26:18AM -0800, Junio C Hamano wrote:

> Nickolai Belakovski <nbelakovski@gmail.com> writes:
> 
> > Yes, the parser used the atom argument in an earlier version of this
> > patch, but we since moved the map out of the atom since it only needs
> > to exist once globally. Even though we have a caching mechanism for
> > atoms it still seemed like a logical move to explicitly keep one
> > instance of the map globally.
> 
> I think that is a mistaken move from an earlier version to this
> one.  The worktree-related stuff only becomes necessary and belongs
> to the %(worktreepath) atom, so unless there is a compelling reason
> not to, we should hang it there, instead of introducing a global.
> When you have --format='%(worktreepath) %(worktreepath)', you'd have
> only one shared instance of it in used_atom[] to ensure that we have
> a singleton instance.

What if you have other atoms that need worktrees? E.g., does
%(worktreepath:foo) use the same used_atom slot? What if we have another
worktree-related atom?

If anything, I'd suggest going in the opposite direction, and teaching
the worktree code a function for looking up a working tree by ref. And
then it can handle its own cache to implement that reverse-mapping
efficiently.

> The object_info support in the file, which is relatively new, may be
> what you borrowed the wrong idea of preferring globals from; I think
> it should be taken as an anti-pattern.

And that one is a good example where we _do_ need the global, because we
already have multiple atoms pulling from it. I think the right level is
"global to the ref-filter context", but we do not have that concept yet
(hence why used_atoms, etc, are all file-static globals).

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-24 18:32             ` Jeff King
@ 2019-01-24 19:27               ` Junio C Hamano
  2019-01-24 19:34                 ` Jeff King
  2019-01-24 19:30               ` Junio C Hamano
  1 sibling, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-24 19:27 UTC (permalink / raw)
  To: Jeff King
  Cc: Nickolai Belakovski, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

Jeff King <peff@peff.net> writes:

> If anything, I'd suggest going in the opposite direction, and teaching
> the worktree code a function for looking up a working tree by ref. And
> then it can handle its own cache to implement that reverse-mapping
> efficiently.

Yeah, that's a thought.  Then "give me a worktree that checks out
this ref" can be asked outside the context of for-each-ref and
friends, which is a big plus.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-24 18:32             ` Jeff King
  2019-01-24 19:27               ` Junio C Hamano
@ 2019-01-24 19:30               ` Junio C Hamano
  2019-01-24 21:26                 ` Jeff King
  1 sibling, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-24 19:30 UTC (permalink / raw)
  To: Jeff King
  Cc: Nickolai Belakovski, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

Jeff King <peff@peff.net> writes:

> What if you have other atoms that need worktrees? E.g., does
> %(worktreepath:foo) use the same used_atom slot? What if we have another
> worktree-related atom?
> ...
> And that one is a good example where we _do_ need the global, because we
> already have multiple atoms pulling from it.

I guess that we broke the original atom design by mistake when we
added ":<modifiers>" support.  There should have been one layer of
indirection that binds the instances of the same atom with different
modifiers together---I agree with you that we cannot avoid globals
without fixing that mistake first.

Thanks.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-24 19:27               ` Junio C Hamano
@ 2019-01-24 19:34                 ` Jeff King
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2019-01-24 19:34 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Nickolai Belakovski, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Thu, Jan 24, 2019 at 11:27:36AM -0800, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > If anything, I'd suggest going in the opposite direction, and teaching
> > the worktree code a function for looking up a working tree by ref. And
> > then it can handle its own cache to implement that reverse-mapping
> > efficiently.
> 
> Yeah, that's a thought.  Then "give me a worktree that checks out
> this ref" can be asked outside the context of for-each-ref and
> friends, which is a big plus.

One tricky thing is that we do not store a list of "struct worktree",
but rather generate it on the fly when get_worktrees() is called.

So having an API to ask for one ref's worktree at a time is slightly
awkward. It's only by having (and caching) this full list in
ref-filter.c that we can easily make the reverse-indexed hashmap.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-24 19:30               ` Junio C Hamano
@ 2019-01-24 21:26                 ` Jeff King
  2019-01-31 20:53                   ` Nickolai Belakovski
  2019-01-31 21:42                   ` Junio C Hamano
  0 siblings, 2 replies; 125+ messages in thread
From: Jeff King @ 2019-01-24 21:26 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Nickolai Belakovski, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Thu, Jan 24, 2019 at 11:30:20AM -0800, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > What if you have other atoms that need worktrees? E.g., does
> > %(worktreepath:foo) use the same used_atom slot? What if we have another
> > worktree-related atom?
> > ...
> > And that one is a good example where we _do_ need the global, because we
> > already have multiple atoms pulling from it.
> 
> I guess that we broke the original atom design by mistake when we
> added ":<modifiers>" support.  There should have been one layer of
> indirection that binds the instances of the same atom with different
> modifiers together---I agree with you that we cannot avoid globals
> without fixing that mistake first.

Yes, that's one way to fix it.

I actually think the biggest mistake is having that used_atoms list in
the first place, as we iterate over it several times asking "can we fill
this in yet?". The way pretty.c does it is just to incrementally parse
the commit, saving intermediate results. And in cat-file.c, we figure
out what we need ahead of time in a single pass, and then just fill it
in for each object (which sort of works out the same, but doesn't
require that the parsing needed for item X is a strict superset of item
Y).

So I'd much rather see us parse the format into a real tree of nodes,
and figure out (once) which properties of each object are required to
fulfill that. Then for each object, we grab those properties, and then
walk the tree to generate the output string.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-24 21:26                 ` Jeff King
@ 2019-01-31 20:53                   ` Nickolai Belakovski
  2019-01-31 23:21                     ` Jeff King
  2019-01-31 21:42                   ` Junio C Hamano
  1 sibling, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-01-31 20:53 UTC (permalink / raw)
  To: Jeff King
  Cc: Junio C Hamano, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

So where does that leave us for this series? We could move hashmap
back into used_atom, but if a user entered
--format="%(worktreepath)%(worktreepath:)" we'd end up freeing
worktrees twice. Not that that should stop us - that scenario is one
where user input isn't sensible and personally I don't think it's
necessary to protect against such things (unless the user was
reasonably confused, but I don't see that as the case here).

I agree with Jeff that a ref-filter "context" would help. And in more
ways than one, it could help us decide ahead of time whether to check
if a ref is a branch or a tag before doing a hashmap lookup or just
skip the check (i.e. if there are no tags within the context, the
check would only add cost). But I do believe that that would be
outside the scope of this series.

I think leaving it as globals is a tiny bit safer and also makes it
easier to pack it into a context if/when we decide to do that work,
but as always I'm open to other interpretations.


On Thu, Jan 24, 2019 at 1:26 PM Jeff King <peff@peff.net> wrote:
>
> On Thu, Jan 24, 2019 at 11:30:20AM -0800, Junio C Hamano wrote:
>
> > Jeff King <peff@peff.net> writes:
> >
> > > What if you have other atoms that need worktrees? E.g., does
> > > %(worktreepath:foo) use the same used_atom slot? What if we have another
> > > worktree-related atom?
> > > ...
> > > And that one is a good example where we _do_ need the global, because we
> > > already have multiple atoms pulling from it.
> >
> > I guess that we broke the original atom design by mistake when we
> > added ":<modifiers>" support.  There should have been one layer of
> > indirection that binds the instances of the same atom with different
> > modifiers together---I agree with you that we cannot avoid globals
> > without fixing that mistake first.
>
> Yes, that's one way to fix it.
>
> I actually think the biggest mistake is having that used_atoms list in
> the first place, as we iterate over it several times asking "can we fill
> this in yet?". The way pretty.c does it is just to incrementally parse
> the commit, saving intermediate results. And in cat-file.c, we figure
> out what we need ahead of time in a single pass, and then just fill it
> in for each object (which sort of works out the same, but doesn't
> require that the parsing needed for item X is a strict superset of item
> Y).
>
> So I'd much rather see us parse the format into a real tree of nodes,
> and figure out (once) which properties of each object are required to
> fulfill that. Then for each object, we grab those properties, and then
> walk the tree to generate the output string.
>
> -Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-24 21:26                 ` Jeff King
  2019-01-31 20:53                   ` Nickolai Belakovski
@ 2019-01-31 21:42                   ` Junio C Hamano
  2019-01-31 23:20                     ` Jeff King
  1 sibling, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-01-31 21:42 UTC (permalink / raw)
  To: Jeff King
  Cc: Nickolai Belakovski, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

Jeff King <peff@peff.net> writes:

> On Thu, Jan 24, 2019 at 11:30:20AM -0800, Junio C Hamano wrote:
>
>> Jeff King <peff@peff.net> writes:
>> 
>> > What if you have other atoms that need worktrees? E.g., does
>> > %(worktreepath:foo) use the same used_atom slot? What if we have another
>> > worktree-related atom?
>> > ...
>> > And that one is a good example where we _do_ need the global, because we
>> > already have multiple atoms pulling from it.
>> 
>> I guess that we broke the original atom design by mistake when we
>> added ":<modifiers>" support.  There should have been one layer of
>> indirection that binds the instances of the same atom with different
>> modifiers together---I agree with you that we cannot avoid globals
>> without fixing that mistake first.
>
> Yes, that's one way to fix it.
>
> I actually think the biggest mistake is having that used_atoms list in
> the first place, as we iterate over it several times asking "can we fill
> this in yet?". The way pretty.c does it is just to incrementally parse
> the commit, saving intermediate results. And in cat-file.c, we figure
> out what we need ahead of time in a single pass, and then just fill it
> in for each object (which sort of works out the same, but doesn't
> require that the parsing needed for item X is a strict superset of item
> Y).
>
> So I'd much rather see us parse the format into a real tree of nodes,
> and figure out (once) which properties of each object are required to
> fulfill that. Then for each object, we grab those properties, and then
> walk the tree to generate the output string.

That sounds like a sensible longer-term strategy.  Let's however
leave it outside the scope of this change.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-31 21:42                   ` Junio C Hamano
@ 2019-01-31 23:20                     ` Jeff King
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2019-01-31 23:20 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Nickolai Belakovski, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Thu, Jan 31, 2019 at 01:42:14PM -0800, Junio C Hamano wrote:

> > So I'd much rather see us parse the format into a real tree of nodes,
> > and figure out (once) which properties of each object are required to
> > fulfill that. Then for each object, we grab those properties, and then
> > walk the tree to generate the output string.
> 
> That sounds like a sensible longer-term strategy.  Let's however
> leave it outside the scope of this change.

Yeah, sorry if I got us too far afield. It's definitely out of scope for
this series. The takeaway I was trying to get at is that storing the
worktree map as a static global is actually pretty reasonable given the
current design.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v6 1/3] ref-filter: add worktreepath atom
  2019-01-31 20:53                   ` Nickolai Belakovski
@ 2019-01-31 23:21                     ` Jeff King
  0 siblings, 0 replies; 125+ messages in thread
From: Jeff King @ 2019-01-31 23:21 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Junio C Hamano, git, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Thu, Jan 31, 2019 at 12:53:24PM -0800, Nickolai Belakovski wrote:

> So where does that leave us for this series? We could move hashmap
> back into used_atom, but if a user entered
> --format="%(worktreepath)%(worktreepath:)" we'd end up freeing
> worktrees twice. Not that that should stop us - that scenario is one
> where user input isn't sensible and personally I don't think it's
> necessary to protect against such things (unless the user was
> reasonably confused, but I don't see that as the case here).
> 
> I agree with Jeff that a ref-filter "context" would help. And in more
> ways than one, it could help us decide ahead of time whether to check
> if a ref is a branch or a tag before doing a hashmap lookup or just
> skip the check (i.e. if there are no tags within the context, the
> check would only add cost). But I do believe that that would be
> outside the scope of this series.
> 
> I think leaving it as globals is a tiny bit safer and also makes it
> easier to pack it into a context if/when we decide to do that work,
> but as always I'm open to other interpretations.

Yeah, I agree with this: global for now, and then easily moved into a
context struct later (along with all the other existing globals).

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v7 0/3]
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (4 preceding siblings ...)
  2019-01-22 23:22   ` [PATCH v6 0/3] nbelakovski
@ 2019-02-01 22:04   ` nbelakovski
  2019-02-01 22:28     ` Junio C Hamano
  2019-02-01 22:04   ` [PATCH v7 1/3] ref-filter: add worktreepath atom nbelakovski
                     ` (5 subsequent siblings)
  11 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-02-01 22:04 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>


Moved initialization of ref_to_worktree_map outside of atom parser. Other minor fixes.

Put the hashmap and the worktree struct in the same struct, to make it more obvious that
they are to be initialized and free'd together.

Travis CI results: https://travis-ci.org/nbelakovski/git/builds/487642061

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: Mark and color a branch differently if it is checked out in a
    linked worktree
  branch: Add an extra verbose output displaying worktree path for refs
    checked out in a linked worktree

 Documentation/git-branch.txt       | 21 +++++-----
 Documentation/git-for-each-ref.txt |  5 +++
 builtin/branch.c                   | 16 ++++++--
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t3200-branch.sh                  |  8 ++--
 t/t3203-branch-output.sh           | 21 ++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 7 files changed, 147 insertions(+), 17 deletions(-)

-- 
2.14.2


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v7 1/3] ref-filter: add worktreepath atom
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (5 preceding siblings ...)
  2019-02-01 22:04   ` [PATCH v7 0/3] nbelakovski
@ 2019-02-01 22:04   ` nbelakovski
  2019-02-01 22:20     ` Eric Sunshine
  2019-02-01 22:31     ` Junio C Hamano
  2019-02-01 22:04   ` [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
                     ` (4 subsequent siblings)
  11 siblings, 2 replies; 125+ messages in thread
From: nbelakovski @ 2019-02-01 22:04 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom providing the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-for-each-ref.txt |  5 +++
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 15 ++++++++
 3 files changed, 98 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 774cecc7ed..6dcd39f6f6 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -214,6 +214,11 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 422a9c9ae3..e46608476d 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -75,6 +77,27 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct ref_to_worktree_entry {
+	struct hashmap_entry ent; /* must be the first member! */
+	struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
+				      const void *existing_hashmap_entry_to_test,
+				      const void *key,
+				      const void *keydata_aka_refname)
+{
+	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+	const struct ref_to_worktree_entry *k = key;
+	return strcmp(e->wt->head_ref,
+		keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct ref_to_worktree_map {
+	struct hashmap map;
+	struct worktree **worktrees;
+} ref_to_worktree_map;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -480,6 +503,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1525,6 +1549,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
+{
+	int i;
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct ref_to_worktree_entry *entry;
+			entry = xmalloc(sizeof(*entry));
+			entry->wt = worktrees[i];
+			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+			hashmap_add(map, entry);
+		}
+	}
+}
+
+static void lazy_init_worktree_map(void)
+{
+	if (ref_to_worktree_map.worktrees)
+		return;
+
+	ref_to_worktree_map.worktrees = get_worktrees(0);
+	hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
+	populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
+}
+
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct hashmap_entry entry;
+	struct ref_to_worktree_entry *lookup_result;
+
+	lazy_init_worktree_map();
+
+	hashmap_entry_init(&entry, strhash(ref->refname));
+	lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
+
+	if (lookup_result)
+		return xstrdup(lookup_result->wt->path);
+	else
+		return xstrdup("");
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (starts_with(name, "worktreepath")) {
+			if (ref->kind == FILTER_REFS_BRANCHES)
+				v->s = get_worktree_path(atom, ref);
+			else
+				v->s = xstrdup("");
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2045,6 +2118,11 @@ void ref_array_clear(struct ref_array *array)
 		free_array_item(array->items[i]);
 	FREE_AND_NULL(array->items);
 	array->nr = array->alloc = 0;
+	if (ref_to_worktree_map.worktrees) {
+		hashmap_free(&(ref_to_worktree_map.map), 1);
+		free_worktrees(ref_to_worktree_map.worktrees);
+		ref_to_worktree_map.worktrees = NULL;
+	}
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..87e0222ea1 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-EOF &&
+	master: $(pwd)
+	master_worktree: $(pwd)/worktree_dir
+	side: not checked out
+	EOF
+	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (6 preceding siblings ...)
  2019-02-01 22:04   ` [PATCH v7 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-02-01 22:04   ` nbelakovski
  2019-02-01 22:34     ` Junio C Hamano
  2019-02-01 22:04   ` [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
                     ` (3 subsequent siblings)
  11 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-02-01 22:04 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

The output of git branch is modified to mark branches checkout out in a
linked worktree with a "+" and color them in cyan (in contrast to the
current branch, which will still be denoted with a "*" and colored in green)

This is meant to communicate to the user that the branches that are
marked or colored will behave differently from other branches if the user
attempts to check them out or delete them, since branches checked out in
another worktree cannot be checked out or deleted.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt | 15 ++++++++-------
 builtin/branch.c             | 12 ++++++++----
 t/t3200-branch.sh            |  8 ++++----
 t/t3203-branch-output.sh     | 21 +++++++++++++++++++++
 4 files changed, 41 insertions(+), 15 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index bf5316ffa9..b3eca6ffdc 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -26,13 +26,14 @@ DESCRIPTION
 -----------
 
 If `--list` is given, or if there are no non-option arguments, existing
-branches are listed; the current branch will be highlighted with an
-asterisk.  Option `-r` causes the remote-tracking branches to be listed,
-and option `-a` shows both local and remote branches. If a `<pattern>`
-is given, it is used as a shell wildcard to restrict the output to
-matching branches. If multiple patterns are given, a branch is shown if
-it matches any of the patterns.  Note that when providing a
-`<pattern>`, you must use `--list`; otherwise the command is interpreted
+branches are listed; the current branch will be highlighted in green and
+marked with an asterisk.  Any branches checked out in linked worktrees will
+be highlighted in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed, and option `-a` shows both local and
+remote branches. If a `<pattern>` is given, it is used as a shell wildcard to
+restrict the output to matching branches. If multiple patterns are given, a
+branch is shown if it matches any of the patterns.  Note that when providing
+a `<pattern>`, you must use `--list`; otherwise the command is interpreted
 as branch creation.
 
 With `--contains`, shows only the branches that contain the named commit
diff --git a/builtin/branch.c b/builtin/branch.c
index 1be727209b..c2a86362bb 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..e404f6e23c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '
 test_expect_success 'git branch --column' '
 	COLUMNS=81 git branch --column=column >actual &&
 	cat >expected <<\EOF &&
-  a/b/c     bam       foo       l       * master    n         o/p       r
+  a/b/c   + bam       foo       l       * master    n         o/p       r
   abc       bar       j/k       m/m       master2   o/o       q
 EOF
 	test_cmp expected actual
@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
 	cat >expected <<EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '
 	git config --unset column.branch &&
 	git config --unset column.ui &&
 	cat >expected <<\EOF &&
-  a/b/c   bam   foo   l   * master    n     o/p   r
+  a/b/c + bam   foo   l   * master    n     o/p   r
   abc     bar   j/k   m/m   master2   o/o   q
 EOF
 	test_cmp expected actual
@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
 	cat >expected <<\EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614c..94ab05ad59 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
++ <CYAN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+	test_terminal git branch >actual.raw &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (7 preceding siblings ...)
  2019-02-01 22:04   ` [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
@ 2019-02-01 22:04   ` nbelakovski
  2019-02-01 22:27     ` Eric Sunshine
  2019-02-01 22:53     ` Junio C Hamano
  2019-02-19  8:31   ` [PATCH v8 0/3] nbelakovski
                     ` (2 subsequent siblings)
  11 siblings, 2 replies; 125+ messages in thread
From: nbelakovski @ 2019-02-01 22:04 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt | 6 ++++--
 builtin/branch.c             | 4 ++++
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index b3eca6ffdc..778be7080f 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.
 	When in list mode,
 	show sha1 and commit subject line for each head, along with
 	relationship to upstream branch (if any). If given twice, print
-	the name of the upstream branch, as well (see also `git remote
-	show <remote>`).
+	the path of the linked worktree, if applicable (not applicable
+	for main worktree since user's path will already be in main
+	worktree) and the name of the upstream branch, as well (see also
+	`git remote show <remote>`).
 
 -q::
 --quiet::
diff --git a/builtin/branch.c b/builtin/branch.c
index c2a86362bb..0b8ba9e4c5 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addf(&local, " %s ", obname.buf);
 
 		if (filter->verbose > 1)
+		{
+			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
 				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+		}
 		else
 			strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
 
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 1/3] ref-filter: add worktreepath atom
  2019-02-01 22:04   ` [PATCH v7 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-02-01 22:20     ` Eric Sunshine
  2019-02-01 22:41       ` Nickolai Belakovski
  2019-02-01 22:31     ` Junio C Hamano
  1 sibling, 1 reply; 125+ messages in thread
From: Eric Sunshine @ 2019-02-01 22:20 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Git List, Jeff King, Rafael Ascensao, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:
> Add an atom providing the path of the linked worktree where this ref is
> checked out, if it is checked out in any linked worktrees, and empty
> string otherwise.
>
> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
> ---
> diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
> @@ -214,6 +214,11 @@ symref::
> +worktreepath::
> +       The absolute path to the worktree in which the ref is checked
> +       out, if it is checked out in any linked worktree. Empty string
> +       otherwise.

This may have been asked previously, but is there a reason this name
was chosen over the more extensible "worktree:" with "path" as a
modifier (i.e. "worktree:path")? I scanned the thread a couple weeks
ago and did see mention of "worktree:path" but did not find any
followup. I ask because it's conceivable that someone in the future
might want to retrieve other information about the worktree beyond its
path (such as whether it's bare or detached, etc.). By using the form
"worktree:<foo>", we leave that door open. (I'm not suggesting that
this patch series needs to implement fetching of any of the other
worktree properties, but just asking if "worktree:<foo>" should be
considered.)

> diff --git a/ref-filter.c b/ref-filter.c
> @@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
>                 if (starts_with(name, "refname"))
>                         refname = get_refname(atom, ref);
> +               else if (starts_with(name, "worktreepath")) {

I think this was brought up previously, but shouldn't this be strcmp()
rather than starts_with()?

(starts_with() would be appropriate, if you went with the suggested
"worktree:<foo>".)

> diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
> @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
> +test_expect_success '"add" a worktree' '
> +       mkdir worktree_dir &&
> +       git worktree add -b master_worktree worktree_dir master
> +'

I don't think 'mkdir' is needed since "git worktree add" should create
the directory itself.

> +test_expect_success 'validate worktree atom' '
> +       cat >expect <<-EOF &&
> +       master: $(pwd)
> +       master_worktree: $(pwd)/worktree_dir
> +       side: not checked out
> +       EOF
> +       git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
> +       test_cmp expect actual
> +'

If this is the only test using that newly-created worktree, it might
make sense to squash the two tests together.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2019-02-01 22:04   ` [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
@ 2019-02-01 22:27     ` Eric Sunshine
  2019-02-01 22:45       ` Nickolai Belakovski
  2019-02-01 22:53     ` Junio C Hamano
  1 sibling, 1 reply; 125+ messages in thread
From: Eric Sunshine @ 2019-02-01 22:27 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Git List, Jeff King, Rafael Ascensao, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:
> Subject: branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree

Overlong subject. Perhaps shorten it to:

    branch: display worktree path in -v -v mode

or something, and use the longer description as the rest of the body
of the commit message.

> Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
> ---
> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
> @@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.
>         When in list mode,
>         show sha1 and commit subject line for each head, along with
>         relationship to upstream branch (if any). If given twice, print
> -       the name of the upstream branch, as well (see also `git remote
> -       show <remote>`).
> +       the path of the linked worktree, if applicable (not applicable
> +       for main worktree since user's path will already be in main
> +       worktree) and the name of the upstream branch, as well (see also
> +       `git remote show <remote>`).

I'm not sure I understand the "not applicable" explanation. When you
say "user's path", do you mean the current working directory? What
happens if the command is invoked from within one of the linked
worktrees (not from within the main worktree)?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 0/3]
  2019-02-01 22:04   ` [PATCH v7 0/3] nbelakovski
@ 2019-02-01 22:28     ` Junio C Hamano
  2019-02-01 23:31       ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-02-01 22:28 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

>   ref-filter: add worktreepath atom
>   branch: Mark and color a branch differently if it is checked out in a
>     linked worktree
>   branch: Add an extra verbose output displaying worktree path for refs
>     checked out in a linked worktree

As you can see in "git shortlog --no-merges", later two patches
would look quite out of place by having overlong title and starting
the description(i.e. after "<area>: ") in a capital letter.

It is still not clear why we would want 2/3, even though I think 3/3
is a good idea.

This round signs off all the three patches, which is a great
improvement ;-)


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 1/3] ref-filter: add worktreepath atom
  2019-02-01 22:04   ` [PATCH v7 1/3] ref-filter: add worktreepath atom nbelakovski
  2019-02-01 22:20     ` Eric Sunshine
@ 2019-02-01 22:31     ` Junio C Hamano
  1 sibling, 0 replies; 125+ messages in thread
From: Junio C Hamano @ 2019-02-01 22:31 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

> +static void lazy_init_worktree_map(void)
> +{
> +	if (ref_to_worktree_map.worktrees)
> +		return;
> +
> +	ref_to_worktree_map.worktrees = get_worktrees(0);
> +	hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
> +	populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
> +}
> +
> +static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
> +{
> +	struct hashmap_entry entry;
> +	struct ref_to_worktree_entry *lookup_result;
> +
> +	lazy_init_worktree_map();
> +
> +	hashmap_entry_init(&entry, strhash(ref->refname));
> +	lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
> +
> +	if (lookup_result)
> +		return xstrdup(lookup_result->wt->path);
> +	else
> +		return xstrdup("");
> +}

Makes more sense than the previous round; much simpler to have
lazy-init in this function.

Thanks.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-02-01 22:04   ` [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
@ 2019-02-01 22:34     ` Junio C Hamano
  2019-02-01 23:12       ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-02-01 22:34 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

>  If `--list` is given, or if there are no non-option arguments, existing
> -branches are listed; the current branch will be highlighted with an
> -asterisk.  Option `-r` causes the remote-tracking branches to be listed,
> -and option `-a` shows both local and remote branches. If a `<pattern>`
> -is given, it is used as a shell wildcard to restrict the output to
> -matching branches. If multiple patterns are given, a branch is shown if
> -it matches any of the patterns.  Note that when providing a
> -`<pattern>`, you must use `--list`; otherwise the command is interpreted
> +branches are listed; the current branch will be highlighted in green and
> +marked with an asterisk.  Any branches checked out in linked worktrees will
> +be highlighted in cyan and marked with a plus sign. Option `-r` causes the
> +remote-tracking branches to be listed, and option `-a` shows both local and
> +remote branches. If a `<pattern>` is given, it is used as a shell wildcard to
> +restrict the output to matching branches. If multiple patterns are given, a
> +branch is shown if it matches any of the patterns.  Note that when providing
> +a `<pattern>`, you must use `--list`; otherwise the command is interpreted
>  as branch creation.

I had to apply and then use --color-words to see what is going on.
Please avoid unnecessary reflowing of the text that makes the patch
harder than necessary to read.

I still do not quite see the point of this step in the series,
though.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 1/3] ref-filter: add worktreepath atom
  2019-02-01 22:20     ` Eric Sunshine
@ 2019-02-01 22:41       ` Nickolai Belakovski
  2019-02-04 18:14         ` Junio C Hamano
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-02-01 22:41 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git List, Jeff King, Rafael Ascensao, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Fri, Feb 1, 2019 at 2:20 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:
> > Add an atom providing the path of the linked worktree where this ref is
> > checked out, if it is checked out in any linked worktrees, and empty
> > string otherwise.
> >
> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
> > ---
> > diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
> > @@ -214,6 +214,11 @@ symref::
> > +worktreepath::
> > +       The absolute path to the worktree in which the ref is checked
> > +       out, if it is checked out in any linked worktree. Empty string
> > +       otherwise.
>
> This may have been asked previously, but is there a reason this name
> was chosen over the more extensible "worktree:" with "path" as a
> modifier (i.e. "worktree:path")? I scanned the thread a couple weeks
> ago and did see mention of "worktree:path" but did not find any
> followup. I ask because it's conceivable that someone in the future
> might want to retrieve other information about the worktree beyond its
> path (such as whether it's bare or detached, etc.). By using the form
> "worktree:<foo>", we leave that door open. (I'm not suggesting that
> this patch series needs to implement fetching of any of the other
> worktree properties, but just asking if "worktree:<foo>" should be
> considered.)
>

There's been a little back and forth on it, but my understanding is
that using the colon separator bypasses the caching mechanism in the
atoms, so every instance of "worktree:path" in a format string would
require a lookup. Future atoms should be along the lines of
"worktreeisdetached", "worktreeisbare", etc. This is consistent with
several of the other atoms, like objecttype/size/name,
comitter/name/email/date.

> > diff --git a/ref-filter.c b/ref-filter.c
> > @@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
> >                 if (starts_with(name, "refname"))
> >                         refname = get_refname(atom, ref);
> > +               else if (starts_with(name, "worktreepath")) {
>
> I think this was brought up previously, but shouldn't this be strcmp()
> rather than starts_with()?
>
> (starts_with() would be appropriate, if you went with the suggested
> "worktree:<foo>".)

Not sure about it being brought up previously. starts_with seemed
consistent with other uses but now I see there's several other
instance of strcmp in populate value. Seems like a reasonable thing to
change. I had previously implemented "worktree:<foo>" and must've left
it alone after we went with worktreepath.

>
> > diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
> > @@ -441,4 +441,19 @@ test_expect_success '--merged is incompatible with --no-merged' '
> > +test_expect_success '"add" a worktree' '
> > +       mkdir worktree_dir &&
> > +       git worktree add -b master_worktree worktree_dir master
> > +'
>
> I don't think 'mkdir' is needed since "git worktree add" should create
> the directory itself.
>
> > +test_expect_success 'validate worktree atom' '
> > +       cat >expect <<-EOF &&
> > +       master: $(pwd)
> > +       master_worktree: $(pwd)/worktree_dir
> > +       side: not checked out
> > +       EOF
> > +       git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
> > +       test_cmp expect actual
> > +'
>
> If this is the only test using that newly-created worktree, it might
> make sense to squash the two tests together.

Sure, can do, on both points.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2019-02-01 22:27     ` Eric Sunshine
@ 2019-02-01 22:45       ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-02-01 22:45 UTC (permalink / raw)
  To: Eric Sunshine
  Cc: Git List, Jeff King, Rafael Ascensao, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Fri, Feb 1, 2019 at 2:28 PM Eric Sunshine <sunshine@sunshineco.com> wrote:
>
> On Fri, Feb 1, 2019 at 5:04 PM <nbelakovski@gmail.com> wrote:
> > Subject: branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
>
> Overlong subject. Perhaps shorten it to:
>
>     branch: display worktree path in -v -v mode
>
> or something, and use the longer description as the rest of the body
> of the commit message.

OK

>
> > Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
> > ---
> > diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
> > @@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.
> >         When in list mode,
> >         show sha1 and commit subject line for each head, along with
> >         relationship to upstream branch (if any). If given twice, print
> > -       the name of the upstream branch, as well (see also `git remote
> > -       show <remote>`).
> > +       the path of the linked worktree, if applicable (not applicable
> > +       for main worktree since user's path will already be in main
> > +       worktree) and the name of the upstream branch, as well (see also
> > +       `git remote show <remote>`).
>
> I'm not sure I understand the "not applicable" explanation. When you
> say "user's path", do you mean the current working directory? What
> happens if the command is invoked from within one of the linked
> worktrees (not from within the main worktree)?

I should correct that to say "current worktree" as opposed to main,
since that's what HEAD will give. And yes user's path means cwd. Does
that make more sense?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2019-02-01 22:04   ` [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
  2019-02-01 22:27     ` Eric Sunshine
@ 2019-02-01 22:53     ` Junio C Hamano
  2019-02-01 23:06       ` Nickolai Belakovski
  1 sibling, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-02-01 22:53 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

> @@ -167,8 +167,10 @@ This option is only applicable in non-verbose mode.
>  	When in list mode,
>  	show sha1 and commit subject line for each head, along with
>  	relationship to upstream branch (if any). If given twice, print
> -	the name of the upstream branch, as well (see also `git remote
> -	show <remote>`).
> +	the path of the linked worktree, if applicable (not applicable
> +	for main worktree since user's path will already be in main
> +	worktree) and the name of the upstream branch, as well (see also
> +	`git remote show <remote>`).

It is unclear what you mean by "user's path"; I take it as the
$(pwd) at least for now for the purpose of this review, but then
I am not sure if I agree with that justification part "since..."

If I start from a normal repository at /home/gitster/main.git,
create a linked worktree of it at /home/gitster/alt.git, chdir to
/home/gitster/alt.git and ask "git branch -v -v", then the branch
that is checked out in the main.git "main worktree" is not shown?

If the rule were "a branch that is checked out in one of the
worktrees connected to the repository is shown with the path to that
worktree" (i.e. no exception), I would understand it.  If the rule
were "a branch that is ... (the same sentence), unless it is the
branch that is checked out in the *current* worktree", then I would
understand it too.

Puzzled.

In any case, please add a test or two to protect this feature from
unintended future breakages.

Thanks.

>  
>  -q::
>  --quiet::
> diff --git a/builtin/branch.c b/builtin/branch.c
> index c2a86362bb..0b8ba9e4c5 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
>  		strbuf_addf(&local, " %s ", obname.buf);
>  
>  		if (filter->verbose > 1)
> +		{
> +			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
> +				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
>  			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
>  				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
>  				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
> +		}
>  		else
>  			strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs checked out in a linked worktree
  2019-02-01 22:53     ` Junio C Hamano
@ 2019-02-01 23:06       ` Nickolai Belakovski
  2019-02-02  1:22         ` [RFC] Sample of test for git branch -vv nbelakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-02-01 23:06 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:

>
> If the rule were "a branch that is checked out in one of the
> worktrees connected to the repository is shown with the path to that
> worktree" (i.e. no exception), I would understand it.  If the rule
> were "a branch that is ... (the same sentence), unless it is the
> branch that is checked out in the *current* worktree", then I would
> understand it too.
>

It is the latter, as in, yes, I meant "current". I will update the docs as such.

>
> In any case, please add a test or two to protect this feature from
> unintended future breakages.
>
> Thanks.
>

Will do.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-02-01 22:34     ` Junio C Hamano
@ 2019-02-01 23:12       ` Nickolai Belakovski
  2019-02-04 18:18         ` Junio C Hamano
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-02-01 23:12 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:
>
>
> I had to apply and then use --color-words to see what is going on.
> Please avoid unnecessary reflowing of the text that makes the patch
> harder than necessary to read.

I was trying to keep the line length consistent. How else can I accomplish that?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 0/3]
  2019-02-01 22:28     ` Junio C Hamano
@ 2019-02-01 23:31       ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-02-01 23:31 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Git List, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:
>
>
> As you can see in "git shortlog --no-merges", later two patches
> would look quite out of place by having overlong title and starting
> the description(i.e. after "<area>: ") in a capital letter.

Hadn't looked at it that way. OK, will shorten/uncapitalize.

>
> It is still not clear why we would want 2/3, even though I think 3/3
> is a good idea.
>
It's interesting to me that you like 3/3 but not 2/3 :)

My apologies for restating the commit message, but the point of 2/3 is
to communicate to the user that highlighted/marked branches will
behave differently from unhighlighted/unmarked branches for commands
to check out or delete. I think this is useful since it gives the user
actionable information ahead of time, as opposed to providing that
information upon failure of checkout/delete. It also makes sense since
'git branch' is already highlighting the current branch, i.e. this is
just an extension of that idea.

As we've stated earlier in this thread, 1/3 allows for users to
implement this on their own with a custom git branch format.
Personally I think there's value in making it default, since it's
adding information in a minimally intrusive way. I do believe that
merely adding information isn't a good enough reason to change things,
as information overload is a real thing, but in this case the output
isn't changed for anyone not using a worktree (same goes for 3/3), and
for someone using a worktree this provides useful and actionable
information, IMO.

Does that change your mind at all?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [RFC] Sample of test for git branch -vv
  2019-02-01 23:06       ` Nickolai Belakovski
@ 2019-02-02  1:22         ` nbelakovski
  0 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-02-02  1:22 UTC (permalink / raw)
  To: git; +Cc: peff, gitster, sunshine, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

I remember now why I didn't add a test for this one earlier.

Testing git branch -vv is a little tricky for a couple reasons.

For one thing, the output contains commit hashes, so the 'expect' file cannot be simply static.

For another, the output doesn't have clear delimiters for all columns, so trying to extract only
the commit hashes is tough.

I took the approach of stripping all information before and including the commit hashes.

You can see below how I did this. For the patch with worktreepath information, the worktreepath would
appear before the commit message on just one of those lines, but I crafted this patch so that it can be applied
to master.

This works, but it's rather awkward and ugly. Does anyone have better suggestions either for how to test or
how to implement?

---
 t/t3203-branch-output.sh | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 94ab05ad59..b836ca21fa 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -285,4 +284,22 @@ test_expect_success '--color overrides auto-color' '
 	test_cmp expect.color actual
 '
 
+test_expect_success 'test verbose verbose output' '
+	cat >expect <<-EOF &&
+	one
+	one
+	two
+	one
+	two
+	two
+	two
+	EOF
+	git branch -vv >tmp &&
+	head -1 tmp >tmp2 &&
+	SUBSTRLENGTH=$(awk "{print index(\$0, \"one\")}" <tmp2) &&
+	awk -v len="$SUBSTRLENGTH" "{print substr(\$0,len,length(\$0))}" <tmp >actual &&
+	test_cmp expect actual
+'
+
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 1/3] ref-filter: add worktreepath atom
  2019-02-01 22:41       ` Nickolai Belakovski
@ 2019-02-04 18:14         ` Junio C Hamano
  2019-02-18 10:09           ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Junio C Hamano @ 2019-02-04 18:14 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Eric Sunshine, Git List, Jeff King, Rafael Ascensao,
	Ævar Arnfjörð Bjarmason

Nickolai Belakovski <nbelakovski@gmail.com> writes:

> There's been a little back and forth on it, but my understanding is
> that using the colon separator bypasses the caching mechanism in the
> atoms, so every instance of "worktree:path" in a format string would
> require a lookup.

Would that be a problem, though?  You now have a singleton hashmap
that is a file-scope global not tied to any particular atom, so...?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree
  2019-02-01 23:12       ` Nickolai Belakovski
@ 2019-02-04 18:18         ` Junio C Hamano
  0 siblings, 0 replies; 125+ messages in thread
From: Junio C Hamano @ 2019-02-04 18:18 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Git List, Jeff King, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

Nickolai Belakovski <nbelakovski@gmail.com> writes:

> On Fri, Feb 1, 2019 at 2:54 PM Junio C Hamano <gitster@pobox.com> wrote:
>>
>>
>> I had to apply and then use --color-words to see what is going on.
>> Please avoid unnecessary reflowing of the text that makes the patch
>> harder than necessary to read.
>
> I was trying to keep the line length consistent. How else can I accomplish that?

By relying on the fact that in the final output it does not matter
how the sources look like, e.g.

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index bf5316ffa9..b64b3bf458 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -27,7 +27,9 @@ DESCRIPTION
 
 If `--list` is given, or if there are no non-option arguments, existing
 branches are listed; the current branch will be highlighted with an
-asterisk.  Option `-r` causes the remote-tracking branches to be listed,
+asterisk and shown in green.  Any branch checked out in linked worktrees
+is shown in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed,
 and option `-a` shows both local and remote branches. If a `<pattern>`
 is given, it is used as a shell wildcard to restrict the output to
 matching branches. If multiple patterns are given, a branch is shown if

^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v7 1/3] ref-filter: add worktreepath atom
  2019-02-04 18:14         ` Junio C Hamano
@ 2019-02-18 10:09           ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-02-18 10:09 UTC (permalink / raw)
  To: Junio C Hamano
  Cc: Eric Sunshine, Git List, Jeff King, Rafael Ascensao,
	Ævar Arnfjörð Bjarmason

Well, it sounded like we didn't like the ":" extender from another
conversation on this thread. Do you think this patch should move back
in that direction?

On Tue, Feb 5, 2019 at 3:14 AM Junio C Hamano <gitster@pobox.com> wrote:
>
> Nickolai Belakovski <nbelakovski@gmail.com> writes:
>
> > There's been a little back and forth on it, but my understanding is
> > that using the colon separator bypasses the caching mechanism in the
> > atoms, so every instance of "worktree:path" in a format string would
> > require a lookup.
>
> Would that be a problem, though?  You now have a singleton hashmap
> that is a file-scope global not tied to any particular atom, so...?

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v8 0/3]
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (8 preceding siblings ...)
  2019-02-01 22:04   ` [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
@ 2019-02-19  8:31   ` nbelakovski
  2019-02-19  8:31     ` [PATCH v8 1/3] ref-filter: add worktreepath atom nbelakovski
                       ` (3 more replies)
  2019-03-16  1:38   ` [PATCH v9 0/3] nbelakovski
  2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
  11 siblings, 4 replies; 125+ messages in thread
From: nbelakovski @ 2019-02-19  8:31 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

I've made the various cosmetic changes that were suggested, as well as adding tests for 3/3

I don't have a particularly strong opinion on the subject of keeping the atom as "worktreepath"
or changing it to "worktree:path". We did feel earlier in this thread that if we went with
"worktree:path", then "worktree" is somewhat ambiguous, and that discussion led to deciding to
have "worktree" return the path,. After that I chose to name it "worktreepath" because I like to
make things explicit and intuitive.

Travis CI results: https://travis-ci.org/nbelakovski/git/builds/494817576

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: update output to include worktree info
  branch: add worktree info on verbose output

 Documentation/git-branch.txt       | 12 ++++--
 Documentation/git-for-each-ref.txt |  5 +++
 builtin/branch.c                   | 16 ++++++--
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t3200-branch.sh                  |  8 ++--
 t/t3203-branch-output.sh           | 38 +++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 11 ++++++
 7 files changed, 156 insertions(+), 12 deletions(-)

-- 
2.14.2

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v8 1/3] ref-filter: add worktreepath atom
  2019-02-19  8:31   ` [PATCH v8 0/3] nbelakovski
@ 2019-02-19  8:31     ` nbelakovski
  2019-02-19  8:31     ` [PATCH v8 2/3] branch: update output to include worktree info nbelakovski
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-02-19  8:31 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom providing the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-for-each-ref.txt |  5 +++
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 11 ++++++
 3 files changed, 94 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 774cecc7ed..6dcd39f6f6 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -214,6 +214,11 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 422a9c9ae3..05531b7534 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -75,6 +77,27 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct ref_to_worktree_entry {
+	struct hashmap_entry ent; /* must be the first member! */
+	struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
+				      const void *existing_hashmap_entry_to_test,
+				      const void *key,
+				      const void *keydata_aka_refname)
+{
+	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+	const struct ref_to_worktree_entry *k = key;
+	return strcmp(e->wt->head_ref,
+		keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct ref_to_worktree_map {
+	struct hashmap map;
+	struct worktree **worktrees;
+} ref_to_worktree_map;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -480,6 +503,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1525,6 +1549,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
+{
+	int i;
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct ref_to_worktree_entry *entry;
+			entry = xmalloc(sizeof(*entry));
+			entry->wt = worktrees[i];
+			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+			hashmap_add(map, entry);
+		}
+	}
+}
+
+static void lazy_init_worktree_map(void)
+{
+	if (ref_to_worktree_map.worktrees)
+		return;
+
+	ref_to_worktree_map.worktrees = get_worktrees(0);
+	hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
+	populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
+}
+
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct hashmap_entry entry;
+	struct ref_to_worktree_entry *lookup_result;
+
+	lazy_init_worktree_map();
+
+	hashmap_entry_init(&entry, strhash(ref->refname));
+	lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
+
+	if (lookup_result)
+		return xstrdup(lookup_result->wt->path);
+	else
+		return xstrdup("");
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1562,6 +1628,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (!strcmp(name, "worktreepath")) {
+			if (ref->kind == FILTER_REFS_BRANCHES)
+				v->s = get_worktree_path(atom, ref);
+			else
+				v->s = xstrdup("");
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2045,6 +2118,11 @@ void ref_array_clear(struct ref_array *array)
 		free_array_item(array->items[i]);
 	FREE_AND_NULL(array->items);
 	array->nr = array->alloc = 0;
+	if (ref_to_worktree_map.worktrees) {
+		hashmap_free(&(ref_to_worktree_map.map), 1);
+		free_worktrees(ref_to_worktree_map.worktrees);
+		ref_to_worktree_map.worktrees = NULL;
+	}
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..4ad20615d5 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,15 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-EOF &&
+	master: $(pwd)
+	master_worktree: $(pwd)/worktree_dir
+	side: not checked out
+	EOF
+	git worktree add -b master_worktree worktree_dir master &&
+	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v8 2/3] branch: update output to include worktree info
  2019-02-19  8:31   ` [PATCH v8 0/3] nbelakovski
  2019-02-19  8:31     ` [PATCH v8 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-02-19  8:31     ` nbelakovski
  2019-02-21 12:44       ` Jeff King
  2019-02-19  8:31     ` [PATCH v8 3/3] branch: add worktree info on verbose output nbelakovski
  2019-02-21 12:36     ` [PATCH v8 0/3] Jeff King
  3 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-02-19  8:31 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

The output of git branch is modified to mark branches checkout out in a
linked worktree with a "+" and color them in cyan (in contrast to the
current branch, which will still be denoted with a "*" and colored in green)

This is meant to communicate to the user that the branches that are
marked or colored will behave differently from other branches if the user
attempts to check them out or delete them, since branches checked out in
another worktree cannot be checked out or deleted.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt |  6 ++++--
 builtin/branch.c             | 12 ++++++++----
 t/t3200-branch.sh            |  8 ++++----
 t/t3203-branch-output.sh     | 21 +++++++++++++++++++++
 4 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 3bd83a7cbd..f2e5a07d64 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -26,8 +26,10 @@ DESCRIPTION
 -----------
 
 If `--list` is given, or if there are no non-option arguments, existing
-branches are listed; the current branch will be highlighted with an
-asterisk.  Option `-r` causes the remote-tracking branches to be listed,
+branches are listed; the current branch will be highlighted in green and
+marked with an asterisk.  Any branches checked out in linked worktrees will
+be highlighted in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed,
 and option `-a` shows both local and remote branches. If a `<pattern>`
 is given, it is used as a shell wildcard to restrict the output to
 matching branches. If multiple patterns are given, a branch is shown if
diff --git a/builtin/branch.c b/builtin/branch.c
index 1be727209b..c2a86362bb 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..e404f6e23c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -292,7 +292,7 @@ test_expect_success 'git branch --list -v with --abbrev' '
 test_expect_success 'git branch --column' '
 	COLUMNS=81 git branch --column=column >actual &&
 	cat >expected <<\EOF &&
-  a/b/c     bam       foo       l       * master    n         o/p       r
+  a/b/c   + bam       foo       l       * master    n         o/p       r
   abc       bar       j/k       m/m       master2   o/o       q
 EOF
 	test_cmp expected actual
@@ -307,7 +307,7 @@ test_expect_success 'git branch --column with an extremely long branch name' '
 	cat >expected <<EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
@@ -332,7 +332,7 @@ test_expect_success 'git branch with column.*' '
 	git config --unset column.branch &&
 	git config --unset column.ui &&
 	cat >expected <<\EOF &&
-  a/b/c   bam   foo   l   * master    n     o/p   r
+  a/b/c + bam   foo   l   * master    n     o/p   r
   abc     bar   j/k   m/m   master2   o/o   q
 EOF
 	test_cmp expected actual
@@ -349,7 +349,7 @@ test_expect_success 'git branch -v with column.ui ignored' '
 	cat >expected <<\EOF &&
   a/b/c
   abc
-  bam
++ bam
   bar
   foo
   j/k
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ee6787614c..94ab05ad59 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success '"add" a worktree' '
+	mkdir worktree_dir &&
+	git worktree add -b master_worktree worktree_dir master
+'
+
+cat >expect <<'EOF'
+* <GREEN>(HEAD detached from fromtag)<RESET>
+  ambiguous<RESET>
+  branch-one<RESET>
+  branch-two<RESET>
+  master<RESET>
++ <CYAN>master_worktree<RESET>
+  ref-to-branch<RESET> -> branch-one
+  ref-to-remote<RESET> -> origin/branch-one
+EOF
+test_expect_success TTY 'worktree colors correct' '
+	test_terminal git branch >actual.raw &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v8 3/3] branch: add worktree info on verbose output
  2019-02-19  8:31   ` [PATCH v8 0/3] nbelakovski
  2019-02-19  8:31     ` [PATCH v8 1/3] ref-filter: add worktreepath atom nbelakovski
  2019-02-19  8:31     ` [PATCH v8 2/3] branch: update output to include worktree info nbelakovski
@ 2019-02-19  8:31     ` nbelakovski
  2019-02-21 12:59       ` Jeff King
  2019-02-21 12:36     ` [PATCH v8 0/3] Jeff King
  3 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-02-19  8:31 UTC (permalink / raw)
  To: git; +Cc: peff, rafa.almas, gitster, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

To display worktree path for refs checked out in a linked worktree

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt |  6 ++++--
 builtin/branch.c             |  4 ++++
 t/t3203-branch-output.sh     | 21 ++++++++++++++++++++-
 3 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index f2e5a07d64..326a45f648 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -168,8 +168,10 @@ This option is only applicable in non-verbose mode.
 	When in list mode,
 	show sha1 and commit subject line for each head, along with
 	relationship to upstream branch (if any). If given twice, print
-	the name of the upstream branch, as well (see also `git remote
-	show <remote>`).
+	the path of the linked worktree, if applicable (not applicable
+	for current worktree since user's path will already be in current
+	worktree) and the name of the upstream branch, as well (see also
+	`git remote show <remote>`).
 
 -q::
 --quiet::
diff --git a/builtin/branch.c b/builtin/branch.c
index c2a86362bb..0b8ba9e4c5 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addf(&local, " %s ", obname.buf);
 
 		if (filter->verbose > 1)
+		{
+			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
 				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+		}
 		else
 			strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
 
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 94ab05ad59..012ddde7f2 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -241,7 +241,6 @@ test_expect_success 'git branch --format option' '
 '
 
 test_expect_success '"add" a worktree' '
-	mkdir worktree_dir &&
 	git worktree add -b master_worktree worktree_dir master
 '
 
@@ -285,4 +284,24 @@ test_expect_success '--color overrides auto-color' '
 	test_cmp expect.color actual
 '
 
+# This test case has some special code to strip the first 30 characters or so
+# of the output so that we do not have to put commit hashes into the expect
+test_expect_success 'verbose output lists worktree path' '
+	cat >expect <<-EOF &&
+	one
+	one
+	two
+	one
+	two
+	($(pwd)/worktree_dir) two
+	two
+	two
+	EOF
+	git branch -vv >tmp &&
+	SUBSTRLENGTH=$(head -1 tmp | awk "{print index(\$0, \"one\")}") &&
+	awk -v substrlength="$SUBSTRLENGTH" "{print substr(\$0,substrlength,length(\$0))}" <tmp >actual &&
+	test_cmp expect actual
+'
+
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v8 0/3]
  2019-02-19  8:31   ` [PATCH v8 0/3] nbelakovski
                       ` (2 preceding siblings ...)
  2019-02-19  8:31     ` [PATCH v8 3/3] branch: add worktree info on verbose output nbelakovski
@ 2019-02-21 12:36     ` Jeff King
  2019-03-14  6:10       ` Nickolai Belakovski
  3 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2019-02-21 12:36 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Tue, Feb 19, 2019 at 05:31:20PM +0900, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> I've made the various cosmetic changes that were suggested, as well as adding tests for 3/3
> 
> I don't have a particularly strong opinion on the subject of keeping the atom as "worktreepath"
> or changing it to "worktree:path". We did feel earlier in this thread that if we went with
> "worktree:path", then "worktree" is somewhat ambiguous, and that discussion led to deciding to
> have "worktree" return the path,. After that I chose to name it "worktreepath" because I like to
> make things explicit and intuitive.

I am OK with it either way. We have used ":" for some variants (e.g.,
objectsize:disk). But we have also used long single names with related
prefixes (e.g., objectname versus objecttype versus objectsize).

Patch 1 looks good to me. Given that we're on v8 and most of the other
comments are for patches 2 and 3, I think we might consider graduating
it separately if the other two are not ready soon. It's independently
useful, IMHO.

I have a few comments on the others which I'll leave as replies there.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v8 2/3] branch: update output to include worktree info
  2019-02-19  8:31     ` [PATCH v8 2/3] branch: update output to include worktree info nbelakovski
@ 2019-02-21 12:44       ` Jeff King
  2019-03-14  5:45         ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2019-02-21 12:44 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Tue, Feb 19, 2019 at 05:31:22PM +0900, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> The output of git branch is modified to mark branches checkout out in a

s/checkout out/checked out/ ?

> linked worktree with a "+" and color them in cyan (in contrast to the
> current branch, which will still be denoted with a "*" and colored in green)
> 
> This is meant to communicate to the user that the branches that are
> marked or colored will behave differently from other branches if the user
> attempts to check them out or delete them, since branches checked out in
> another worktree cannot be checked out or deleted.

I think this makes sense to have. You cannot "git checkout" such a
marked branch (since it would conflict with the other worktree), and
that alone seems to make it worth marking in the output.

> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
> index 3bd83a7cbd..f2e5a07d64 100644
> --- a/Documentation/git-branch.txt
> +++ b/Documentation/git-branch.txt
> @@ -26,8 +26,10 @@ DESCRIPTION
>  -----------
>  
>  If `--list` is given, or if there are no non-option arguments, existing
> -branches are listed; the current branch will be highlighted with an
> -asterisk.  Option `-r` causes the remote-tracking branches to be listed,
> +branches are listed; the current branch will be highlighted in green and
> +marked with an asterisk.  Any branches checked out in linked worktrees will
> +be highlighted in cyan and marked with a plus sign. Option `-r` causes the
> +remote-tracking branches to be listed,

This makes sense to me.

> -	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
> -		    branch_get_color(BRANCH_COLOR_CURRENT),
> -		    branch_get_color(BRANCH_COLOR_LOCAL));
> +	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
> +			branch_get_color(BRANCH_COLOR_CURRENT),
> +			branch_get_color(BRANCH_COLOR_WORKTREE),
> +			branch_get_color(BRANCH_COLOR_LOCAL));

Makes sense. The long line is ugly. Our format does not support breaking
long lines, though we could break the C string, I think, like:

  strbuf_add(&local,
	     "%%(if)%%(HEAD)"
	       "%%(then)* %s"
	     "%%(else)%(if)%%(worktreepath)"
	       "%%(then)+ %s"
	     "%%(else)"
	       "%%(then)  %s"
	     "%%(end)%%(end)");

That's pretty ugly, too, but it at least shows the conditional
structure.

> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
> index ee6787614c..94ab05ad59 100755
> --- a/t/t3203-branch-output.sh
> +++ b/t/t3203-branch-output.sh
> @@ -240,6 +240,27 @@ test_expect_success 'git branch --format option' '
>  	test_i18ncmp expect actual
>  '
>  
> +test_expect_success '"add" a worktree' '
> +	mkdir worktree_dir &&
> +	git worktree add -b master_worktree worktree_dir master
> +'

This mkdir gets deleted in the next patch. It should just not be added
here.

> +cat >expect <<'EOF'
> +* <GREEN>(HEAD detached from fromtag)<RESET>
> +  ambiguous<RESET>
> +  branch-one<RESET>
> +  branch-two<RESET>
> +  master<RESET>
> ++ <CYAN>master_worktree<RESET>
> +  ref-to-branch<RESET> -> branch-one
> +  ref-to-remote<RESET> -> origin/branch-one
> +EOF
> +test_expect_success TTY 'worktree colors correct' '
> +	test_terminal git branch >actual.raw &&
> +	test_decode_color <actual.raw >actual &&
> +	test_cmp expect actual
> +'

We are not testing the auto-color behavior here, so I think you could
just use "git branch --color >actual.raw" and drop the TTY prerequisite.
That's shorter and simpler, and will let your test run on more
platforms.

-Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v8 3/3] branch: add worktree info on verbose output
  2019-02-19  8:31     ` [PATCH v8 3/3] branch: add worktree info on verbose output nbelakovski
@ 2019-02-21 12:59       ` Jeff King
  2019-03-14  5:58         ` Nickolai Belakovski
  0 siblings, 1 reply; 125+ messages in thread
From: Jeff King @ 2019-02-21 12:59 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, rafa.almas, gitster, avarab

On Tue, Feb 19, 2019 at 05:31:23PM +0900, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> To display worktree path for refs checked out in a linked worktree

This would be a good place to describe why this is useful. :)

I do not have an opinion myself. Patch 2 makes a lot of sense to me, but
I don't know if people would like this one or not. I don't use "-v"
myself, though, so what do I know. :)

> diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
> index f2e5a07d64..326a45f648 100644
> --- a/Documentation/git-branch.txt
> +++ b/Documentation/git-branch.txt
> @@ -168,8 +168,10 @@ This option is only applicable in non-verbose mode.
>  	When in list mode,
>  	show sha1 and commit subject line for each head, along with
>  	relationship to upstream branch (if any). If given twice, print
> -	the name of the upstream branch, as well (see also `git remote
> -	show <remote>`).
> +	the path of the linked worktree, if applicable (not applicable
> +	for current worktree since user's path will already be in current
> +	worktree) and the name of the upstream branch, as well (see also
> +	`git remote show <remote>`).

That parenthetical feels a bit awkward. Maybe:

  ...print the path of the linked worktree (if any) and the name of the
  upstream branch, as well (see also `git remote show <remote>`). Note
  that the current worktree's HEAD will not have its path printed (it
  will always be your current directory).

> diff --git a/builtin/branch.c b/builtin/branch.c
> index c2a86362bb..0b8ba9e4c5 100644
> --- a/builtin/branch.c
> +++ b/builtin/branch.c
> @@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
>  		strbuf_addf(&local, " %s ", obname.buf);
>  
>  		if (filter->verbose > 1)
> +		{
> +			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
> +				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
>  			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
>  				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
>  				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
> +		}

Another unreadable long line (both the one you're adding, and the existing
one!). I don't know if it's worth trying to clean these up, but if we
do, it might be worth hitting the existing ones, too.

I'm OK if that comes as a patch on top later on, though.

> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
> index 94ab05ad59..012ddde7f2 100755
> --- a/t/t3203-branch-output.sh
> +++ b/t/t3203-branch-output.sh
> @@ -241,7 +241,6 @@ test_expect_success 'git branch --format option' '
>  '
>  
>  test_expect_success '"add" a worktree' '
> -	mkdir worktree_dir &&
>  	git worktree add -b master_worktree worktree_dir master
>  '

Here's that mysterious mkdir going away. :)

> @@ -285,4 +284,24 @@ test_expect_success '--color overrides auto-color' '
>  	test_cmp expect.color actual
>  '
>  
> +# This test case has some special code to strip the first 30 characters or so
> +# of the output so that we do not have to put commit hashes into the expect
> +test_expect_success 'verbose output lists worktree path' '
> +	cat >expect <<-EOF &&
> +	one
> +	one
> +	two
> +	one
> +	two
> +	($(pwd)/worktree_dir) two
> +	two
> +	two
> +	EOF
> +	git branch -vv >tmp &&
> +	SUBSTRLENGTH=$(head -1 tmp | awk "{print index(\$0, \"one\")}") &&
> +	awk -v substrlength="$SUBSTRLENGTH" "{print substr(\$0,substrlength,length(\$0))}" <tmp >actual &&
> +	test_cmp expect actual
> +'

It's hard to tell if this awk is doing the right thing. I guess it works
because git-branch tries to line up all of the hashes. I think the
result might be easier to verify if we simply blanked the hashes.
Unfortunately the output is actually pretty hard to parse. Since there
are only two tip commits, perhaps it would not be so bad to just do
something like this:

diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index 012ddde7f2..8065279be6 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -284,22 +284,20 @@ test_expect_success '--color overrides auto-color' '
 	test_cmp expect.color actual
 '
 
-# This test case has some special code to strip the first 30 characters or so
-# of the output so that we do not have to put commit hashes into the expect
 test_expect_success 'verbose output lists worktree path' '
+	one=$(git rev-parse --short HEAD) &&
+	two=$(git rev-parse --short master) &&
 	cat >expect <<-EOF &&
-	one
-	one
-	two
-	one
-	two
-	($(pwd)/worktree_dir) two
-	two
-	two
+	* (HEAD detached from fromtag) $one one
+	  ambiguous                    $one one
+	  branch-one                   $two two
+	  branch-two                   $one one
+	  master                       $two two
+	+ master_worktree              $two ($(pwd)/worktree_dir) two
+	  ref-to-branch                $two two
+	  ref-to-remote                $two two
 	EOF
-	git branch -vv >tmp &&
-	SUBSTRLENGTH=$(head -1 tmp | awk "{print index(\$0, \"one\")}") &&
-	awk -v substrlength="$SUBSTRLENGTH" "{print substr(\$0,substrlength,length(\$0))}" <tmp >actual &&
+	git branch -vv >actual &&
 	test_cmp expect actual
 '
 

I don't like how it depends on the space alignment of the branches, but
I do like that you can clearly see which branch is being annotated.

-Peff

^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v8 2/3] branch: update output to include worktree info
  2019-02-21 12:44       ` Jeff King
@ 2019-03-14  5:45         ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-03-14  5:45 UTC (permalink / raw)
  To: Jeff King
  Cc: Git List, Rafael Ascensão, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Thu, Feb 21, 2019 at 4:44 AM Jeff King <peff@peff.net> wrote:
>
> On Tue, Feb 19, 2019 at 05:31:22PM +0900, nbelakovski@gmail.com wrote:
>
> > From: Nickolai Belakovski <nbelakovski@gmail.com>
> >
> > The output of git branch is modified to mark branches checkout out in a
>
> s/checkout out/checked out/ ?
>
Yes, thanks
>
> > -     strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
> > -                 branch_get_color(BRANCH_COLOR_CURRENT),
> > -                 branch_get_color(BRANCH_COLOR_LOCAL));
> > +     strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
> > +                     branch_get_color(BRANCH_COLOR_CURRENT),
> > +                     branch_get_color(BRANCH_COLOR_WORKTREE),
> > +                     branch_get_color(BRANCH_COLOR_LOCAL));
>
> Makes sense. The long line is ugly. Our format does not support breaking
> long lines, though we could break the C string, I think, like:
>
>   strbuf_add(&local,
>              "%%(if)%%(HEAD)"
>                "%%(then)* %s"
>              "%%(else)%(if)%%(worktreepath)"
>                "%%(then)+ %s"
>              "%%(else)"
>                "%%(then)  %s"
>              "%%(end)%%(end)");
>
> That's pretty ugly, too, but it at least shows the conditional
> structure.
True, but other lines within that file are about as long. I'd feel
that I should make all of them reflect the conditional structure if
I'm going to make one of them reflect it. Granted none of the others
have nested if's, but personally I think it's OK as is. The nested if
is short enough.
>
> >
> > +test_expect_success '"add" a worktree' '
> > +     mkdir worktree_dir &&
> > +     git worktree add -b master_worktree worktree_dir master
> > +'
>
> This mkdir gets deleted in the next patch. It should just not be added
> here.
Whoops, removed
>
> > +cat >expect <<'EOF'
> > +* <GREEN>(HEAD detached from fromtag)<RESET>
> > +  ambiguous<RESET>
> > +  branch-one<RESET>
> > +  branch-two<RESET>
> > +  master<RESET>
> > ++ <CYAN>master_worktree<RESET>
> > +  ref-to-branch<RESET> -> branch-one
> > +  ref-to-remote<RESET> -> origin/branch-one
> > +EOF
> > +test_expect_success TTY 'worktree colors correct' '
> > +     test_terminal git branch >actual.raw &&
> > +     test_decode_color <actual.raw >actual &&
> > +     test_cmp expect actual
> > +'
>
> We are not testing the auto-color behavior here, so I think you could
> just use "git branch --color >actual.raw" and drop the TTY prerequisite.
> That's shorter and simpler, and will let your test run on more
> platforms.
>
Done locally, will be part of v9

> -Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v8 3/3] branch: add worktree info on verbose output
  2019-02-21 12:59       ` Jeff King
@ 2019-03-14  5:58         ` Nickolai Belakovski
  2019-03-18  2:12           ` Junio C Hamano
  0 siblings, 1 reply; 125+ messages in thread
From: Nickolai Belakovski @ 2019-03-14  5:58 UTC (permalink / raw)
  To: Jeff King
  Cc: Git List, Rafael Ascensão, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

On Thu, Feb 21, 2019 at 4:59 AM Jeff King <peff@peff.net> wrote:
>
> On Tue, Feb 19, 2019 at 05:31:23PM +0900, nbelakovski@gmail.com wrote:
>
> > From: Nickolai Belakovski <nbelakovski@gmail.com>
> >
> > To display worktree path for refs checked out in a linked worktree
>
> This would be a good place to describe why this is useful. :)
>
> I do not have an opinion myself. Patch 2 makes a lot of sense to me, but
> I don't know if people would like this one or not. I don't use "-v"
> myself, though, so what do I know. :)
I threw this one in because I thought it wouldn't be clear to the
average user why some
branches are in cyan. By putting the worktree path in cyan on the next
level of output
I thought this would help the user make the connection, but actually I
don't have strong
feelings about this one.
>
> > diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
> > index f2e5a07d64..326a45f648 100644
> > --- a/Documentation/git-branch.txt
> > +++ b/Documentation/git-branch.txt
> > @@ -168,8 +168,10 @@ This option is only applicable in non-verbose mode.
> >       When in list mode,
> >       show sha1 and commit subject line for each head, along with
> >       relationship to upstream branch (if any). If given twice, print
> > -     the name of the upstream branch, as well (see also `git remote
> > -     show <remote>`).
> > +     the path of the linked worktree, if applicable (not applicable
> > +     for current worktree since user's path will already be in current
> > +     worktree) and the name of the upstream branch, as well (see also
> > +     `git remote show <remote>`).
>
> That parenthetical feels a bit awkward. Maybe:
>
>   ...print the path of the linked worktree (if any) and the name of the
>   upstream branch, as well (see also `git remote show <remote>`). Note
>   that the current worktree's HEAD will not have its path printed (it
>   will always be your current directory).
Sure I can make that change
>
> > diff --git a/builtin/branch.c b/builtin/branch.c
> > index c2a86362bb..0b8ba9e4c5 100644
> > --- a/builtin/branch.c
> > +++ b/builtin/branch.c
> > @@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
> >               strbuf_addf(&local, " %s ", obname.buf);
> >
> >               if (filter->verbose > 1)
> > +             {
> > +                     strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
> > +                                 branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
> >                       strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
> >                                   "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
> >                                   branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
> > +             }
>
> Another unreadable long line (both the one you're adding, and the existing
> one!). I don't know if it's worth trying to clean these up, but if we
> do, it might be worth hitting the existing ones, too.
>
> I'm OK if that comes as a patch on top later on, though.
Agreed, but there's enough lines like this that it'll just look
inconsistent if only one were broken up.
>
>
> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
> index 012ddde7f2..8065279be6 100755
> --- a/t/t3203-branch-output.sh
> +++ b/t/t3203-branch-output.sh
> @@ -284,22 +284,20 @@ test_expect_success '--color overrides auto-color' '
>         test_cmp expect.color actual
>  '
>
> -# This test case has some special code to strip the first 30 characters or so
> -# of the output so that we do not have to put commit hashes into the expect
>  test_expect_success 'verbose output lists worktree path' '
> +       one=$(git rev-parse --short HEAD) &&
> +       two=$(git rev-parse --short master) &&
>         cat >expect <<-EOF &&
> -       one
> -       one
> -       two
> -       one
> -       two
> -       ($(pwd)/worktree_dir) two
> -       two
> -       two
> +       * (HEAD detached from fromtag) $one one
> +         ambiguous                    $one one
> +         branch-one                   $two two
> +         branch-two                   $one one
> +         master                       $two two
> +       + master_worktree              $two ($(pwd)/worktree_dir) two
> +         ref-to-branch                $two two
> +         ref-to-remote                $two two
>         EOF
> -       git branch -vv >tmp &&
> -       SUBSTRLENGTH=$(head -1 tmp | awk "{print index(\$0, \"one\")}") &&
> -       awk -v substrlength="$SUBSTRLENGTH" "{print substr(\$0,substrlength,length(\$0))}" <tmp >actual &&
> +       git branch -vv >actual &&
>         test_cmp expect actual
>  '
>
>
> I don't like how it depends on the space alignment of the branches, but
> I do like that you can clearly see which branch is being annotated.
Thanks for the suggestion. While I'm kinda proud of my awk thing, I
think yours is a lot easier to read. Will add.
>
> -Peff

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v8 0/3]
  2019-02-21 12:36     ` [PATCH v8 0/3] Jeff King
@ 2019-03-14  6:10       ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-03-14  6:10 UTC (permalink / raw)
  To: Jeff King
  Cc: Git List, Rafael Ascensão, Junio C Hamano,
	Ævar Arnfjörð Bjarmason

>
> Patch 1 looks good to me. Given that we're on v8 and most of the other
> comments are for patches 2 and 3, I think we might consider graduating
> it separately if the other two are not ready soon. It's independently
> useful, IMHO.

Patch 2 was my main motivation, so it would be nice to get it in
together with 1 :)
Patch 3, like I said in the thread on that one I don't have strong
feeling about it. It was an attempt to provide a connection between
the new cyan output and its intent, as opposed to having the user
guess, but I think anyone who's using a worktree will figure it out
sooner or later, and anyone not using a worktree will be unaffected.

I'm willing to keep going with comments on patch 2. I can't imagine it
would take many more revisions as it's much more straightforward than
patch 1, it's basically just modifying one line of branch.c. If we
decide to drop patch 3 fine with me.

I'll send in v9 with the latest changes for both 2 and 3 sometime
tomorrow unless I hear otherwise.

Thanks for the feedback.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v9 0/3]
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (9 preceding siblings ...)
  2019-02-19  8:31   ` [PATCH v8 0/3] nbelakovski
@ 2019-03-16  1:38   ` nbelakovski
  2019-03-16  1:38     ` [PATCH v9 1/3] ref-filter: add worktreepath atom nbelakovski
                       ` (3 more replies)
  2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
  11 siblings, 4 replies; 125+ messages in thread
From: nbelakovski @ 2019-03-16  1:38 UTC (permalink / raw)
  To: git; +Cc: peff, gitster, rafa.almas, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Cleanup on 2/3 and 3/3

To reiterate from elsewhere in the thread, I'd really like to get 1/3 and 2/3 in together.
For 3/3 I'm basically indifferent. I see some value in it, but I also think it clutters up
the verbose output, so I could understand if there's a lack of interest in it.

Also, I changed my strategy for how I updated tests that were impacted by these changes.
Instead of updating the impacted tests with the new expected output, I went back and made various
tests more self-contained. This seemed like a more sensible strategy from the standpoint
of decoupling tests and limiting scope of tests.

Travis-CI results: https://travis-ci.org/nbelakovski/git/builds/506853143

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: update output to include worktree info
  branch: add worktree info on verbose output

 Documentation/git-branch.txt       | 12 ++++--
 Documentation/git-for-each-ref.txt |  5 +++
 builtin/branch.c                   | 16 ++++++--
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t3200-branch.sh                  | 16 +++++---
 t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-
 t/t6302-for-each-ref-filter.sh     | 13 +++++++
 7 files changed, 168 insertions(+), 15 deletions(-)

-- 
2.14.2


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v9 1/3] ref-filter: add worktreepath atom
  2019-03-16  1:38   ` [PATCH v9 0/3] nbelakovski
@ 2019-03-16  1:38     ` nbelakovski
  2019-03-16  1:38     ` [PATCH v9 2/3] branch: update output to include worktree info nbelakovski
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-03-16  1:38 UTC (permalink / raw)
  To: git; +Cc: peff, gitster, rafa.almas, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom providing the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-for-each-ref.txt |  5 +++
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 13 +++++++
 3 files changed, 96 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 774cecc7ed..6dcd39f6f6 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -214,6 +214,11 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 3aca105307..79cfec914a 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -75,6 +77,27 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct ref_to_worktree_entry {
+	struct hashmap_entry ent; /* must be the first member! */
+	struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
+				      const void *existing_hashmap_entry_to_test,
+				      const void *key,
+				      const void *keydata_aka_refname)
+{
+	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+	const struct ref_to_worktree_entry *k = key;
+	return strcmp(e->wt->head_ref,
+		keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct ref_to_worktree_map {
+	struct hashmap map;
+	struct worktree **worktrees;
+} ref_to_worktree_map;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -480,6 +503,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1529,6 +1553,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
+{
+	int i;
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct ref_to_worktree_entry *entry;
+			entry = xmalloc(sizeof(*entry));
+			entry->wt = worktrees[i];
+			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+			hashmap_add(map, entry);
+		}
+	}
+}
+
+static void lazy_init_worktree_map(void)
+{
+	if (ref_to_worktree_map.worktrees)
+		return;
+
+	ref_to_worktree_map.worktrees = get_worktrees(0);
+	hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
+	populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
+}
+
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct hashmap_entry entry;
+	struct ref_to_worktree_entry *lookup_result;
+
+	lazy_init_worktree_map();
+
+	hashmap_entry_init(&entry, strhash(ref->refname));
+	lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
+
+	if (lookup_result)
+		return xstrdup(lookup_result->wt->path);
+	else
+		return xstrdup("");
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1566,6 +1632,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (!strcmp(name, "worktreepath")) {
+			if (ref->kind == FILTER_REFS_BRANCHES)
+				v->s = get_worktree_path(atom, ref);
+			else
+				v->s = xstrdup("");
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2049,6 +2122,11 @@ void ref_array_clear(struct ref_array *array)
 		free_array_item(array->items[i]);
 	FREE_AND_NULL(array->items);
 	array->nr = array->alloc = 0;
+	if (ref_to_worktree_map.worktrees) {
+		hashmap_free(&(ref_to_worktree_map.map), 1);
+		free_worktrees(ref_to_worktree_map.worktrees);
+		ref_to_worktree_map.worktrees = NULL;
+	}
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..35408d53fd 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,17 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-EOF &&
+	master: $(pwd)
+	master_worktree: $(pwd)/worktree_dir
+	side: not checked out
+	EOF
+	git worktree add -b master_worktree worktree_dir master &&
+	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
+	rm -r worktree_dir &&
+	git worktree prune &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v9 2/3] branch: update output to include worktree info
  2019-03-16  1:38   ` [PATCH v9 0/3] nbelakovski
  2019-03-16  1:38     ` [PATCH v9 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-03-16  1:38     ` nbelakovski
  2019-03-16  1:38     ` [PATCH v9 3/3] branch: add worktree info on verbose output nbelakovski
  2019-03-18  5:30     ` [PATCH v9 0/3] Junio C Hamano
  3 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-03-16  1:38 UTC (permalink / raw)
  To: git; +Cc: peff, gitster, rafa.almas, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

The output of git branch is modified to mark branches checked out in a
linked worktree with a "+" and color them in cyan (in contrast to the
current branch, which will still be denoted with a "*" and colored in green)

This is meant to communicate to the user that the branches that are
marked or colored will behave differently from other branches if the user
attempts to check them out or delete them, since branches checked out in
another worktree cannot be checked out or deleted.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt |  6 ++++--
 builtin/branch.c             | 12 ++++++++----
 t/t3200-branch.sh            | 16 +++++++++++-----
 t/t3203-branch-output.sh     | 24 ++++++++++++++++++++++--
 4 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0cd87ddeff..7d18dffc4b 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -26,8 +26,10 @@ DESCRIPTION
 -----------
 
 If `--list` is given, or if there are no non-option arguments, existing
-branches are listed; the current branch will be highlighted with an
-asterisk.  Option `-r` causes the remote-tracking branches to be listed,
+branches are listed; the current branch will be highlighted in green and
+marked with an asterisk.  Any branches checked out in linked worktrees will
+be highlighted in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed,
 and option `-a` shows both local and remote branches. If a `<pattern>`
 is given, it is used as a shell wildcard to restrict the output to
 matching branches. If multiple patterns are given, a branch is shown if
diff --git a/builtin/branch.c b/builtin/branch.c
index 4c83055730..350b039063 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..88719cc02c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -202,18 +202,22 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
 	git worktree add -f bazdir2 baz &&
 	git branch -M baz bam &&
 	test $(git -C bazdir rev-parse --abbrev-ref HEAD) = bam &&
-	test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam
+	test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&
+	rm -r bazdir bazdir2 &&
+	git worktree prune
 '
 
 test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '
 	git checkout -b baz &&
-	git worktree add -f bazdir3 baz &&
+	git worktree add -f bazdir baz &&
 	(
-		cd bazdir3 &&
+		cd bazdir &&
 		git branch -M baz bam &&
 		test $(git rev-parse --abbrev-ref HEAD) = bam
 	) &&
-	test $(git rev-parse --abbrev-ref HEAD) = bam
+	test $(git rev-parse --abbrev-ref HEAD) = bam &&
+	rm -r bazdir &&
+	git worktree prune
 '
 
 test_expect_success 'git branch -M master should work when master is checked out' '
@@ -774,7 +778,9 @@ test_expect_success 'test deleting branch without config' '
 test_expect_success 'deleting currently checked out branch fails' '
 	git worktree add -b my7 my7 &&
 	test_must_fail git -C my7 branch -d my7 &&
-	test_must_fail git branch -d my7
+	test_must_fail git branch -d my7 &&
+	rm -r my7 &&
+	git worktree prune
 '
 
 test_expect_success 'test --track without .fetch entries' '
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index be55148930..ceb74e0826 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -136,11 +136,13 @@ test_expect_success 'git branch `--show-current` works properly with worktrees'
 	branch-two
 	EOF
 	git checkout branch-one &&
-	git worktree add worktree branch-two &&
+	git worktree add worktree_dir branch-two &&
 	{
 		git branch --show-current &&
-		git -C worktree branch --show-current
+		git -C worktree_dir branch --show-current
 	} >actual &&
+	rm -r worktree_dir &&
+	git worktree prune &&
 	test_cmp expect actual
 '
 
@@ -284,6 +286,24 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success 'worktree colors correct' '
+	cat >expect <<-EOF &&
+	* <GREEN>(HEAD detached from fromtag)<RESET>
+	  ambiguous<RESET>
+	  branch-one<RESET>
+	+ <CYAN>branch-two<RESET>
+	  master<RESET>
+	  ref-to-branch<RESET> -> branch-one
+	  ref-to-remote<RESET> -> origin/branch-one
+	EOF
+	git worktree add worktree_dir branch-two &&
+	git branch --color >actual.raw &&
+	rm -r worktree_dir &&
+	git worktree prune &&
+	test_decode_color <actual.raw >actual &&
+	test_cmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v9 3/3] branch: add worktree info on verbose output
  2019-03-16  1:38   ` [PATCH v9 0/3] nbelakovski
  2019-03-16  1:38     ` [PATCH v9 1/3] ref-filter: add worktreepath atom nbelakovski
  2019-03-16  1:38     ` [PATCH v9 2/3] branch: update output to include worktree info nbelakovski
@ 2019-03-16  1:38     ` nbelakovski
  2019-03-18 12:10       ` SZEDER Gábor
  2019-03-18  5:30     ` [PATCH v9 0/3] Junio C Hamano
  3 siblings, 1 reply; 125+ messages in thread
From: nbelakovski @ 2019-03-16  1:38 UTC (permalink / raw)
  To: git; +Cc: peff, gitster, rafa.almas, avarab, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

To display worktree path for refs checked out in a linked worktree

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt |  6 ++++--
 builtin/branch.c             |  4 ++++
 t/t3203-branch-output.sh     | 19 +++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 7d18dffc4b..d11d00583a 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -172,8 +172,10 @@ This option is only applicable in non-verbose mode.
 	When in list mode,
 	show sha1 and commit subject line for each head, along with
 	relationship to upstream branch (if any). If given twice, print
-	the name of the upstream branch, as well (see also `git remote
-	show <remote>`).
+	the path of the linked worktree (if any) and the name of the upstream
+	branch, as well (see also `git remote show <remote>`).  Note that the
+	current worktree's HEAD will not have its path printed (it will always
+	be your current directory).
 
 -q::
 --quiet::
diff --git a/builtin/branch.c b/builtin/branch.c
index 350b039063..3d1872babc 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addf(&local, " %s ", obname.buf);
 
 		if (filter->verbose > 1)
+		{
+			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
 				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+		}
 		else
 			strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
 
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index ceb74e0826..e5dc23e225 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -328,4 +328,23 @@ test_expect_success '--color overrides auto-color' '
 	test_cmp expect.color actual
 '
 
+test_expect_success 'verbose output lists worktree path' '
+	one=$(git rev-parse --short HEAD) &&
+	two=$(git rev-parse --short master) &&
+	cat >expect <<-EOF &&
+	* (HEAD detached from fromtag) $one one
+	  ambiguous                    $one one
+	  branch-one                   $two two
+	+ branch-two                   $one ($(pwd)/worktree_dir) one
+	  master                       $two two
+	  ref-to-branch                $two two
+	  ref-to-remote                $two two
+	EOF
+	git worktree add worktree_dir branch-two &&
+	git branch -vv >actual &&
+	rm -r worktree_dir &&
+	git worktree prune &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v8 3/3] branch: add worktree info on verbose output
  2019-03-14  5:58         ` Nickolai Belakovski
@ 2019-03-18  2:12           ` Junio C Hamano
  0 siblings, 0 replies; 125+ messages in thread
From: Junio C Hamano @ 2019-03-18  2:12 UTC (permalink / raw)
  To: Nickolai Belakovski
  Cc: Jeff King, Git List, Rafael Ascensão,
	Ævar Arnfjörð Bjarmason

Nickolai Belakovski <nbelakovski@gmail.com> writes:

> On Thu, Feb 21, 2019 at 4:59 AM Jeff King <peff@peff.net> wrote:
>>
>> On Tue, Feb 19, 2019 at 05:31:23PM +0900, nbelakovski@gmail.com wrote:
>>
>> > From: Nickolai Belakovski <nbelakovski@gmail.com>
>> >
>> > To display worktree path for refs checked out in a linked worktree
>>
>> This would be a good place to describe why this is useful. :)
>>
>> I do not have an opinion myself. Patch 2 makes a lot of sense to me, but
>> I don't know if people would like this one or not. I don't use "-v"
>> myself, though, so what do I know. :)
> I threw this one in because I thought it wouldn't be clear to the
> average user why some
> branches are in cyan. By putting the worktree path in cyan on the next
> level of output
> I thought this would help the user make the connection, but actually I
> don't have strong
> feelings about this one.

I am moderately skeptical on 2/3, but together with 3/3 I think it
makes sense.

The fact that two branch names painted in different colors from the
other ones, without knowing which one is checked out in what
worktree, will not give enough information to allow the user to
actually start working on one of them.  All the user gets with 2/3
alone is "don't touch it---it is used elsewhere and I am not telling
where", isn't it?



^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v9 0/3]
  2019-03-16  1:38   ` [PATCH v9 0/3] nbelakovski
                       ` (2 preceding siblings ...)
  2019-03-16  1:38     ` [PATCH v9 3/3] branch: add worktree info on verbose output nbelakovski
@ 2019-03-18  5:30     ` Junio C Hamano
  3 siblings, 0 replies; 125+ messages in thread
From: Junio C Hamano @ 2019-03-18  5:30 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, rafa.almas, avarab

nbelakovski@gmail.com writes:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
>
> Cleanup on 2/3 and 3/3

I'll have to re-read the test part myself to see what you meant by
the "strategy for updating tests" and if it makes sense, but what
you wrote as the goal and approach in the cover letter all sounded
sensible.

Thanks, will requeue.  

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v9 3/3] branch: add worktree info on verbose output
  2019-03-16  1:38     ` [PATCH v9 3/3] branch: add worktree info on verbose output nbelakovski
@ 2019-03-18 12:10       ` SZEDER Gábor
  0 siblings, 0 replies; 125+ messages in thread
From: SZEDER Gábor @ 2019-03-18 12:10 UTC (permalink / raw)
  To: nbelakovski; +Cc: git, peff, gitster, rafa.almas, avarab

On Fri, Mar 15, 2019 at 06:38:07PM -0700, nbelakovski@gmail.com wrote:
> diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
> index ceb74e0826..e5dc23e225 100755
> --- a/t/t3203-branch-output.sh
> +++ b/t/t3203-branch-output.sh
> @@ -328,4 +328,23 @@ test_expect_success '--color overrides auto-color' '
>  	test_cmp expect.color actual
>  '
>  
> +test_expect_success 'verbose output lists worktree path' '
> +	one=$(git rev-parse --short HEAD) &&
> +	two=$(git rev-parse --short master) &&
> +	cat >expect <<-EOF &&
> +	* (HEAD detached from fromtag) $one one

This 'HEAD detached from ..." message is translated ...

> +	  ambiguous                    $one one
> +	  branch-one                   $two two
> +	+ branch-two                   $one ($(pwd)/worktree_dir) one
> +	  master                       $two two
> +	  ref-to-branch                $two two
> +	  ref-to-remote                $two two
> +	EOF
> +	git worktree add worktree_dir branch-two &&
> +	git branch -vv >actual &&
> +	rm -r worktree_dir &&
> +	git worktree prune &&
> +	test_cmp expect actual

... therefore here you should use 'test_i18ncmp', as otherwise the
GETTEXT_POISON test run fails.

> +'
> +
>  test_done
> -- 
> 2.14.2
> 

^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v10 0/3]
  2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
                     ` (10 preceding siblings ...)
  2019-03-16  1:38   ` [PATCH v9 0/3] nbelakovski
@ 2019-04-29  5:19   ` nbelakovski
  2019-04-29  5:19     ` [PATCH v10 1/3] ref-filter: add worktreepath atom nbelakovski
                       ` (4 more replies)
  11 siblings, 5 replies; 125+ messages in thread
From: nbelakovski @ 2019-04-29  5:19 UTC (permalink / raw)
  To: git; +Cc: szeder.dev, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Added test_i18ncmp per instructions from Szeder

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.

Travis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210

Nickolai Belakovski (3):
  ref-filter: add worktreepath atom
  branch: update output to include worktree info
  branch: add worktree info on verbose output

 Documentation/git-branch.txt       | 12 ++++--
 Documentation/git-for-each-ref.txt |  5 +++
 builtin/branch.c                   | 16 ++++++--
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t3200-branch.sh                  | 16 +++++---
 t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-
 t/t6302-for-each-ref-filter.sh     | 13 +++++++
 7 files changed, 168 insertions(+), 15 deletions(-)

-- 
2.14.2


^ permalink raw reply	[flat|nested] 125+ messages in thread

* [PATCH v10 1/3] ref-filter: add worktreepath atom
  2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
@ 2019-04-29  5:19     ` nbelakovski
  2019-04-29  5:19     ` [PATCH v10 2/3] branch: update output to include worktree info nbelakovski
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-04-29  5:19 UTC (permalink / raw)
  To: git; +Cc: szeder.dev, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

Add an atom providing the path of the linked worktree where this ref is
checked out, if it is checked out in any linked worktrees, and empty
string otherwise.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-for-each-ref.txt |  5 +++
 ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
 t/t6302-for-each-ref-filter.sh     | 13 +++++++
 3 files changed, 96 insertions(+)

diff --git a/Documentation/git-for-each-ref.txt b/Documentation/git-for-each-ref.txt
index 774cecc7ed..6dcd39f6f6 100644
--- a/Documentation/git-for-each-ref.txt
+++ b/Documentation/git-for-each-ref.txt
@@ -214,6 +214,11 @@ symref::
 	`:lstrip` and `:rstrip` options in the same way as `refname`
 	above.
 
+worktreepath::
+	The absolute path to the worktree in which the ref is checked
+	out, if it is checked out in any linked worktree. Empty string
+	otherwise.
+
 In addition to the above, for commit and tag objects, the header
 field names (`tree`, `parent`, `object`, `type`, and `tag`) can
 be used to specify the value in the header field.
diff --git a/ref-filter.c b/ref-filter.c
index 8d11a94cbd..13984fa8ca 100644
--- a/ref-filter.c
+++ b/ref-filter.c
@@ -20,6 +20,8 @@
 #include "commit-slab.h"
 #include "commit-graph.h"
 #include "commit-reach.h"
+#include "worktree.h"
+#include "hashmap.h"
 
 static struct ref_msg {
 	const char *gone;
@@ -75,6 +77,27 @@ static struct expand_data {
 	struct object_info info;
 } oi, oi_deref;
 
+struct ref_to_worktree_entry {
+	struct hashmap_entry ent; /* must be the first member! */
+	struct worktree *wt; /* key is wt->head_ref */
+};
+
+static int ref_to_worktree_map_cmpfnc(const void *unused_lookupdata,
+				      const void *existing_hashmap_entry_to_test,
+				      const void *key,
+				      const void *keydata_aka_refname)
+{
+	const struct ref_to_worktree_entry *e = existing_hashmap_entry_to_test;
+	const struct ref_to_worktree_entry *k = key;
+	return strcmp(e->wt->head_ref,
+		keydata_aka_refname ? keydata_aka_refname : k->wt->head_ref);
+}
+
+static struct ref_to_worktree_map {
+	struct hashmap map;
+	struct worktree **worktrees;
+} ref_to_worktree_map;
+
 /*
  * An atom is a valid field atom listed below, possibly prefixed with
  * a "*" to denote deref_tag().
@@ -480,6 +503,7 @@ static struct {
 	{ "flag", SOURCE_NONE },
 	{ "HEAD", SOURCE_NONE, FIELD_STR, head_atom_parser },
 	{ "color", SOURCE_NONE, FIELD_STR, color_atom_parser },
+	{ "worktreepath", SOURCE_NONE },
 	{ "align", SOURCE_NONE, FIELD_STR, align_atom_parser },
 	{ "end", SOURCE_NONE },
 	{ "if", SOURCE_NONE, FIELD_STR, if_atom_parser },
@@ -1529,6 +1553,48 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj
 	return 0;
 }
 
+static void populate_worktree_map(struct hashmap *map, struct worktree **worktrees)
+{
+	int i;
+
+	for (i = 0; worktrees[i]; i++) {
+		if (worktrees[i]->head_ref) {
+			struct ref_to_worktree_entry *entry;
+			entry = xmalloc(sizeof(*entry));
+			entry->wt = worktrees[i];
+			hashmap_entry_init(entry, strhash(worktrees[i]->head_ref));
+
+			hashmap_add(map, entry);
+		}
+	}
+}
+
+static void lazy_init_worktree_map(void)
+{
+	if (ref_to_worktree_map.worktrees)
+		return;
+
+	ref_to_worktree_map.worktrees = get_worktrees(0);
+	hashmap_init(&(ref_to_worktree_map.map), ref_to_worktree_map_cmpfnc, NULL, 0);
+	populate_worktree_map(&(ref_to_worktree_map.map), ref_to_worktree_map.worktrees);
+}
+
+static char *get_worktree_path(const struct used_atom *atom, const struct ref_array_item *ref)
+{
+	struct hashmap_entry entry;
+	struct ref_to_worktree_entry *lookup_result;
+
+	lazy_init_worktree_map();
+
+	hashmap_entry_init(&entry, strhash(ref->refname));
+	lookup_result = hashmap_get(&(ref_to_worktree_map.map), &entry, ref->refname);
+
+	if (lookup_result)
+		return xstrdup(lookup_result->wt->path);
+	else
+		return xstrdup("");
+}
+
 /*
  * Parse the object referred by ref, and grab needed value.
  */
@@ -1566,6 +1632,13 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err)
 
 		if (starts_with(name, "refname"))
 			refname = get_refname(atom, ref);
+		else if (!strcmp(name, "worktreepath")) {
+			if (ref->kind == FILTER_REFS_BRANCHES)
+				v->s = get_worktree_path(atom, ref);
+			else
+				v->s = xstrdup("");
+			continue;
+		}
 		else if (starts_with(name, "symref"))
 			refname = get_symref(atom, ref);
 		else if (starts_with(name, "upstream")) {
@@ -2049,6 +2122,11 @@ void ref_array_clear(struct ref_array *array)
 		free_array_item(array->items[i]);
 	FREE_AND_NULL(array->items);
 	array->nr = array->alloc = 0;
+	if (ref_to_worktree_map.worktrees) {
+		hashmap_free(&(ref_to_worktree_map.map), 1);
+		free_worktrees(ref_to_worktree_map.worktrees);
+		ref_to_worktree_map.worktrees = NULL;
+	}
 }
 
 static void do_merge_filter(struct ref_filter_cbdata *ref_cbdata)
diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh
index fc067ed672..35408d53fd 100755
--- a/t/t6302-for-each-ref-filter.sh
+++ b/t/t6302-for-each-ref-filter.sh
@@ -441,4 +441,17 @@ test_expect_success '--merged is incompatible with --no-merged' '
 	test_must_fail git for-each-ref --merged HEAD --no-merged HEAD
 '
 
+test_expect_success 'validate worktree atom' '
+	cat >expect <<-EOF &&
+	master: $(pwd)
+	master_worktree: $(pwd)/worktree_dir
+	side: not checked out
+	EOF
+	git worktree add -b master_worktree worktree_dir master &&
+	git for-each-ref --format="%(refname:short): %(if)%(worktreepath)%(then)%(worktreepath)%(else)not checked out%(end)" refs/heads/ >actual &&
+	rm -r worktree_dir &&
+	git worktree prune &&
+	test_cmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v10 2/3] branch: update output to include worktree info
  2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
  2019-04-29  5:19     ` [PATCH v10 1/3] ref-filter: add worktreepath atom nbelakovski
@ 2019-04-29  5:19     ` nbelakovski
  2019-04-29  5:19     ` [PATCH v10 3/3] branch: add worktree info on verbose output nbelakovski
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-04-29  5:19 UTC (permalink / raw)
  To: git; +Cc: szeder.dev, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

The output of git branch is modified to mark branches checked out in a
linked worktree with a "+" and color them in cyan (in contrast to the
current branch, which will still be denoted with a "*" and colored in green)

This is meant to communicate to the user that the branches that are
marked or colored will behave differently from other branches if the user
attempts to check them out or delete them, since branches checked out in
another worktree cannot be checked out or deleted.

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt |  6 ++++--
 builtin/branch.c             | 12 ++++++++----
 t/t3200-branch.sh            | 16 +++++++++++-----
 t/t3203-branch-output.sh     | 24 ++++++++++++++++++++++--
 4 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 0cd87ddeff..7d18dffc4b 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -26,8 +26,10 @@ DESCRIPTION
 -----------
 
 If `--list` is given, or if there are no non-option arguments, existing
-branches are listed; the current branch will be highlighted with an
-asterisk.  Option `-r` causes the remote-tracking branches to be listed,
+branches are listed; the current branch will be highlighted in green and
+marked with an asterisk.  Any branches checked out in linked worktrees will
+be highlighted in cyan and marked with a plus sign. Option `-r` causes the
+remote-tracking branches to be listed,
 and option `-a` shows both local and remote branches. If a `<pattern>`
 is given, it is used as a shell wildcard to restrict the output to
 matching branches. If multiple patterns are given, a branch is shown if
diff --git a/builtin/branch.c b/builtin/branch.c
index d4359b33ac..a295380f45 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -47,6 +47,7 @@ static char branch_colors[][COLOR_MAXLEN] = {
 	GIT_COLOR_NORMAL,       /* LOCAL */
 	GIT_COLOR_GREEN,        /* CURRENT */
 	GIT_COLOR_BLUE,         /* UPSTREAM */
+	GIT_COLOR_CYAN,         /* WORKTREE */
 };
 enum color_branch {
 	BRANCH_COLOR_RESET = 0,
@@ -54,7 +55,8 @@ enum color_branch {
 	BRANCH_COLOR_REMOTE = 2,
 	BRANCH_COLOR_LOCAL = 3,
 	BRANCH_COLOR_CURRENT = 4,
-	BRANCH_COLOR_UPSTREAM = 5
+	BRANCH_COLOR_UPSTREAM = 5,
+	BRANCH_COLOR_WORKTREE = 6
 };
 
 static const char *color_branch_slots[] = {
@@ -64,6 +66,7 @@ static const char *color_branch_slots[] = {
 	[BRANCH_COLOR_LOCAL]	= "local",
 	[BRANCH_COLOR_CURRENT]	= "current",
 	[BRANCH_COLOR_UPSTREAM] = "upstream",
+	[BRANCH_COLOR_WORKTREE] = "worktree",
 };
 
 static struct string_list output = STRING_LIST_INIT_DUP;
@@ -342,9 +345,10 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 	struct strbuf local = STRBUF_INIT;
 	struct strbuf remote = STRBUF_INIT;
 
-	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)  %s%%(end)",
-		    branch_get_color(BRANCH_COLOR_CURRENT),
-		    branch_get_color(BRANCH_COLOR_LOCAL));
+	strbuf_addf(&local, "%%(if)%%(HEAD)%%(then)* %s%%(else)%%(if)%%(worktreepath)%%(then)+ %s%%(else)  %s%%(end)%%(end)",
+			branch_get_color(BRANCH_COLOR_CURRENT),
+			branch_get_color(BRANCH_COLOR_WORKTREE),
+			branch_get_color(BRANCH_COLOR_LOCAL));
 	strbuf_addf(&remote, "  %s",
 		    branch_get_color(BRANCH_COLOR_REMOTE));
 
diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh
index 478b82cf9b..88719cc02c 100755
--- a/t/t3200-branch.sh
+++ b/t/t3200-branch.sh
@@ -202,18 +202,22 @@ test_expect_success 'git branch -M baz bam should succeed when baz is checked ou
 	git worktree add -f bazdir2 baz &&
 	git branch -M baz bam &&
 	test $(git -C bazdir rev-parse --abbrev-ref HEAD) = bam &&
-	test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam
+	test $(git -C bazdir2 rev-parse --abbrev-ref HEAD) = bam &&
+	rm -r bazdir bazdir2 &&
+	git worktree prune
 '
 
 test_expect_success 'git branch -M baz bam should succeed within a worktree in which baz is checked out' '
 	git checkout -b baz &&
-	git worktree add -f bazdir3 baz &&
+	git worktree add -f bazdir baz &&
 	(
-		cd bazdir3 &&
+		cd bazdir &&
 		git branch -M baz bam &&
 		test $(git rev-parse --abbrev-ref HEAD) = bam
 	) &&
-	test $(git rev-parse --abbrev-ref HEAD) = bam
+	test $(git rev-parse --abbrev-ref HEAD) = bam &&
+	rm -r bazdir &&
+	git worktree prune
 '
 
 test_expect_success 'git branch -M master should work when master is checked out' '
@@ -774,7 +778,9 @@ test_expect_success 'test deleting branch without config' '
 test_expect_success 'deleting currently checked out branch fails' '
 	git worktree add -b my7 my7 &&
 	test_must_fail git -C my7 branch -d my7 &&
-	test_must_fail git branch -d my7
+	test_must_fail git branch -d my7 &&
+	rm -r my7 &&
+	git worktree prune
 '
 
 test_expect_success 'test --track without .fetch entries' '
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index be55148930..a3436bf25a 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -136,11 +136,13 @@ test_expect_success 'git branch `--show-current` works properly with worktrees'
 	branch-two
 	EOF
 	git checkout branch-one &&
-	git worktree add worktree branch-two &&
+	git worktree add worktree_dir branch-two &&
 	{
 		git branch --show-current &&
-		git -C worktree branch --show-current
+		git -C worktree_dir branch --show-current
 	} >actual &&
+	rm -r worktree_dir &&
+	git worktree prune &&
 	test_cmp expect actual
 '
 
@@ -284,6 +286,24 @@ test_expect_success 'git branch --format option' '
 	test_i18ncmp expect actual
 '
 
+test_expect_success 'worktree colors correct' '
+	cat >expect <<-EOF &&
+	* <GREEN>(HEAD detached from fromtag)<RESET>
+	  ambiguous<RESET>
+	  branch-one<RESET>
+	+ <CYAN>branch-two<RESET>
+	  master<RESET>
+	  ref-to-branch<RESET> -> branch-one
+	  ref-to-remote<RESET> -> origin/branch-one
+	EOF
+	git worktree add worktree_dir branch-two &&
+	git branch --color >actual.raw &&
+	rm -r worktree_dir &&
+	git worktree prune &&
+	test_decode_color <actual.raw >actual &&
+	test_i18ncmp expect actual
+'
+
 test_expect_success "set up color tests" '
 	echo "<RED>master<RESET>" >expect.color &&
 	echo "master" >expect.bare &&
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* [PATCH v10 3/3] branch: add worktree info on verbose output
  2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
  2019-04-29  5:19     ` [PATCH v10 1/3] ref-filter: add worktreepath atom nbelakovski
  2019-04-29  5:19     ` [PATCH v10 2/3] branch: update output to include worktree info nbelakovski
@ 2019-04-29  5:19     ` nbelakovski
  2019-04-29 14:12     ` [PATCH v10 0/3] SZEDER Gábor
  2019-04-29 20:57     ` Johannes Schindelin
  4 siblings, 0 replies; 125+ messages in thread
From: nbelakovski @ 2019-04-29  5:19 UTC (permalink / raw)
  To: git; +Cc: szeder.dev, Nickolai Belakovski

From: Nickolai Belakovski <nbelakovski@gmail.com>

To display worktree path for refs checked out in a linked worktree

Signed-off-by: Nickolai Belakovski <nbelakovski@gmail.com>
---
 Documentation/git-branch.txt |  6 ++++--
 builtin/branch.c             |  4 ++++
 t/t3203-branch-output.sh     | 19 +++++++++++++++++++
 3 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/Documentation/git-branch.txt b/Documentation/git-branch.txt
index 7d18dffc4b..d11d00583a 100644
--- a/Documentation/git-branch.txt
+++ b/Documentation/git-branch.txt
@@ -172,8 +172,10 @@ This option is only applicable in non-verbose mode.
 	When in list mode,
 	show sha1 and commit subject line for each head, along with
 	relationship to upstream branch (if any). If given twice, print
-	the name of the upstream branch, as well (see also `git remote
-	show <remote>`).
+	the path of the linked worktree (if any) and the name of the upstream
+	branch, as well (see also `git remote show <remote>`).  Note that the
+	current worktree's HEAD will not have its path printed (it will always
+	be your current directory).
 
 -q::
 --quiet::
diff --git a/builtin/branch.c b/builtin/branch.c
index a295380f45..2cb45e42e1 100644
--- a/builtin/branch.c
+++ b/builtin/branch.c
@@ -367,9 +367,13 @@ static char *build_format(struct ref_filter *filter, int maxwidth, const char *r
 		strbuf_addf(&local, " %s ", obname.buf);
 
 		if (filter->verbose > 1)
+		{
+			strbuf_addf(&local, "%%(if:notequals=*)%%(HEAD)%%(then)%%(if)%%(worktreepath)%%(then)(%s%%(worktreepath)%s) %%(end)%%(end)",
+				    branch_get_color(BRANCH_COLOR_WORKTREE), branch_get_color(BRANCH_COLOR_RESET));
 			strbuf_addf(&local, "%%(if)%%(upstream)%%(then)[%s%%(upstream:short)%s%%(if)%%(upstream:track)"
 				    "%%(then): %%(upstream:track,nobracket)%%(end)] %%(end)%%(contents:subject)",
 				    branch_get_color(BRANCH_COLOR_UPSTREAM), branch_get_color(BRANCH_COLOR_RESET));
+		}
 		else
 			strbuf_addf(&local, "%%(if)%%(upstream:track)%%(then)%%(upstream:track) %%(end)%%(contents:subject)");
 
diff --git a/t/t3203-branch-output.sh b/t/t3203-branch-output.sh
index a3436bf25a..4bef8c7569 100755
--- a/t/t3203-branch-output.sh
+++ b/t/t3203-branch-output.sh
@@ -328,4 +328,23 @@ test_expect_success '--color overrides auto-color' '
 	test_cmp expect.color actual
 '
 
+test_expect_success 'verbose output lists worktree path' '
+	one=$(git rev-parse --short HEAD) &&
+	two=$(git rev-parse --short master) &&
+	cat >expect <<-EOF &&
+	* (HEAD detached from fromtag) $one one
+	  ambiguous                    $one one
+	  branch-one                   $two two
+	+ branch-two                   $one ($(pwd)/worktree_dir) one
+	  master                       $two two
+	  ref-to-branch                $two two
+	  ref-to-remote                $two two
+	EOF
+	git worktree add worktree_dir branch-two &&
+	git branch -vv >actual &&
+	rm -r worktree_dir &&
+	git worktree prune &&
+	test_i18ncmp expect actual
+'
+
 test_done
-- 
2.14.2


^ permalink raw reply related	[flat|nested] 125+ messages in thread

* Re: [PATCH v10 0/3]
  2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
                       ` (2 preceding siblings ...)
  2019-04-29  5:19     ` [PATCH v10 3/3] branch: add worktree info on verbose output nbelakovski
@ 2019-04-29 14:12     ` SZEDER Gábor
  2019-04-29 19:27       ` Nickolai Belakovski
  2019-04-29 20:57     ` Johannes Schindelin
  4 siblings, 1 reply; 125+ messages in thread
From: SZEDER Gábor @ 2019-04-29 14:12 UTC (permalink / raw)
  To: nbelakovski; +Cc: git

On Sun, Apr 28, 2019 at 10:19:41PM -0700, nbelakovski@gmail.com wrote:
> From: Nickolai Belakovski <nbelakovski@gmail.com>
> 
> Added test_i18ncmp per instructions from Szeder
> 
> 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.
> 
> Travis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210

Testing with GETTEXT_POISON was broken since 6cdccfce (i18n: make
GETTEXT_POISON a runtime option, 2018-11-08), and didn't catch any of
these issues.  See:

  https://public-inbox.org/git/xmqqlg0bvppc.fsf_-_@gitster-ct.c.googlers.com/T/#u

The fix f88b9cb603 (gettext tests: export the restored
GIT_TEST_GETTEXT_POISON, 2019-04-15) was merged to master just last
week.


^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v10 0/3]
  2019-04-29 14:12     ` [PATCH v10 0/3] SZEDER Gábor
@ 2019-04-29 19:27       ` Nickolai Belakovski
  0 siblings, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-04-29 19:27 UTC (permalink / raw)
  To: SZEDER Gábor; +Cc: Git List

> Testing with GETTEXT_POISON was broken since 6cdccfce (i18n: make
> GETTEXT_POISON a runtime option, 2018-11-08), and didn't catch any of
> these issues.  See:
>
>   https://public-inbox.org/git/xmqqlg0bvppc.fsf_-_@gitster-ct.c.googlers.com/T/#u
>
> The fix f88b9cb603 (gettext tests: export the restored
> GIT_TEST_GETTEXT_POISON, 2019-04-15) was merged to master just last
> week.
>

Ah I see, thanks for the info.

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v10 0/3]
  2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
                       ` (3 preceding siblings ...)
  2019-04-29 14:12     ` [PATCH v10 0/3] SZEDER Gábor
@ 2019-04-29 20:57     ` Johannes Schindelin
  2019-04-29 21:33       ` Nickolai Belakovski
       [not found]       ` <CAC05385Mc7pqiCd5mb+1c4WM+v7K=h=GMHuvkw9xizhRFJXXBA@mail.gmail.com>
  4 siblings, 2 replies; 125+ messages in thread
From: Johannes Schindelin @ 2019-04-29 20:57 UTC (permalink / raw)
  To: Nickolai Belakovski; +Cc: git, szeder.dev

Hi,

am I the only person who is puzzled every time this patch series with a
completely empty subject and without any further explanation about the
intent in the mail body is sent?

Ciao,
Johannes


On Sun, 28 Apr 2019, nbelakovski@gmail.com wrote:

> From: Nickolai Belakovski <nbelakovski@gmail.com>
>
> Added test_i18ncmp per instructions from Szeder
>
> 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.
>
> Travis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210
>
> Nickolai Belakovski (3):
>   ref-filter: add worktreepath atom
>   branch: update output to include worktree info
>   branch: add worktree info on verbose output
>
>  Documentation/git-branch.txt       | 12 ++++--
>  Documentation/git-for-each-ref.txt |  5 +++
>  builtin/branch.c                   | 16 ++++++--
>  ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
>  t/t3200-branch.sh                  | 16 +++++---
>  t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-
>  t/t6302-for-each-ref-filter.sh     | 13 +++++++
>  7 files changed, 168 insertions(+), 15 deletions(-)
>
> --
> 2.14.2
>
>

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v10 0/3]
  2019-04-29 20:57     ` Johannes Schindelin
@ 2019-04-29 21:33       ` Nickolai Belakovski
       [not found]       ` <CAC05385Mc7pqiCd5mb+1c4WM+v7K=h=GMHuvkw9xizhRFJXXBA@mail.gmail.com>
  1 sibling, 0 replies; 125+ messages in thread
From: Nickolai Belakovski @ 2019-04-29 21:33 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Git List, SZEDER Gábor

Sorry, I'm not very accustomed to mailing list development. I had
assumed that this was being threaded with the other messages in the
series, hence leaving the subject blank and only putting new info in
the body.

In the future I'll add in an appropriate subject and brief re-hash in
the body. Thanks for bringing it up.

Nickolai

On Mon, Apr 29, 2019 at 1:57 PM Johannes Schindelin
<Johannes.Schindelin@gmx.de> wrote:
>
> Hi,
>
> am I the only person who is puzzled every time this patch series with a
> completely empty subject and without any further explanation about the
> intent in the mail body is sent?
>
> Ciao,
> Johannes
>
>
> On Sun, 28 Apr 2019, nbelakovski@gmail.com wrote:
>
> > From: Nickolai Belakovski <nbelakovski@gmail.com>
> >
> > Added test_i18ncmp per instructions from Szeder
> >
> > 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.
> >
> > Travis CI results: https://travis-ci.org/nbelakovski/git/builds/525801210
> >
> > Nickolai Belakovski (3):
> >   ref-filter: add worktreepath atom
> >   branch: update output to include worktree info
> >   branch: add worktree info on verbose output
> >
> >  Documentation/git-branch.txt       | 12 ++++--
> >  Documentation/git-for-each-ref.txt |  5 +++
> >  builtin/branch.c                   | 16 ++++++--
> >  ref-filter.c                       | 78 ++++++++++++++++++++++++++++++++++++++
> >  t/t3200-branch.sh                  | 16 +++++---
> >  t/t3203-branch-output.sh           | 43 ++++++++++++++++++++-
> >  t/t6302-for-each-ref-filter.sh     | 13 +++++++
> >  7 files changed, 168 insertions(+), 15 deletions(-)
> >
> > --
> > 2.14.2
> >
> >

^ permalink raw reply	[flat|nested] 125+ messages in thread

* Re: [PATCH v10 0/3]
       [not found]       ` <CAC05385Mc7pqiCd5mb+1c4WM+v7K=h=GMHuvkw9xizhRFJXXBA@mail.gmail.com>
@ 2019-04-30 21:46         ` Johannes Schindelin
  0 siblings, 0 replies; 125+ messages in thread
From: Johannes Schindelin @ 2019-04-30 21:46 UTC (permalink / raw)
  To: Nickolai Belakovski; +Cc: Git List, SZEDER Gábor

Hi Nickolai,

On Mon, 29 Apr 2019, Nickolai Belakovski wrote:

> Sorry, I'm not very accustomed to mailing list development. I had assumed
> that this was being threaded with the other messages in the series, hence
> leaving the subject blank and only putting new info in the body.

The openness of a mailing list-centric development is that everybody with
an email address can participate [*1*].

The downside is that *anybody* with *any* mail program can be a reader, so
you cannot assume *anything* about how people will read your mails. Some
will read it in a mail program that color-codes levels of quotation.
Others will not have any color whatsoever. Some thread. Some don't. In
most mail programs, you cannot even search for a Message-ID. Which can be
non-unique.

So the perceived benefits of this way to run a project come at a price.

> In the future I'll add in an appropriate subject and brief re-hash in the
> body. Thanks for bringing it up.

Thank you,
Johannes

Footnote *1*: Of course, it is not *all* that open. If you cannot convince
your mail program to send mails in plain text only, and to stop
reformatting mails e.g. to make them look better on cell phones (refusing
this is the price of requiring patches to be sent in whitespace-preserving
plain text emails), then you're not invited to the party. This is why I
sometimes say, not altogether without reason, that you can use *any*
mail program to participate in the Git project as long as it is `mutt`.

^ permalink raw reply	[flat|nested] 125+ messages in thread

end of thread, other threads:[~2019-04-30 21:46 UTC | newest]

Thread overview: 125+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <"<CAC05386q2iGoiJ_fRgwoOTF23exEN2D1+oh4VjajEvYQ58O1TQ@mail.gmail.com>
2018-09-27 15:13 ` [PATCH] branch: colorize branches checked out in a linked working tree the same way as the current branch is colorized Nickolai Belakovski
2018-09-27 15:33   ` Ævar Arnfjörð Bjarmason
2018-09-27 17:46     ` Nickolai Belakovski
     [not found]     ` <CAC05387S9P+w8yqqcjkQDnURYSgQmqtukxS4KvqJu-kDA+_o0g@mail.gmail.com>
2018-09-27 17:59       ` Ævar Arnfjörð Bjarmason
2018-10-02 20:41         ` Johannes Schindelin
2018-09-27 17:58   ` Duy Nguyen
2018-09-27 18:17   ` Jeff King
2018-09-27 18:39     ` Nickolai Belakovski
2018-09-27 18:51       ` Jeff King
2018-09-27 19:28     ` Rafael Ascensão
2018-09-27 19:35       ` Jeff King
2018-09-27 19:41         ` Jeff King
2018-09-27 21:22           ` Junio C Hamano
2018-09-28  1:05             ` Jeff King
2018-09-28  1:28               ` Junio C Hamano
2018-09-27 21:35         ` Rafael Ascensão
2018-09-28  1:07           ` Jeff King
2018-09-27 20:02       ` Ævar Arnfjörð Bjarmason
2018-09-27 20:16         ` Nickolai Belakovski
2018-09-27 20:40           ` Rafael Ascensão
2018-11-11 23:58             ` [PATCH v2 0/2] refactoring branch colorization to ref-filter nbelakovski
2018-11-11 23:58               ` [PATCH v2 1/2] ref-filter: add worktree atom nbelakovski
2018-11-12 10:11                 ` Junio C Hamano
2018-11-12 12:22                   ` Jeff King
2018-11-13  1:38                     ` Junio C Hamano
2018-11-21 14:05                       ` Nickolai Belakovski
2018-11-21 14:08                         ` Jeff King
2018-11-12 12:23                 ` Jeff King
2018-11-11 23:58               ` [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree nbelakovski
2018-11-12 10:20                 ` Junio C Hamano
2018-11-12 12:14                   ` Jeff King
2018-11-12 18:07                     ` Rafael Ascensão
2018-11-13  1:45                       ` Junio C Hamano
2018-11-13 14:49                       ` Jeff King
2018-11-21 14:07                         ` Nickolai Belakovski
2018-12-16 21:57               ` [PATCH v3 0/3] nbelakovski
2018-12-16 21:57                 ` [PATCH v3 1/3] ref-filter: add worktreepath atom nbelakovski
2018-12-18 17:22                   ` Jeff King
2018-12-20  7:09                     ` Nickolai Belakovski
2018-12-20 14:59                       ` Jeff King
2018-12-24  8:47                         ` [PATCH v4 0/3] nbelakovski
2018-12-24  8:47                           ` [PATCH v4 1/3] ref-filter: add worktreepath atom nbelakovski
2019-01-03  5:40                             ` Jeff King
2019-01-03  9:31                               ` Eric Sunshine
2018-12-24  8:47                           ` [PATCH v4 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
2018-12-24  8:47                           ` [PATCH v4 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
2019-01-03  5:42                             ` Jeff King
2019-01-03  5:22                           ` [PATCH v4 0/3] Jeff King
2018-12-16 21:57                 ` [PATCH v3 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
2018-12-16 21:57                 ` [PATCH v3 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
2018-12-18 17:25                 ` [PATCH v3 0/3] Jeff King
2019-01-06  0:26   ` [PATCH v5 0/3] nbelakovski
2019-01-06  0:26     ` [PATCH v5 1/3] ref-filter: add worktreepath atom nbelakovski
2019-01-07 18:20       ` Junio C Hamano
2019-01-18 22:17         ` Nickolai Belakovski
2019-01-18 22:20           ` Nickolai Belakovski
2019-01-06  0:26     ` [PATCH v5 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
2019-01-07 19:04       ` Junio C Hamano
2019-01-10 21:42         ` Philip Oakley
2019-01-13  1:41           ` Nickolai Belakovski
2019-01-14 18:18             ` Junio C Hamano
2019-01-18 22:18               ` Nickolai Belakovski
2019-01-06  0:26     ` [PATCH v5 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
2019-01-07 19:09       ` Junio C Hamano
2019-01-22 23:22   ` [PATCH v6 0/3] nbelakovski
2019-01-22 23:22     ` [PATCH v6 1/3] ref-filter: add worktreepath atom nbelakovski
2019-01-23 18:57       ` Junio C Hamano
2019-01-23 23:34         ` Nickolai Belakovski
2019-01-24 18:26           ` Junio C Hamano
2019-01-24 18:32             ` Jeff King
2019-01-24 19:27               ` Junio C Hamano
2019-01-24 19:34                 ` Jeff King
2019-01-24 19:30               ` Junio C Hamano
2019-01-24 21:26                 ` Jeff King
2019-01-31 20:53                   ` Nickolai Belakovski
2019-01-31 23:21                     ` Jeff King
2019-01-31 21:42                   ` Junio C Hamano
2019-01-31 23:20                     ` Jeff King
2019-01-22 23:23     ` [PATCH v6 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
2019-01-22 23:23     ` [PATCH v6 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
2019-02-01 22:04   ` [PATCH v7 0/3] nbelakovski
2019-02-01 22:28     ` Junio C Hamano
2019-02-01 23:31       ` Nickolai Belakovski
2019-02-01 22:04   ` [PATCH v7 1/3] ref-filter: add worktreepath atom nbelakovski
2019-02-01 22:20     ` Eric Sunshine
2019-02-01 22:41       ` Nickolai Belakovski
2019-02-04 18:14         ` Junio C Hamano
2019-02-18 10:09           ` Nickolai Belakovski
2019-02-01 22:31     ` Junio C Hamano
2019-02-01 22:04   ` [PATCH v7 2/3] branch: Mark and color a branch differently if it is checked out in a linked worktree nbelakovski
2019-02-01 22:34     ` Junio C Hamano
2019-02-01 23:12       ` Nickolai Belakovski
2019-02-04 18:18         ` Junio C Hamano
2019-02-01 22:04   ` [PATCH v7 3/3] branch: Add an extra verbose output displaying worktree path for refs " nbelakovski
2019-02-01 22:27     ` Eric Sunshine
2019-02-01 22:45       ` Nickolai Belakovski
2019-02-01 22:53     ` Junio C Hamano
2019-02-01 23:06       ` Nickolai Belakovski
2019-02-02  1:22         ` [RFC] Sample of test for git branch -vv nbelakovski
2019-02-19  8:31   ` [PATCH v8 0/3] nbelakovski
2019-02-19  8:31     ` [PATCH v8 1/3] ref-filter: add worktreepath atom nbelakovski
2019-02-19  8:31     ` [PATCH v8 2/3] branch: update output to include worktree info nbelakovski
2019-02-21 12:44       ` Jeff King
2019-03-14  5:45         ` Nickolai Belakovski
2019-02-19  8:31     ` [PATCH v8 3/3] branch: add worktree info on verbose output nbelakovski
2019-02-21 12:59       ` Jeff King
2019-03-14  5:58         ` Nickolai Belakovski
2019-03-18  2:12           ` Junio C Hamano
2019-02-21 12:36     ` [PATCH v8 0/3] Jeff King
2019-03-14  6:10       ` Nickolai Belakovski
2019-03-16  1:38   ` [PATCH v9 0/3] nbelakovski
2019-03-16  1:38     ` [PATCH v9 1/3] ref-filter: add worktreepath atom nbelakovski
2019-03-16  1:38     ` [PATCH v9 2/3] branch: update output to include worktree info nbelakovski
2019-03-16  1:38     ` [PATCH v9 3/3] branch: add worktree info on verbose output nbelakovski
2019-03-18 12:10       ` SZEDER Gábor
2019-03-18  5:30     ` [PATCH v9 0/3] Junio C Hamano
2019-04-29  5:19   ` [PATCH v10 0/3] nbelakovski
2019-04-29  5:19     ` [PATCH v10 1/3] ref-filter: add worktreepath atom nbelakovski
2019-04-29  5:19     ` [PATCH v10 2/3] branch: update output to include worktree info nbelakovski
2019-04-29  5:19     ` [PATCH v10 3/3] branch: add worktree info on verbose output nbelakovski
2019-04-29 14:12     ` [PATCH v10 0/3] SZEDER Gábor
2019-04-29 19:27       ` Nickolai Belakovski
2019-04-29 20:57     ` Johannes Schindelin
2019-04-29 21:33       ` Nickolai Belakovski
     [not found]       ` <CAC05385Mc7pqiCd5mb+1c4WM+v7K=h=GMHuvkw9xizhRFJXXBA@mail.gmail.com>
2019-04-30 21:46         ` Johannes Schindelin

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).