Subject: [PATCH v2 2/2] branch: Mark and colorize a branch differently if it is checked out in a linked worktree

From: [email-masked]
Date: Sun, 11 Nov 2018 15:58:31 -0800

From: Nickolai Belakovski <[email-masked]>

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 <[email-masked]>
---
 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