git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH 0/1] Colorize some errors on stderr
@ 2018-02-16 12:25 Johannes Schindelin
  2018-02-16 12:25 ` [PATCH 1/1] Colorize push errors Johannes Schindelin
                   ` (3 more replies)
  0 siblings, 4 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-02-16 12:25 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

This is an RFC because it tries to introduce a fundamental new color feature:
Coloring messages *on stderr*.

So far, pretty much everything in color.[ch] assumed that you want to color
only stuff on stdout.

However, in this case, a user (who became a contributor!) wanted some messages
that are printed to stderr and were missed by his colleagues to be colored.

The contribution comes via Pull Request from the Git for Windows project:

	https://github.com/git-for-windows/git/pull/1429

Now, what would be possible solutions for this?

- introduce `int fd` in `want_color()` (and callees) so that we can make
  a distinction whether we want to detect whether stdout or stderr is connected
  to a tty

- introduce a separate `want_color_stderr()` (we still would need to decide
  whether we want a config setting for this)

- not color stderr, ever

Also, I did not have too much time to dig into the question how to test this in
Git's test suite. Do we already have tests that generate fake server-side errors
onto which I could piggy-back a new test case?

Thoughts? Suggestions? Help?


Ryan Dammrose (1):
  Colorize push errors

 advice.c       | 42 +++++++++++++++++++++++++++++++++++++++--
 builtin/push.c | 38 +++++++++++++++++++++++++++++++++++++
 transport.c    | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 136 insertions(+), 3 deletions(-)


base-commit: b2e45c695d09f6a31ce09347ae0a5d2cdfe9dd4e
Published-As: https://github.com/dscho/git/releases/tag/colorize-push-errors-v1
Fetch-It-Via: git fetch https://github.com/dscho/git colorize-push-errors-v1
-- 
2.16.1.windows.4


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

* [PATCH 1/1] Colorize push errors
  2018-02-16 12:25 [PATCH 0/1] Colorize some errors on stderr Johannes Schindelin
@ 2018-02-16 12:25 ` Johannes Schindelin
  2018-02-16 19:21 ` [PATCH 0/1] Colorize some errors on stderr Junio C Hamano
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-02-16 12:25 UTC (permalink / raw)
  To: git; +Cc: Ryan Dammrose, Junio C Hamano

From: Ryan Dammrose <ryandammrose@gmail.com>

This is an attempt to resolve an issue I experience with people that are
new to Git -- especially colleagues in a team setting -- where they miss
that their push to a remote location failed because the failure and
success both return a block of white text.

An example is if I push something to a remote repository and then a
colleague attempts to push to the same remote repository and the push
fails because it requires them to pull first, but they don't notice
because a success and failure both return a block of white text. They
then continue about their business, thinking it has been successfully
pushed.

My solution was to try to change the stderr and hint colors (red and
yellow, respectively) so whenever there is a failure when pushing to a
remote repository that fails, it is more noticeable.

The challenge was that it seemed that stderr has never been colored and
I attempted to utilize what was already established; but this meant
using functions like want_color() even if it targets stdout while I
wanted to target stderr.

Additionally, to check for all rejection types, I did a strstr check in
transport.c, but this code could be problematic if there is need for
translation.

Signed-off-by: Ryan Dammrose ryandammrose@gmail.com
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 advice.c       | 42 +++++++++++++++++++++++++++++++++++++++--
 builtin/push.c | 38 +++++++++++++++++++++++++++++++++++++
 transport.c    | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 136 insertions(+), 3 deletions(-)

diff --git a/advice.c b/advice.c
index 406efc183ba..42460877ef6 100644
--- a/advice.c
+++ b/advice.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "config.h"
+#include "color.h"
 
 int advice_push_update_rejected = 1;
 int advice_push_non_ff_current = 1;
@@ -20,6 +21,33 @@ int advice_add_embedded_repo = 1;
 int advice_ignored_hook = 1;
 int advice_waiting_for_editor = 1;
 
+static int advice_use_color = -1;
+static char advice_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_YELLOW,	/* HINT */
+};
+
+enum color_advice {
+	ADVICE_COLOR_RESET = 0,
+	ADVICE_COLOR_HINT = 1,
+};
+
+static int parse_advise_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return ADVICE_COLOR_RESET;
+	if (!strcasecmp(slot, "advice"))
+		return ADVICE_COLOR_HINT;
+	return -1;
+}
+
+static const char *advise_get_color(enum color_advice ix)
+{
+	if (want_color(advice_use_color))
+		return advice_colors[ix];
+	return "";
+}
+
 static struct {
 	const char *name;
 	int *preference;
@@ -59,7 +87,8 @@ void advise(const char *advice, ...)
 
 	for (cp = buf.buf; *cp; cp = np) {
 		np = strchrnul(cp, '\n');
-		fprintf(stderr,	_("hint: %.*s\n"), (int)(np - cp), cp);
+		fprintf(stderr,	_("%shint: %.*s%s\n"), advise_get_color(ADVICE_COLOR_HINT),
+			(int)(np - cp), cp, advise_get_color(ADVICE_COLOR_RESET));
 		if (*np)
 			np++;
 	}
@@ -68,9 +97,18 @@ void advise(const char *advice, ...)
 
 int git_default_advice_config(const char *var, const char *value)
 {
-	const char *k;
+	const char *k, *slot_name;
 	int i;
 
+	if (skip_prefix(var, "color.advice.", &slot_name)) {
+		int slot = parse_advise_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!value)
+			return config_error_nonbool(var);
+		return color_parse(value, advice_colors[slot]);
+	}
+
 	if (!skip_prefix(var, "advice.", &k))
 		return 0;
 
diff --git a/builtin/push.c b/builtin/push.c
index 1c28427d82e..997ccab52ac 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -12,12 +12,40 @@
 #include "submodule.h"
 #include "submodule-config.h"
 #include "send-pack.h"
+#include "color.h"
 
 static const char * const push_usage[] = {
 	N_("git push [<options>] [<repository> [<refspec>...]]"),
 	NULL,
 };
 
+static int push_use_color = -1;
+static char push_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_RED,	/* ERROR */
+};
+
+enum color_push {
+	PUSH_COLOR_RESET = 0,
+	PUSH_COLOR_ERROR = 1
+};
+
+static int parse_push_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return PUSH_COLOR_RESET;
+	if (!strcasecmp(slot, "error"))
+		return PUSH_COLOR_ERROR;
+	return -1;
+}
+
+static const char *push_get_color(enum color_push ix)
+{
+	if (want_color(push_use_color))
+		return push_colors[ix];
+	return "";
+}
+
 static int thin = 1;
 static int deleterefs;
 static const char *receivepack;
@@ -338,7 +366,9 @@ static int push_with_options(struct transport *transport, int flags)
 	err = transport_push(transport, refspec_nr, refspec, flags,
 			     &reject_reasons);
 	if (err != 0)
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
 		error(_("failed to push some refs to '%s'"), transport->url);
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_RESET));
 
 	err |= transport_disconnect(transport);
 	if (!err)
@@ -467,6 +497,7 @@ static void set_push_cert_flags(int *flags, int v)
 
 static int git_push_config(const char *k, const char *v, void *cb)
 {
+	const char *slot_name;
 	int *flags = cb;
 	int status;
 
@@ -514,6 +545,13 @@ static int git_push_config(const char *k, const char *v, void *cb)
 			else
 				string_list_append(&push_options_config, v);
 		return 0;
+	} else if (skip_prefix(k, "color.advice.", &slot_name)) {
+		int slot = parse_push_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!v)
+			return config_error_nonbool(k);
+		return color_parse(v, push_colors[slot]);
 	}
 
 	return git_default_config(k, v, NULL);
diff --git a/transport.c b/transport.c
index 00d48b5b565..dd98dd84b05 100644
--- a/transport.c
+++ b/transport.c
@@ -18,6 +18,50 @@
 #include "sha1-array.h"
 #include "sigchain.h"
 #include "transport-internal.h"
+#include "color.h"
+
+static int transport_use_color = -1;
+static char transport_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_RED		/* REJECTED */
+};
+
+enum color_transport {
+	TRANSPORT_COLOR_RESET = 0,
+	TRANSPORT_COLOR_REJECTED = 1
+};
+
+static int transport_color_config(void)
+{
+	const char *keys[] = {
+		"transport.color.reset",
+		"transport.color.rejected"
+	};
+	char *value;
+	int i;
+	static int initialized;
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	for (i = 0; i < ARRAY_SIZE(keys); i++)
+		if (!git_config_get_string(keys[i], &value)) {
+			if (!value)
+				return config_error_nonbool(keys[i]);
+			if (color_parse(value, transport_colors[i]) < 0)
+				return -1;
+		}
+
+	return 0;
+}
+
+static const char *transport_get_color(enum color_transport ix)
+{
+	if (want_color(transport_use_color))
+		return transport_colors[ix];
+	return "";
+}
 
 static void set_upstreams(struct transport *transport, struct ref *refs,
 	int pretend)
@@ -338,7 +382,11 @@ static void print_ref_status(char flag, const char *summary,
 		else
 			fprintf(stdout, "%s\n", summary);
 	} else {
-		fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
+		if (strstr(summary, "rejected") != NULL || strstr(summary, "failure") != NULL)
+			fprintf(stderr, " %s%c %-*s%s ", transport_get_color(TRANSPORT_COLOR_REJECTED),
+				flag, summary_width, summary, transport_get_color(TRANSPORT_COLOR_RESET));
+		else
+			fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
 		if (from)
 			fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
 		else
@@ -487,6 +535,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,
 	char *head;
 	int summary_width = transport_summary_width(refs);
 
+	if (transport_color_config() < 0)
+		warning(_("could not parse transport.color.* config"));
+
 	head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
 
 	if (verbose) {
@@ -553,6 +604,9 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 	struct send_pack_args args;
 	int ret;
 
+	if (transport_color_config() < 0)
+		return -1;
+
 	if (!data->got_remote_heads) {
 		struct ref *tmp_refs;
 		connect_setup(transport, 1);
@@ -997,6 +1051,9 @@ int transport_push(struct transport *transport,
 	*reject_reasons = 0;
 	transport_verify_remote_names(refspec_nr, refspec);
 
+	if (transport_color_config() < 0)
+		return -1;
+
 	if (transport->vtable->push_refs) {
 		struct ref *remote_refs;
 		struct ref *local_refs = get_local_heads();
-- 
2.16.1.windows.4

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

* Re: [PATCH 0/1] Colorize some errors on stderr
  2018-02-16 12:25 [PATCH 0/1] Colorize some errors on stderr Johannes Schindelin
  2018-02-16 12:25 ` [PATCH 1/1] Colorize push errors Johannes Schindelin
@ 2018-02-16 19:21 ` Junio C Hamano
  2018-04-06 11:21   ` Johannes Schindelin
  2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
  2018-04-06 18:48 ` [PATCH 0/1] Colorize some errors on stderr Ævar Arnfjörð Bjarmason
  3 siblings, 1 reply; 22+ messages in thread
From: Junio C Hamano @ 2018-02-16 19:21 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git

Johannes Schindelin <johannes.schindelin@gmx.de> writes:

> Now, what would be possible solutions for this?
>
> - introduce `int fd` in `want_color()` (and callees) so that we can make
>   a distinction whether we want to detect whether stdout or stderr is connected
>   to a tty
>
> - introduce a separate `want_color_stderr()` (we still would need to decide
>   whether we want a config setting for this)

Between the above two, there probably aren't so big a difference, but
in order to avoid disrupting existing callers of want_color() while
possibly sharing as much code between the old and new callers,
perhaps:

	extern int want_color_fd(int fd, int colorbool);
	#define want_color(colorbool) want_color_fd(1, (colorbool))
	#define want_color_stderr(colorbool) want_color_fd(2, (colorbool))

We should honor configuration at two levels, just like the colors on
stdout, i.e. color in which individual items are painted (e.g.
color.diff.filename, color.advice.hint) and whether we use colors in
UI at all (e.g. color.ui).  I do not think it is necessary or even
at the right granularity to allow settings like "do color stdout but
do not color errors".

> - not color stderr, ever

This is my personal preference, but that does not and should not
carry too much weight ;-)

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

* [PATCH v2 0/4] Colorize push errors
  2018-02-16 12:25 [PATCH 0/1] Colorize some errors on stderr Johannes Schindelin
  2018-02-16 12:25 ` [PATCH 1/1] Colorize push errors Johannes Schindelin
  2018-02-16 19:21 ` [PATCH 0/1] Colorize some errors on stderr Junio C Hamano
@ 2018-04-05 22:48 ` Johannes Schindelin
  2018-04-05 22:48   ` [PATCH v2 1/4] color: introduce support for colorizing stderr Johannes Schindelin
                     ` (4 more replies)
  2018-04-06 18:48 ` [PATCH 0/1] Colorize some errors on stderr Ævar Arnfjörð Bjarmason
  3 siblings, 5 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-05 22:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

To help users discern large chunks of white text (when the push
succeeds) from large chunks of white text (when the push fails), let's
add some color to the latter.

The original contribution came in via Pull Request from the Git for
Windows project:

	https://github.com/git-for-windows/git/pull/1429

Changes since v1:

- implemented want_color_fd() as suggested by Junio

- added color.{advice,push,transport} to be able to force this thing on

- added a test

- added documentation to `git config`'s man page

- fixed a bug where the push config looked at color.advice.<slot>

- fixed a bug where `color.advise.<slot>` was not parsed because
  git_default_config() would fail to hand `color.advise.*` settings to
  git_default_advice_config()

- wrapped a couple of too-long lines

- changed the strstr() hack to detect push failures to use push_had_errors()
  instead

- renamed the transport.color.* settings to color.transport.* (to make them
  consistent with all the other color.<category>.<slot> settings)


Johannes Schindelin (3):
  color: introduce support for colorizing stderr
  Add a test to verify that push errors are colorful
  Document the new color.* settings to colorize push errors/hints

Ryan Dammrose (1):
  push: colorize errors

 Documentation/config.txt   | 28 ++++++++++++++++
 advice.c                   | 49 ++++++++++++++++++++++++++--
 builtin/push.c             | 44 ++++++++++++++++++++++++-
 color.c                    | 20 +++++++-----
 color.h                    |  4 ++-
 config.c                   |  2 +-
 t/t5541-http-push-smart.sh | 18 ++++++++++
 transport.c                | 67 +++++++++++++++++++++++++++++++++++++-
 8 files changed, 217 insertions(+), 15 deletions(-)


base-commit: 468165c1d8a442994a825f3684528361727cd8c0
Published-As: https://github.com/dscho/git/releases/tag/colorize-push-errors-v2
Fetch-It-Via: git fetch https://github.com/dscho/git colorize-push-errors-v2

Interdiff vs v1:
 diff --git a/Documentation/config.txt b/Documentation/config.txt
 index 4e0cff87f62..40e3828b85f 100644
 --- a/Documentation/config.txt
 +++ b/Documentation/config.txt
 @@ -1088,6 +1088,16 @@ clean.requireForce::
  	A boolean to make git-clean do nothing unless given -f,
  	-i or -n.   Defaults to true.
  
 +color.advice::
 +	A boolean to enable/disable color in hints (e.g. when a push
 +	failed, see `advice.*` for a list).  May be set to `always`,
 +	`false` (or `never`) or `auto` (or `true`), in which case colors
 +	are used only when the error output goes to a terminal. If
 +	unset, then the value of `color.ui` is used (`auto` by default).
 +
 +color.advice.advice::
 +	Use customized color for hints.
 +
  color.branch::
  	A boolean to enable/disable color in the output of
  	linkgit:git-branch[1]. May be set to `always`,
 @@ -1190,6 +1200,15 @@ color.pager::
  	A boolean to enable/disable colored output when the pager is in
  	use (default is true).
  
 +color.push::
 +	A boolean to enable/disable color in push errors. May be set to
 +	`always`, `false` (or `never`) or `auto` (or `true`), in which
 +	case colors are used only when the error output goes to a terminal.
 +	If unset, then the value of `color.ui` is used (`auto` by default).
 +
 +color.push.error::
 +	Use customized color for push errors.
 +
  color.showBranch::
  	A boolean to enable/disable color in the output of
  	linkgit:git-show-branch[1]. May be set to `always`,
 @@ -1218,6 +1237,15 @@ color.status.<slot>::
  	status short-format), or
  	`unmerged` (files which have unmerged changes).
  
 +color.transport::
 +	A boolean to enable/disable color when pushes are rejected. May be
 +	set to `always`, `false` (or `never`) or `auto` (or `true`), in which
 +	case colors are used only when the error output goes to a terminal.
 +	If unset, then the value of `color.ui` is used (`auto` by default).
 +
 +color.transport.rejected::
 +	Use customized color when a push was rejected.
 +
  color.ui::
  	This variable determines the default value for variables such
  	as `color.diff` and `color.grep` that control the use of color
 diff --git a/advice.c b/advice.c
 index 42460877ef6..2121c1811fd 100644
 --- a/advice.c
 +++ b/advice.c
 @@ -43,7 +43,7 @@ static int parse_advise_color_slot(const char *slot)
  
  static const char *advise_get_color(enum color_advice ix)
  {
 -	if (want_color(advice_use_color))
 +	if (want_color_stderr(advice_use_color))
  		return advice_colors[ix];
  	return "";
  }
 @@ -87,8 +87,10 @@ void advise(const char *advice, ...)
  
  	for (cp = buf.buf; *cp; cp = np) {
  		np = strchrnul(cp, '\n');
 -		fprintf(stderr,	_("%shint: %.*s%s\n"), advise_get_color(ADVICE_COLOR_HINT),
 -			(int)(np - cp), cp, advise_get_color(ADVICE_COLOR_RESET));
 +		fprintf(stderr,	_("%shint: %.*s%s\n"),
 +			advise_get_color(ADVICE_COLOR_HINT),
 +			(int)(np - cp), cp,
 +			advise_get_color(ADVICE_COLOR_RESET));
  		if (*np)
  			np++;
  	}
 @@ -100,6 +102,11 @@ int git_default_advice_config(const char *var, const char *value)
  	const char *k, *slot_name;
  	int i;
  
 +	if (!strcmp(var, "color.advice")) {
 +		advice_use_color = git_config_colorbool(var, value);
 +		return 0;
 +	}
 +
  	if (skip_prefix(var, "color.advice.", &slot_name)) {
  		int slot = parse_advise_color_slot(slot_name);
  		if (slot < 0)
 diff --git a/builtin/push.c b/builtin/push.c
 index e443dd40de9..ac3705370e1 100644
 --- a/builtin/push.c
 +++ b/builtin/push.c
 @@ -41,7 +41,7 @@ static int parse_push_color_slot(const char *slot)
  
  static const char *push_get_color(enum color_push ix)
  {
 -	if (want_color(push_use_color))
 +	if (want_color_stderr(push_use_color))
  		return push_colors[ix];
  	return "";
  }
 @@ -365,10 +365,11 @@ static int push_with_options(struct transport *transport, int flags)
  		fprintf(stderr, _("Pushing to %s\n"), transport->url);
  	err = transport_push(transport, refspec_nr, refspec, flags,
  			     &reject_reasons);
 -	if (err != 0)
 +	if (err != 0) {
  		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
  		error(_("failed to push some refs to '%s'"), transport->url);
  		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_RESET));
 +	}
  
  	err |= transport_disconnect(transport);
  	if (!err)
 @@ -545,7 +546,10 @@ static int git_push_config(const char *k, const char *v, void *cb)
  			else
  				string_list_append(&push_options_config, v);
  		return 0;
 -	} else if (skip_prefix(k, "color.advice.", &slot_name)) {
 +	} else if (!strcmp(k, "color.push")) {
 +		push_use_color = git_config_colorbool(k, v);
 +		return 0;
 +	} else if (skip_prefix(k, "color.push.", &slot_name)) {
  		int slot = parse_push_color_slot(slot_name);
  		if (slot < 0)
  			return 0;
 diff --git a/color.c b/color.c
 index f277e72e4ce..c6c6c4f580f 100644
 --- a/color.c
 +++ b/color.c
 @@ -319,18 +319,20 @@ int git_config_colorbool(const char *var, const char *value)
  	return GIT_COLOR_AUTO;
  }
  
 -static int check_auto_color(void)
 +static int check_auto_color(int fd)
  {
 -	if (color_stdout_is_tty < 0)
 -		color_stdout_is_tty = isatty(1);
 -	if (color_stdout_is_tty || (pager_in_use() && pager_use_color)) {
 +	static int color_stderr_is_tty = -1;
 +	int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
 +	if (*is_tty_p < 0)
 +		*is_tty_p = isatty(fd);
 +	if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
  		if (!is_terminal_dumb())
  			return 1;
  	}
  	return 0;
  }
  
 -int want_color(int var)
 +int want_color_fd(int fd, int var)
  {
  	/*
  	 * NEEDSWORK: This function is sometimes used from multiple threads, and
 @@ -339,15 +341,15 @@ int want_color(int var)
  	 * is listed in .tsan-suppressions for the time being.
  	 */
  
 -	static int want_auto = -1;
 +	static int want_auto[3] = { -1, -1, -1 };
  
  	if (var < 0)
  		var = git_use_color_default;
  
  	if (var == GIT_COLOR_AUTO) {
 -		if (want_auto < 0)
 -			want_auto = check_auto_color();
 -		return want_auto;
 +		if (want_auto[fd] < 0)
 +			want_auto[fd] = check_auto_color(fd);
 +		return want_auto[fd];
  	}
  	return var;
  }
 diff --git a/color.h b/color.h
 index cd0bcedd084..5b744e1bc68 100644
 --- a/color.h
 +++ b/color.h
 @@ -88,7 +88,9 @@ int git_config_colorbool(const char *var, const char *value);
   * Return a boolean whether to use color, where the argument 'var' is
   * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.
   */
 -int want_color(int var);
 +int want_color_fd(int fd, int var);
 +#define want_color(colorbool) want_color_fd(1, (colorbool))
 +#define want_color_stderr(colorbool) want_color_fd(2, (colorbool))
  
  /*
   * Translate a Git color from 'value' into a string that the terminal can
 diff --git a/config.c b/config.c
 index b0c20e6cb8a..3bdbe36a638 100644
 --- a/config.c
 +++ b/config.c
 @@ -1365,7 +1365,7 @@ int git_default_config(const char *var, const char *value, void *dummy)
  	if (starts_with(var, "mailmap."))
  		return git_default_mailmap_config(var, value);
  
 -	if (starts_with(var, "advice."))
 +	if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
  		return git_default_advice_config(var, value);
  
  	if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
 diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
 index 21340e89c96..1c2be98dc2b 100755
 --- a/t/t5541-http-push-smart.sh
 +++ b/t/t5541-http-push-smart.sh
 @@ -377,5 +377,23 @@ test_expect_success 'push status output scrubs password' '
  	grep "^To $HTTPD_URL/smart/test_repo.git" status
  '
  
 +test_expect_success 'colorize errors/hints' '
 +	cd "$ROOT_PATH"/test_repo_clone &&
 +	cat >exp <<-EOF &&
 +	To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
 +	 <RED>! [rejected]       <RESET> origin/master^ -> master (non-fast-forward)
 +	error: failed to push some refs to '\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\''
 +	EOF
 +
 +	test_must_fail git -c color.transport=always -c color.advice=always \
 +		-c color.push=always \
 +		push origin origin/master^:master 2>act &&
 +	test_decode_color <act >decoded &&
 +	test_i18ngrep "<RED>.*rejected.*<RESET>" decoded &&
 +	test_i18ngrep "<RED>error: failed to push some refs" decoded &&
 +	test_i18ngrep "<YELLOW>hint: " decoded &&
 +	test_i18ngrep ! "^hint: " decoded
 +'
 +
  stop_httpd
  test_done
 diff --git a/transport.c b/transport.c
 index dd98dd84b05..4702b9fbc8f 100644
 --- a/transport.c
 +++ b/transport.c
 @@ -34,9 +34,9 @@ enum color_transport {
  static int transport_color_config(void)
  {
  	const char *keys[] = {
 -		"transport.color.reset",
 -		"transport.color.rejected"
 -	};
 +		"color.transport.reset",
 +		"color.transport.rejected"
 +	}, *key = "color.transport";
  	char *value;
  	int i;
  	static int initialized;
 @@ -45,6 +45,12 @@ static int transport_color_config(void)
  		return 0;
  	initialized = 1;
  
 +	if (!git_config_get_string(key, &value))
 +		transport_use_color = git_config_colorbool(key, value);
 +
 +	if (!want_color_stderr(transport_use_color))
 +		return 0;
 +
  	for (i = 0; i < ARRAY_SIZE(keys); i++)
  		if (!git_config_get_string(keys[i], &value)) {
  			if (!value)
 @@ -58,7 +64,7 @@ static int transport_color_config(void)
  
  static const char *transport_get_color(enum color_transport ix)
  {
 -	if (want_color(transport_use_color))
 +	if (want_color_stderr(transport_use_color))
  		return transport_colors[ix];
  	return "";
  }
 @@ -382,11 +388,13 @@ static void print_ref_status(char flag, const char *summary,
  		else
  			fprintf(stdout, "%s\n", summary);
  	} else {
 -		if (strstr(summary, "rejected") != NULL || strstr(summary, "failure") != NULL)
 -			fprintf(stderr, " %s%c %-*s%s ", transport_get_color(TRANSPORT_COLOR_REJECTED),
 -				flag, summary_width, summary, transport_get_color(TRANSPORT_COLOR_RESET));
 -		else
 -			fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
 +		const char *red = "", *reset = "";
 +		if (push_had_errors(to)) {
 +			red = transport_get_color(TRANSPORT_COLOR_REJECTED);
 +			reset = transport_get_color(TRANSPORT_COLOR_RESET);
 +		}
 +		fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
 +			summary, reset);
  		if (from)
  			fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
  		else
-- 
2.17.0.windows.1.4.g7e4058d72e3


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

* [PATCH v2 1/4] color: introduce support for colorizing stderr
  2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
@ 2018-04-05 22:48   ` Johannes Schindelin
  2018-04-05 22:48   ` [PATCH v2 2/4] push: colorize errors Johannes Schindelin
                     ` (3 subsequent siblings)
  4 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-05 22:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

So far, we only ever asked whether stdout wants to be colorful. In the
upcoming patches, we will want to make push errors more prominent, which
are printed to stderr, though.

So let's refactor the want_color() function into a want_color_fd()
function (which expects to be called with fd == 1 or fd == 2 for stdout
and stderr, respectively), and then define the macro `want_color()` to
use the want_color_fd() function.

And then also add a macro `want_color_stderr()`, for convenience and
for documentation.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 color.c | 20 +++++++++++---------
 color.h |  4 +++-
 2 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/color.c b/color.c
index f277e72e4ce..c6c6c4f580f 100644
--- a/color.c
+++ b/color.c
@@ -319,18 +319,20 @@ int git_config_colorbool(const char *var, const char *value)
 	return GIT_COLOR_AUTO;
 }
 
-static int check_auto_color(void)
+static int check_auto_color(int fd)
 {
-	if (color_stdout_is_tty < 0)
-		color_stdout_is_tty = isatty(1);
-	if (color_stdout_is_tty || (pager_in_use() && pager_use_color)) {
+	static int color_stderr_is_tty = -1;
+	int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
+	if (*is_tty_p < 0)
+		*is_tty_p = isatty(fd);
+	if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
 		if (!is_terminal_dumb())
 			return 1;
 	}
 	return 0;
 }
 
-int want_color(int var)
+int want_color_fd(int fd, int var)
 {
 	/*
 	 * NEEDSWORK: This function is sometimes used from multiple threads, and
@@ -339,15 +341,15 @@ int want_color(int var)
 	 * is listed in .tsan-suppressions for the time being.
 	 */
 
-	static int want_auto = -1;
+	static int want_auto[3] = { -1, -1, -1 };
 
 	if (var < 0)
 		var = git_use_color_default;
 
 	if (var == GIT_COLOR_AUTO) {
-		if (want_auto < 0)
-			want_auto = check_auto_color();
-		return want_auto;
+		if (want_auto[fd] < 0)
+			want_auto[fd] = check_auto_color(fd);
+		return want_auto[fd];
 	}
 	return var;
 }
diff --git a/color.h b/color.h
index cd0bcedd084..5b744e1bc68 100644
--- a/color.h
+++ b/color.h
@@ -88,7 +88,9 @@ int git_config_colorbool(const char *var, const char *value);
  * Return a boolean whether to use color, where the argument 'var' is
  * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.
  */
-int want_color(int var);
+int want_color_fd(int fd, int var);
+#define want_color(colorbool) want_color_fd(1, (colorbool))
+#define want_color_stderr(colorbool) want_color_fd(2, (colorbool))
 
 /*
  * Translate a Git color from 'value' into a string that the terminal can
-- 
2.17.0.windows.1.4.g7e4058d72e3



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

* [PATCH v2 2/4] push: colorize errors
  2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
  2018-04-05 22:48   ` [PATCH v2 1/4] color: introduce support for colorizing stderr Johannes Schindelin
@ 2018-04-05 22:48   ` Johannes Schindelin
  2018-04-05 23:37     ` Jacob Keller
  2018-04-05 22:48   ` [PATCH v2 3/4] Add a test to verify that push errors are colorful Johannes Schindelin
                     ` (2 subsequent siblings)
  4 siblings, 1 reply; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-05 22:48 UTC (permalink / raw)
  To: git; +Cc: Ryan Dammrose, Junio C Hamano

From: Ryan Dammrose <ryandammrose@gmail.com>

This is an attempt to resolve an issue I experience with people that are
new to Git -- especially colleagues in a team setting -- where they miss
that their push to a remote location failed because the failure and
success both return a block of white text.

An example is if I push something to a remote repository and then a
colleague attempts to push to the same remote repository and the push
fails because it requires them to pull first, but they don't notice
because a success and failure both return a block of white text. They
then continue about their business, thinking it has been successfully
pushed.

This patch colorizes the errors and hints (in red and yellow,
respectively) so whenever there is a failure when pushing to a remote
repository that fails, it is more noticeable.

[jes: fixed a couple bugs, added the color.{advice,push,transport}
settings, refactored to use want_color_stderr().]

Signed-off-by: Ryan Dammrose ryandammrose@gmail.com
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>

squash! push: colorize errors

Stop talking about localized errors
---
 advice.c       | 49 ++++++++++++++++++++++++++++++++++--
 builtin/push.c | 44 ++++++++++++++++++++++++++++++++-
 config.c       |  2 +-
 transport.c    | 67 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 157 insertions(+), 5 deletions(-)

diff --git a/advice.c b/advice.c
index 406efc183ba..2121c1811fd 100644
--- a/advice.c
+++ b/advice.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "config.h"
+#include "color.h"
 
 int advice_push_update_rejected = 1;
 int advice_push_non_ff_current = 1;
@@ -20,6 +21,33 @@ int advice_add_embedded_repo = 1;
 int advice_ignored_hook = 1;
 int advice_waiting_for_editor = 1;
 
+static int advice_use_color = -1;
+static char advice_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_YELLOW,	/* HINT */
+};
+
+enum color_advice {
+	ADVICE_COLOR_RESET = 0,
+	ADVICE_COLOR_HINT = 1,
+};
+
+static int parse_advise_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return ADVICE_COLOR_RESET;
+	if (!strcasecmp(slot, "advice"))
+		return ADVICE_COLOR_HINT;
+	return -1;
+}
+
+static const char *advise_get_color(enum color_advice ix)
+{
+	if (want_color_stderr(advice_use_color))
+		return advice_colors[ix];
+	return "";
+}
+
 static struct {
 	const char *name;
 	int *preference;
@@ -59,7 +87,10 @@ void advise(const char *advice, ...)
 
 	for (cp = buf.buf; *cp; cp = np) {
 		np = strchrnul(cp, '\n');
-		fprintf(stderr,	_("hint: %.*s\n"), (int)(np - cp), cp);
+		fprintf(stderr,	_("%shint: %.*s%s\n"),
+			advise_get_color(ADVICE_COLOR_HINT),
+			(int)(np - cp), cp,
+			advise_get_color(ADVICE_COLOR_RESET));
 		if (*np)
 			np++;
 	}
@@ -68,9 +99,23 @@ void advise(const char *advice, ...)
 
 int git_default_advice_config(const char *var, const char *value)
 {
-	const char *k;
+	const char *k, *slot_name;
 	int i;
 
+	if (!strcmp(var, "color.advice")) {
+		advice_use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+
+	if (skip_prefix(var, "color.advice.", &slot_name)) {
+		int slot = parse_advise_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!value)
+			return config_error_nonbool(var);
+		return color_parse(value, advice_colors[slot]);
+	}
+
 	if (!skip_prefix(var, "advice.", &k))
 		return 0;
 
diff --git a/builtin/push.c b/builtin/push.c
index 013c20d6164..ac3705370e1 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -12,12 +12,40 @@
 #include "submodule.h"
 #include "submodule-config.h"
 #include "send-pack.h"
+#include "color.h"
 
 static const char * const push_usage[] = {
 	N_("git push [<options>] [<repository> [<refspec>...]]"),
 	NULL,
 };
 
+static int push_use_color = -1;
+static char push_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_RED,	/* ERROR */
+};
+
+enum color_push {
+	PUSH_COLOR_RESET = 0,
+	PUSH_COLOR_ERROR = 1
+};
+
+static int parse_push_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return PUSH_COLOR_RESET;
+	if (!strcasecmp(slot, "error"))
+		return PUSH_COLOR_ERROR;
+	return -1;
+}
+
+static const char *push_get_color(enum color_push ix)
+{
+	if (want_color_stderr(push_use_color))
+		return push_colors[ix];
+	return "";
+}
+
 static int thin = 1;
 static int deleterefs;
 static const char *receivepack;
@@ -337,8 +365,11 @@ static int push_with_options(struct transport *transport, int flags)
 		fprintf(stderr, _("Pushing to %s\n"), transport->url);
 	err = transport_push(transport, refspec_nr, refspec, flags,
 			     &reject_reasons);
-	if (err != 0)
+	if (err != 0) {
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
 		error(_("failed to push some refs to '%s'"), transport->url);
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_RESET));
+	}
 
 	err |= transport_disconnect(transport);
 	if (!err)
@@ -467,6 +498,7 @@ static void set_push_cert_flags(int *flags, int v)
 
 static int git_push_config(const char *k, const char *v, void *cb)
 {
+	const char *slot_name;
 	int *flags = cb;
 	int status;
 
@@ -514,6 +546,16 @@ static int git_push_config(const char *k, const char *v, void *cb)
 			else
 				string_list_append(&push_options_config, v);
 		return 0;
+	} else if (!strcmp(k, "color.push")) {
+		push_use_color = git_config_colorbool(k, v);
+		return 0;
+	} else if (skip_prefix(k, "color.push.", &slot_name)) {
+		int slot = parse_push_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!v)
+			return config_error_nonbool(k);
+		return color_parse(v, push_colors[slot]);
 	}
 
 	return git_default_config(k, v, NULL);
diff --git a/config.c b/config.c
index b0c20e6cb8a..3bdbe36a638 100644
--- a/config.c
+++ b/config.c
@@ -1365,7 +1365,7 @@ int git_default_config(const char *var, const char *value, void *dummy)
 	if (starts_with(var, "mailmap."))
 		return git_default_mailmap_config(var, value);
 
-	if (starts_with(var, "advice."))
+	if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
 		return git_default_advice_config(var, value);
 
 	if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
diff --git a/transport.c b/transport.c
index 00d48b5b565..4702b9fbc8f 100644
--- a/transport.c
+++ b/transport.c
@@ -18,6 +18,56 @@
 #include "sha1-array.h"
 #include "sigchain.h"
 #include "transport-internal.h"
+#include "color.h"
+
+static int transport_use_color = -1;
+static char transport_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_RED		/* REJECTED */
+};
+
+enum color_transport {
+	TRANSPORT_COLOR_RESET = 0,
+	TRANSPORT_COLOR_REJECTED = 1
+};
+
+static int transport_color_config(void)
+{
+	const char *keys[] = {
+		"color.transport.reset",
+		"color.transport.rejected"
+	}, *key = "color.transport";
+	char *value;
+	int i;
+	static int initialized;
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	if (!git_config_get_string(key, &value))
+		transport_use_color = git_config_colorbool(key, value);
+
+	if (!want_color_stderr(transport_use_color))
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(keys); i++)
+		if (!git_config_get_string(keys[i], &value)) {
+			if (!value)
+				return config_error_nonbool(keys[i]);
+			if (color_parse(value, transport_colors[i]) < 0)
+				return -1;
+		}
+
+	return 0;
+}
+
+static const char *transport_get_color(enum color_transport ix)
+{
+	if (want_color_stderr(transport_use_color))
+		return transport_colors[ix];
+	return "";
+}
 
 static void set_upstreams(struct transport *transport, struct ref *refs,
 	int pretend)
@@ -338,7 +388,13 @@ static void print_ref_status(char flag, const char *summary,
 		else
 			fprintf(stdout, "%s\n", summary);
 	} else {
-		fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
+		const char *red = "", *reset = "";
+		if (push_had_errors(to)) {
+			red = transport_get_color(TRANSPORT_COLOR_REJECTED);
+			reset = transport_get_color(TRANSPORT_COLOR_RESET);
+		}
+		fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
+			summary, reset);
 		if (from)
 			fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
 		else
@@ -487,6 +543,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,
 	char *head;
 	int summary_width = transport_summary_width(refs);
 
+	if (transport_color_config() < 0)
+		warning(_("could not parse transport.color.* config"));
+
 	head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
 
 	if (verbose) {
@@ -553,6 +612,9 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 	struct send_pack_args args;
 	int ret;
 
+	if (transport_color_config() < 0)
+		return -1;
+
 	if (!data->got_remote_heads) {
 		struct ref *tmp_refs;
 		connect_setup(transport, 1);
@@ -997,6 +1059,9 @@ int transport_push(struct transport *transport,
 	*reject_reasons = 0;
 	transport_verify_remote_names(refspec_nr, refspec);
 
+	if (transport_color_config() < 0)
+		return -1;
+
 	if (transport->vtable->push_refs) {
 		struct ref *remote_refs;
 		struct ref *local_refs = get_local_heads();
-- 
2.17.0.windows.1.4.g7e4058d72e3



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

* [PATCH v2 3/4] Add a test to verify that push errors are colorful
  2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
  2018-04-05 22:48   ` [PATCH v2 1/4] color: introduce support for colorizing stderr Johannes Schindelin
  2018-04-05 22:48   ` [PATCH v2 2/4] push: colorize errors Johannes Schindelin
@ 2018-04-05 22:48   ` Johannes Schindelin
  2018-04-06 10:50     ` Eric Sunshine
  2018-04-05 22:48   ` [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints Johannes Schindelin
  2018-04-21 10:09   ` [PATCH v3 0/4] Colorize push errors Johannes Schindelin
  4 siblings, 1 reply; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-05 22:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

This actually only tests whether the push errors/hints are colored if
the respective color.* config settings are `always`, but in the regular
case they default to `auto` (in which case we color the messages when
stderr is connected to an interactive terminal), therefore these tests
should suffice.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t5541-http-push-smart.sh | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index 21340e89c96..1c2be98dc2b 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -377,5 +377,23 @@ test_expect_success 'push status output scrubs password' '
 	grep "^To $HTTPD_URL/smart/test_repo.git" status
 '
 
+test_expect_success 'colorize errors/hints' '
+	cd "$ROOT_PATH"/test_repo_clone &&
+	cat >exp <<-EOF &&
+	To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
+	 <RED>! [rejected]       <RESET> origin/master^ -> master (non-fast-forward)
+	error: failed to push some refs to '\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\''
+	EOF
+
+	test_must_fail git -c color.transport=always -c color.advice=always \
+		-c color.push=always \
+		push origin origin/master^:master 2>act &&
+	test_decode_color <act >decoded &&
+	test_i18ngrep "<RED>.*rejected.*<RESET>" decoded &&
+	test_i18ngrep "<RED>error: failed to push some refs" decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded &&
+	test_i18ngrep ! "^hint: " decoded
+'
+
 stop_httpd
 test_done
-- 
2.17.0.windows.1.4.g7e4058d72e3



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

* [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints
  2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
                     ` (2 preceding siblings ...)
  2018-04-05 22:48   ` [PATCH v2 3/4] Add a test to verify that push errors are colorful Johannes Schindelin
@ 2018-04-05 22:48   ` Johannes Schindelin
  2018-04-06 10:56     ` Eric Sunshine
  2018-04-21 10:09   ` [PATCH v3 0/4] Colorize push errors Johannes Schindelin
  4 siblings, 1 reply; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-05 22:48 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano

Let's make it easier for users to find out how to customize these colors.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Documentation/config.txt | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 4e0cff87f62..40e3828b85f 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1088,6 +1088,16 @@ clean.requireForce::
 	A boolean to make git-clean do nothing unless given -f,
 	-i or -n.   Defaults to true.
 
+color.advice::
+	A boolean to enable/disable color in hints (e.g. when a push
+	failed, see `advice.*` for a list).  May be set to `always`,
+	`false` (or `never`) or `auto` (or `true`), in which case colors
+	are used only when the error output goes to a terminal. If
+	unset, then the value of `color.ui` is used (`auto` by default).
+
+color.advice.advice::
+	Use customized color for hints.
+
 color.branch::
 	A boolean to enable/disable color in the output of
 	linkgit:git-branch[1]. May be set to `always`,
@@ -1190,6 +1200,15 @@ color.pager::
 	A boolean to enable/disable colored output when the pager is in
 	use (default is true).
 
+color.push::
+	A boolean to enable/disable color in push errors. May be set to
+	`always`, `false` (or `never`) or `auto` (or `true`), in which
+	case colors are used only when the error output goes to a terminal.
+	If unset, then the value of `color.ui` is used (`auto` by default).
+
+color.push.error::
+	Use customized color for push errors.
+
 color.showBranch::
 	A boolean to enable/disable color in the output of
 	linkgit:git-show-branch[1]. May be set to `always`,
@@ -1218,6 +1237,15 @@ color.status.<slot>::
 	status short-format), or
 	`unmerged` (files which have unmerged changes).
 
+color.transport::
+	A boolean to enable/disable color when pushes are rejected. May be
+	set to `always`, `false` (or `never`) or `auto` (or `true`), in which
+	case colors are used only when the error output goes to a terminal.
+	If unset, then the value of `color.ui` is used (`auto` by default).
+
+color.transport.rejected::
+	Use customized color when a push was rejected.
+
 color.ui::
 	This variable determines the default value for variables such
 	as `color.diff` and `color.grep` that control the use of color
-- 
2.17.0.windows.1.4.g7e4058d72e3

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

* Re: [PATCH v2 2/4] push: colorize errors
  2018-04-05 22:48   ` [PATCH v2 2/4] push: colorize errors Johannes Schindelin
@ 2018-04-05 23:37     ` Jacob Keller
  2018-04-06 11:15       ` Johannes Schindelin
  0 siblings, 1 reply; 22+ messages in thread
From: Jacob Keller @ 2018-04-05 23:37 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Git mailing list, Ryan Dammrose, Junio C Hamano

On Thu, Apr 5, 2018 at 3:48 PM, Johannes Schindelin
<johannes.schindelin@gmx.de> wrote:
> From: Ryan Dammrose <ryandammrose@gmail.com>
>
> This is an attempt to resolve an issue I experience with people that are
> new to Git -- especially colleagues in a team setting -- where they miss
> that their push to a remote location failed because the failure and
> success both return a block of white text.
>
> An example is if I push something to a remote repository and then a
> colleague attempts to push to the same remote repository and the push
> fails because it requires them to pull first, but they don't notice
> because a success and failure both return a block of white text. They
> then continue about their business, thinking it has been successfully
> pushed.
>
> This patch colorizes the errors and hints (in red and yellow,
> respectively) so whenever there is a failure when pushing to a remote
> repository that fails, it is more noticeable.
>
> [jes: fixed a couple bugs, added the color.{advice,push,transport}
> settings, refactored to use want_color_stderr().]
>
> Signed-off-by: Ryan Dammrose ryandammrose@gmail.com
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
>
> squash! push: colorize errors
>
> Stop talking about localized errors

Guessing you intended to remove this part after squashing?

Didn't see anything else to comment on in the actual code.

Thanks,
Jake

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

* Re: [PATCH v2 3/4] Add a test to verify that push errors are colorful
  2018-04-05 22:48   ` [PATCH v2 3/4] Add a test to verify that push errors are colorful Johannes Schindelin
@ 2018-04-06 10:50     ` Eric Sunshine
  2018-04-06 12:13       ` Johannes Schindelin
  0 siblings, 1 reply; 22+ messages in thread
From: Eric Sunshine @ 2018-04-06 10:50 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Git List, Junio C Hamano

On Thu, Apr 5, 2018 at 6:48 PM, Johannes Schindelin
<johannes.schindelin@gmx.de> wrote:
> This actually only tests whether the push errors/hints are colored if
> the respective color.* config settings are `always`, but in the regular
> case they default to `auto` (in which case we color the messages when
> stderr is connected to an interactive terminal), therefore these tests
> should suffice.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
> diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
> @@ -377,5 +377,23 @@ test_expect_success 'push status output scrubs password' '
> +test_expect_success 'colorize errors/hints' '
> +       cd "$ROOT_PATH"/test_repo_clone &&
> +       cat >exp <<-EOF &&
> +       To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
> +        <RED>! [rejected]       <RESET> origin/master^ -> master (non-fast-forward)
> +       error: failed to push some refs to '\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\''
> +       EOF

This "exp" file is not used by the test.

> +       test_must_fail git -c color.transport=always -c color.advice=always \
> +               -c color.push=always \
> +               push origin origin/master^:master 2>act &&
> +       test_decode_color <act >decoded &&
> +       test_i18ngrep "<RED>.*rejected.*<RESET>" decoded &&
> +       test_i18ngrep "<RED>error: failed to push some refs" decoded &&
> +       test_i18ngrep "<YELLOW>hint: " decoded &&
> +       test_i18ngrep ! "^hint: " decoded
> +'

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

* Re: [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints
  2018-04-05 22:48   ` [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints Johannes Schindelin
@ 2018-04-06 10:56     ` Eric Sunshine
  2018-04-06 12:15       ` Johannes Schindelin
  0 siblings, 1 reply; 22+ messages in thread
From: Eric Sunshine @ 2018-04-06 10:56 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Git List, Junio C Hamano

On Thu, Apr 5, 2018 at 6:48 PM, Johannes Schindelin
<johannes.schindelin@gmx.de> wrote:
> Let's make it easier for users to find out how to customize these colors.
>
> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> ---
> diff --git a/Documentation/config.txt b/Documentation/config.txt
> @@ -1088,6 +1088,16 @@ clean.requireForce::
> +color.advice::
> +       A boolean to enable/disable color in hints (e.g. when a push
> +       failed, see `advice.*` for a list).  May be set to `always`,
> +       `false` (or `never`) or `auto` (or `true`), in which case colors
> +       are used only when the error output goes to a terminal. If
> +       unset, then the value of `color.ui` is used (`auto` by default).
> +
> +color.advice.advice::
> +       Use customized color for hints.

Is "color.advice.advice" correct?

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

* Re: [PATCH v2 2/4] push: colorize errors
  2018-04-05 23:37     ` Jacob Keller
@ 2018-04-06 11:15       ` Johannes Schindelin
  0 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-06 11:15 UTC (permalink / raw)
  To: Jacob Keller; +Cc: Git mailing list, Ryan Dammrose, Junio C Hamano

Hi Jake,

On Thu, 5 Apr 2018, Jacob Keller wrote:

> On Thu, Apr 5, 2018 at 3:48 PM, Johannes Schindelin
> <johannes.schindelin@gmx.de> wrote:
> > From: Ryan Dammrose <ryandammrose@gmail.com>
> >
> > This is an attempt to resolve an issue I experience with people that are
> > new to Git -- especially colleagues in a team setting -- where they miss
> > that their push to a remote location failed because the failure and
> > success both return a block of white text.
> >
> > An example is if I push something to a remote repository and then a
> > colleague attempts to push to the same remote repository and the push
> > fails because it requires them to pull first, but they don't notice
> > because a success and failure both return a block of white text. They
> > then continue about their business, thinking it has been successfully
> > pushed.
> >
> > This patch colorizes the errors and hints (in red and yellow,
> > respectively) so whenever there is a failure when pushing to a remote
> > repository that fails, it is more noticeable.
> >
> > [jes: fixed a couple bugs, added the color.{advice,push,transport}
> > settings, refactored to use want_color_stderr().]
> >
> > Signed-off-by: Ryan Dammrose ryandammrose@gmail.com
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> >
> > squash! push: colorize errors
> >
> > Stop talking about localized errors
> 
> Guessing you intended to remove this part after squashing?

Hah! You caught be red-handed.

This was intended as a reminder, as you probably guessed, to remove any
mentions of "localized errors" because I had verified that there was no
localized error message; besides, I replaced the call to strstr() looking
at the error message with a call to push_had_errors() (i.e. using the
ref_status instead). So there are definitely no issues about localized
errors left.

> Didn't see anything else to comment on in the actual code.

Thank you,
Dscho

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

* Re: [PATCH 0/1] Colorize some errors on stderr
  2018-02-16 19:21 ` [PATCH 0/1] Colorize some errors on stderr Junio C Hamano
@ 2018-04-06 11:21   ` Johannes Schindelin
  0 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-06 11:21 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Hi Junio,

[and welcome back, at least I hope you only read this after a good and
relaxing vacation]

On Fri, 16 Feb 2018, Junio C Hamano wrote:

> Johannes Schindelin <johannes.schindelin@gmx.de> writes:
> 
> > Now, what would be possible solutions for this?
> >
> > - introduce `int fd` in `want_color()` (and callees) so that we can make
> >   a distinction whether we want to detect whether stdout or stderr is connected
> >   to a tty
> >
> > - introduce a separate `want_color_stderr()` (we still would need to decide
> >   whether we want a config setting for this)
> 
> Between the above two, there probably aren't so big a difference, but
> in order to avoid disrupting existing callers of want_color() while
> possibly sharing as much code between the old and new callers,
> perhaps:
> 
> 	extern int want_color_fd(int fd, int colorbool);
> 	#define want_color(colorbool) want_color_fd(1, (colorbool))
> 	#define want_color_stderr(colorbool) want_color_fd(2, (colorbool))

I made it so.

Note that I also had to change the check_auto_color() function, and while
want_color_fd() can have a "private" record of previous results,
check_auto_color() needs to use the global color_stdout_is_tty (so that
builtin/config.c can edit it, for use in `git config --colorbool <name>
[stdout-is-tty]`).

> We should honor configuration at two levels, just like the colors on
> stdout, i.e. color in which individual items are painted (e.g.
> color.diff.filename, color.advice.hint) and whether we use colors in
> UI at all (e.g. color.ui).

This is how v2 does it.

Thanks for your suggestions,
Dscho

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

* Re: [PATCH v2 3/4] Add a test to verify that push errors are colorful
  2018-04-06 10:50     ` Eric Sunshine
@ 2018-04-06 12:13       ` Johannes Schindelin
  0 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-06 12:13 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Junio C Hamano

Hi Eric,


On Fri, 6 Apr 2018, Eric Sunshine wrote:

> On Thu, Apr 5, 2018 at 6:48 PM, Johannes Schindelin
> <johannes.schindelin@gmx.de> wrote:
> > This actually only tests whether the push errors/hints are colored if
> > the respective color.* config settings are `always`, but in the regular
> > case they default to `auto` (in which case we color the messages when
> > stderr is connected to an interactive terminal), therefore these tests
> > should suffice.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> > diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
> > @@ -377,5 +377,23 @@ test_expect_success 'push status output scrubs password' '
> > +test_expect_success 'colorize errors/hints' '
> > +       cd "$ROOT_PATH"/test_repo_clone &&
> > +       cat >exp <<-EOF &&
> > +       To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
> > +        <RED>! [rejected]       <RESET> origin/master^ -> master (non-fast-forward)
> > +       error: failed to push some refs to '\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\''
> > +       EOF
> 
> This "exp" file is not used by the test.

Indeed! I was *so* sure I had removed it, but a `git stash` must have made
that change go away before I could commit it.

Will be fixed in v3.

Ciao,
Dscho

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

* Re: [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints
  2018-04-06 10:56     ` Eric Sunshine
@ 2018-04-06 12:15       ` Johannes Schindelin
  2018-04-07  6:55         ` Eric Sunshine
  0 siblings, 1 reply; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-06 12:15 UTC (permalink / raw)
  To: Eric Sunshine; +Cc: Git List, Junio C Hamano

Hi Eric,

On Fri, 6 Apr 2018, Eric Sunshine wrote:

> On Thu, Apr 5, 2018 at 6:48 PM, Johannes Schindelin
> <johannes.schindelin@gmx.de> wrote:
> > Let's make it easier for users to find out how to customize these colors.
> >
> > Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
> > ---
> > diff --git a/Documentation/config.txt b/Documentation/config.txt
> > @@ -1088,6 +1088,16 @@ clean.requireForce::
> > +color.advice::
> > +       A boolean to enable/disable color in hints (e.g. when a push
> > +       failed, see `advice.*` for a list).  May be set to `always`,
> > +       `false` (or `never`) or `auto` (or `true`), in which case colors
> > +       are used only when the error output goes to a terminal. If
> > +       unset, then the value of `color.ui` is used (`auto` by default).
> > +
> > +color.advice.advice::
> > +       Use customized color for hints.
> 
> Is "color.advice.advice" correct?

As per the patch, yes. But you're right, it sounds silly. Will change to
`color.advice.hint`, okay?

Will be fixed in v3,
Dscho

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

* Re: [PATCH 0/1] Colorize some errors on stderr
  2018-02-16 12:25 [PATCH 0/1] Colorize some errors on stderr Johannes Schindelin
                   ` (2 preceding siblings ...)
  2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
@ 2018-04-06 18:48 ` Ævar Arnfjörð Bjarmason
  3 siblings, 0 replies; 22+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-04-06 18:48 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: git, Junio C Hamano


On Fri, Feb 16 2018, Johannes Schindelin wrote:

> This is an RFC because it tries to introduce a fundamental new color feature:
> Coloring messages *on stderr*.

I missed this the first time around, and don't have anything to add that
others haven't covered. Just wanted to say I'd love to get this into
git, it's a great UI improvement.

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

* Re: [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints
  2018-04-06 12:15       ` Johannes Schindelin
@ 2018-04-07  6:55         ` Eric Sunshine
  0 siblings, 0 replies; 22+ messages in thread
From: Eric Sunshine @ 2018-04-07  6:55 UTC (permalink / raw)
  To: Johannes Schindelin; +Cc: Git List, Junio C Hamano

On Fri, Apr 6, 2018 at 8:15 AM, Johannes Schindelin
<Johannes.Schindelin@gmx.de> wrote:
> On Fri, 6 Apr 2018, Eric Sunshine wrote:
>> On Thu, Apr 5, 2018 at 6:48 PM, Johannes Schindelin
>> <johannes.schindelin@gmx.de> wrote:
>> > +color.advice.advice::
>> > +       Use customized color for hints.
>>
>> Is "color.advice.advice" correct?
>
> As per the patch, yes. But you're right, it sounds silly. Will change to
> `color.advice.hint`, okay?

That's more understandable. Thanks.

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

* [PATCH v3 0/4] Colorize push errors
  2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
                     ` (3 preceding siblings ...)
  2018-04-05 22:48   ` [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints Johannes Schindelin
@ 2018-04-21 10:09   ` Johannes Schindelin
  2018-04-21 10:09     ` [PATCH v3 1/4] color: introduce support for colorizing stderr Johannes Schindelin
                       ` (3 more replies)
  4 siblings, 4 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-21 10:09 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Eric Sunshine, Jacob Keller,
	Ævar Arnfjörð Bjarmason

To help users discern large chunks of white text (when the push
succeeds) from large chunks of white text (when the push fails), let's
add some color to the latter.

The original contribution came in via Pull Request from the Git for
Windows project:

	https://github.com/git-for-windows/git/pull/1429

I almost forgot to submit v3. Guess it's a good thing I have a project
management system with tickets I can move through a story board...

Changes since v2:

- removed a bogus "squash! ..." from the commit message of 2/4

- removed the unnecessary here-doc from the test added in 4/4

- renamed color.advice.advice to color.advice.hint in 2/4 and 4/4


Johannes Schindelin (3):
  color: introduce support for colorizing stderr
  Add a test to verify that push errors are colorful
  Document the new color.* settings to colorize push errors/hints

Ryan Dammrose (1):
  push: colorize errors

 Documentation/config.txt   | 28 ++++++++++++++++
 advice.c                   | 49 ++++++++++++++++++++++++++--
 builtin/push.c             | 44 ++++++++++++++++++++++++-
 color.c                    | 20 +++++++-----
 color.h                    |  4 ++-
 config.c                   |  2 +-
 t/t5541-http-push-smart.sh | 12 +++++++
 transport.c                | 67 +++++++++++++++++++++++++++++++++++++-
 8 files changed, 211 insertions(+), 15 deletions(-)


base-commit: fe0a9eaf31dd0c349ae4308498c33a5c3794b293
Published-As: https://github.com/dscho/git/releases/tag/colorize-push-errors-v3
Fetch-It-Via: git fetch https://github.com/dscho/git colorize-push-errors-v3

Interdiff vs v2:
 diff --git a/Documentation/config.txt b/Documentation/config.txt
 index 1fef60a7301..2cea0c6c899 100644
 --- a/Documentation/config.txt
 +++ b/Documentation/config.txt
 @@ -1095,7 +1095,7 @@ color.advice::
  	are used only when the error output goes to a terminal. If
  	unset, then the value of `color.ui` is used (`auto` by default).
  
 -color.advice.advice::
 +color.advice.hint::
  	Use customized color for hints.
  
  color.branch::
 diff --git a/advice.c b/advice.c
 index 2121c1811fd..89fda1de55b 100644
 --- a/advice.c
 +++ b/advice.c
 @@ -36,7 +36,7 @@ static int parse_advise_color_slot(const char *slot)
  {
  	if (!strcasecmp(slot, "reset"))
  		return ADVICE_COLOR_RESET;
 -	if (!strcasecmp(slot, "advice"))
 +	if (!strcasecmp(slot, "hint"))
  		return ADVICE_COLOR_HINT;
  	return -1;
  }
 diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
 index 1c2be98dc2b..a2af693068f 100755
 --- a/t/t5541-http-push-smart.sh
 +++ b/t/t5541-http-push-smart.sh
 @@ -379,12 +379,6 @@ test_expect_success 'push status output scrubs password' '
  
  test_expect_success 'colorize errors/hints' '
  	cd "$ROOT_PATH"/test_repo_clone &&
 -	cat >exp <<-EOF &&
 -	To http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git
 -	 <RED>! [rejected]       <RESET> origin/master^ -> master (non-fast-forward)
 -	error: failed to push some refs to '\''http://127.0.0.1:$LIB_HTTPD_PORT/smart/test_repo.git'\''
 -	EOF
 -
  	test_must_fail git -c color.transport=always -c color.advice=always \
  		-c color.push=always \
  		push origin origin/master^:master 2>act &&
-- 
2.17.0.windows.1.15.gaa56ade3205


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

* [PATCH v3 1/4] color: introduce support for colorizing stderr
  2018-04-21 10:09   ` [PATCH v3 0/4] Colorize push errors Johannes Schindelin
@ 2018-04-21 10:09     ` Johannes Schindelin
  2018-04-21 10:10     ` [PATCH v3 2/4] push: colorize errors Johannes Schindelin
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-21 10:09 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Eric Sunshine, Jacob Keller,
	Ævar Arnfjörð Bjarmason

So far, we only ever asked whether stdout wants to be colorful. In the
upcoming patches, we will want to make push errors more prominent, which
are printed to stderr, though.

So let's refactor the want_color() function into a want_color_fd()
function (which expects to be called with fd == 1 or fd == 2 for stdout
and stderr, respectively), and then define the macro `want_color()` to
use the want_color_fd() function.

And then also add a macro `want_color_stderr()`, for convenience and
for documentation.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 color.c | 20 +++++++++++---------
 color.h |  4 +++-
 2 files changed, 14 insertions(+), 10 deletions(-)

diff --git a/color.c b/color.c
index f277e72e4ce..c6c6c4f580f 100644
--- a/color.c
+++ b/color.c
@@ -319,18 +319,20 @@ int git_config_colorbool(const char *var, const char *value)
 	return GIT_COLOR_AUTO;
 }
 
-static int check_auto_color(void)
+static int check_auto_color(int fd)
 {
-	if (color_stdout_is_tty < 0)
-		color_stdout_is_tty = isatty(1);
-	if (color_stdout_is_tty || (pager_in_use() && pager_use_color)) {
+	static int color_stderr_is_tty = -1;
+	int *is_tty_p = fd == 1 ? &color_stdout_is_tty : &color_stderr_is_tty;
+	if (*is_tty_p < 0)
+		*is_tty_p = isatty(fd);
+	if (*is_tty_p || (fd == 1 && pager_in_use() && pager_use_color)) {
 		if (!is_terminal_dumb())
 			return 1;
 	}
 	return 0;
 }
 
-int want_color(int var)
+int want_color_fd(int fd, int var)
 {
 	/*
 	 * NEEDSWORK: This function is sometimes used from multiple threads, and
@@ -339,15 +341,15 @@ int want_color(int var)
 	 * is listed in .tsan-suppressions for the time being.
 	 */
 
-	static int want_auto = -1;
+	static int want_auto[3] = { -1, -1, -1 };
 
 	if (var < 0)
 		var = git_use_color_default;
 
 	if (var == GIT_COLOR_AUTO) {
-		if (want_auto < 0)
-			want_auto = check_auto_color();
-		return want_auto;
+		if (want_auto[fd] < 0)
+			want_auto[fd] = check_auto_color(fd);
+		return want_auto[fd];
 	}
 	return var;
 }
diff --git a/color.h b/color.h
index cd0bcedd084..5b744e1bc68 100644
--- a/color.h
+++ b/color.h
@@ -88,7 +88,9 @@ int git_config_colorbool(const char *var, const char *value);
  * Return a boolean whether to use color, where the argument 'var' is
  * one of GIT_COLOR_UNKNOWN, GIT_COLOR_NEVER, GIT_COLOR_ALWAYS, GIT_COLOR_AUTO.
  */
-int want_color(int var);
+int want_color_fd(int fd, int var);
+#define want_color(colorbool) want_color_fd(1, (colorbool))
+#define want_color_stderr(colorbool) want_color_fd(2, (colorbool))
 
 /*
  * Translate a Git color from 'value' into a string that the terminal can
-- 
2.17.0.windows.1.15.gaa56ade3205



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

* [PATCH v3 2/4] push: colorize errors
  2018-04-21 10:09   ` [PATCH v3 0/4] Colorize push errors Johannes Schindelin
  2018-04-21 10:09     ` [PATCH v3 1/4] color: introduce support for colorizing stderr Johannes Schindelin
@ 2018-04-21 10:10     ` Johannes Schindelin
  2018-04-21 10:10     ` [PATCH v3 3/4] Add a test to verify that push errors are colorful Johannes Schindelin
  2018-04-21 10:10     ` [PATCH v3 4/4] Document the new color.* settings to colorize push errors/hints Johannes Schindelin
  3 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-21 10:10 UTC (permalink / raw)
  To: git
  Cc: Ryan Dammrose, Junio C Hamano, Eric Sunshine, Jacob Keller,
	Ævar Arnfjörð Bjarmason

From: Ryan Dammrose <ryandammrose@gmail.com>

This is an attempt to resolve an issue I experience with people that are
new to Git -- especially colleagues in a team setting -- where they miss
that their push to a remote location failed because the failure and
success both return a block of white text.

An example is if I push something to a remote repository and then a
colleague attempts to push to the same remote repository and the push
fails because it requires them to pull first, but they don't notice
because a success and failure both return a block of white text. They
then continue about their business, thinking it has been successfully
pushed.

This patch colorizes the errors and hints (in red and yellow,
respectively) so whenever there is a failure when pushing to a remote
repository that fails, it is more noticeable.

[jes: fixed a couple bugs, added the color.{advice,push,transport}
settings, refactored to use want_color_stderr().]

Signed-off-by: Ryan Dammrose ryandammrose@gmail.com
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 advice.c       | 49 ++++++++++++++++++++++++++++++++++--
 builtin/push.c | 44 ++++++++++++++++++++++++++++++++-
 config.c       |  2 +-
 transport.c    | 67 +++++++++++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 157 insertions(+), 5 deletions(-)

diff --git a/advice.c b/advice.c
index 406efc183ba..89fda1de55b 100644
--- a/advice.c
+++ b/advice.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "config.h"
+#include "color.h"
 
 int advice_push_update_rejected = 1;
 int advice_push_non_ff_current = 1;
@@ -20,6 +21,33 @@ int advice_add_embedded_repo = 1;
 int advice_ignored_hook = 1;
 int advice_waiting_for_editor = 1;
 
+static int advice_use_color = -1;
+static char advice_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_YELLOW,	/* HINT */
+};
+
+enum color_advice {
+	ADVICE_COLOR_RESET = 0,
+	ADVICE_COLOR_HINT = 1,
+};
+
+static int parse_advise_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return ADVICE_COLOR_RESET;
+	if (!strcasecmp(slot, "hint"))
+		return ADVICE_COLOR_HINT;
+	return -1;
+}
+
+static const char *advise_get_color(enum color_advice ix)
+{
+	if (want_color_stderr(advice_use_color))
+		return advice_colors[ix];
+	return "";
+}
+
 static struct {
 	const char *name;
 	int *preference;
@@ -59,7 +87,10 @@ void advise(const char *advice, ...)
 
 	for (cp = buf.buf; *cp; cp = np) {
 		np = strchrnul(cp, '\n');
-		fprintf(stderr,	_("hint: %.*s\n"), (int)(np - cp), cp);
+		fprintf(stderr,	_("%shint: %.*s%s\n"),
+			advise_get_color(ADVICE_COLOR_HINT),
+			(int)(np - cp), cp,
+			advise_get_color(ADVICE_COLOR_RESET));
 		if (*np)
 			np++;
 	}
@@ -68,9 +99,23 @@ void advise(const char *advice, ...)
 
 int git_default_advice_config(const char *var, const char *value)
 {
-	const char *k;
+	const char *k, *slot_name;
 	int i;
 
+	if (!strcmp(var, "color.advice")) {
+		advice_use_color = git_config_colorbool(var, value);
+		return 0;
+	}
+
+	if (skip_prefix(var, "color.advice.", &slot_name)) {
+		int slot = parse_advise_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!value)
+			return config_error_nonbool(var);
+		return color_parse(value, advice_colors[slot]);
+	}
+
 	if (!skip_prefix(var, "advice.", &k))
 		return 0;
 
diff --git a/builtin/push.c b/builtin/push.c
index 013c20d6164..ac3705370e1 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -12,12 +12,40 @@
 #include "submodule.h"
 #include "submodule-config.h"
 #include "send-pack.h"
+#include "color.h"
 
 static const char * const push_usage[] = {
 	N_("git push [<options>] [<repository> [<refspec>...]]"),
 	NULL,
 };
 
+static int push_use_color = -1;
+static char push_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_RED,	/* ERROR */
+};
+
+enum color_push {
+	PUSH_COLOR_RESET = 0,
+	PUSH_COLOR_ERROR = 1
+};
+
+static int parse_push_color_slot(const char *slot)
+{
+	if (!strcasecmp(slot, "reset"))
+		return PUSH_COLOR_RESET;
+	if (!strcasecmp(slot, "error"))
+		return PUSH_COLOR_ERROR;
+	return -1;
+}
+
+static const char *push_get_color(enum color_push ix)
+{
+	if (want_color_stderr(push_use_color))
+		return push_colors[ix];
+	return "";
+}
+
 static int thin = 1;
 static int deleterefs;
 static const char *receivepack;
@@ -337,8 +365,11 @@ static int push_with_options(struct transport *transport, int flags)
 		fprintf(stderr, _("Pushing to %s\n"), transport->url);
 	err = transport_push(transport, refspec_nr, refspec, flags,
 			     &reject_reasons);
-	if (err != 0)
+	if (err != 0) {
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
 		error(_("failed to push some refs to '%s'"), transport->url);
+		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_RESET));
+	}
 
 	err |= transport_disconnect(transport);
 	if (!err)
@@ -467,6 +498,7 @@ static void set_push_cert_flags(int *flags, int v)
 
 static int git_push_config(const char *k, const char *v, void *cb)
 {
+	const char *slot_name;
 	int *flags = cb;
 	int status;
 
@@ -514,6 +546,16 @@ static int git_push_config(const char *k, const char *v, void *cb)
 			else
 				string_list_append(&push_options_config, v);
 		return 0;
+	} else if (!strcmp(k, "color.push")) {
+		push_use_color = git_config_colorbool(k, v);
+		return 0;
+	} else if (skip_prefix(k, "color.push.", &slot_name)) {
+		int slot = parse_push_color_slot(slot_name);
+		if (slot < 0)
+			return 0;
+		if (!v)
+			return config_error_nonbool(k);
+		return color_parse(v, push_colors[slot]);
 	}
 
 	return git_default_config(k, v, NULL);
diff --git a/config.c b/config.c
index c698988f5e1..f21317a25a7 100644
--- a/config.c
+++ b/config.c
@@ -1365,7 +1365,7 @@ int git_default_config(const char *var, const char *value, void *dummy)
 	if (starts_with(var, "mailmap."))
 		return git_default_mailmap_config(var, value);
 
-	if (starts_with(var, "advice."))
+	if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
 		return git_default_advice_config(var, value);
 
 	if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
diff --git a/transport.c b/transport.c
index 94eccf29aa3..f72081a5a58 100644
--- a/transport.c
+++ b/transport.c
@@ -19,6 +19,56 @@
 #include "sigchain.h"
 #include "transport-internal.h"
 #include "object-store.h"
+#include "color.h"
+
+static int transport_use_color = -1;
+static char transport_colors[][COLOR_MAXLEN] = {
+	GIT_COLOR_RESET,
+	GIT_COLOR_RED		/* REJECTED */
+};
+
+enum color_transport {
+	TRANSPORT_COLOR_RESET = 0,
+	TRANSPORT_COLOR_REJECTED = 1
+};
+
+static int transport_color_config(void)
+{
+	const char *keys[] = {
+		"color.transport.reset",
+		"color.transport.rejected"
+	}, *key = "color.transport";
+	char *value;
+	int i;
+	static int initialized;
+
+	if (initialized)
+		return 0;
+	initialized = 1;
+
+	if (!git_config_get_string(key, &value))
+		transport_use_color = git_config_colorbool(key, value);
+
+	if (!want_color_stderr(transport_use_color))
+		return 0;
+
+	for (i = 0; i < ARRAY_SIZE(keys); i++)
+		if (!git_config_get_string(keys[i], &value)) {
+			if (!value)
+				return config_error_nonbool(keys[i]);
+			if (color_parse(value, transport_colors[i]) < 0)
+				return -1;
+		}
+
+	return 0;
+}
+
+static const char *transport_get_color(enum color_transport ix)
+{
+	if (want_color_stderr(transport_use_color))
+		return transport_colors[ix];
+	return "";
+}
 
 static void set_upstreams(struct transport *transport, struct ref *refs,
 	int pretend)
@@ -339,7 +389,13 @@ static void print_ref_status(char flag, const char *summary,
 		else
 			fprintf(stdout, "%s\n", summary);
 	} else {
-		fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
+		const char *red = "", *reset = "";
+		if (push_had_errors(to)) {
+			red = transport_get_color(TRANSPORT_COLOR_REJECTED);
+			reset = transport_get_color(TRANSPORT_COLOR_RESET);
+		}
+		fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
+			summary, reset);
 		if (from)
 			fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
 		else
@@ -488,6 +544,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,
 	char *head;
 	int summary_width = transport_summary_width(refs);
 
+	if (transport_color_config() < 0)
+		warning(_("could not parse transport.color.* config"));
+
 	head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
 
 	if (verbose) {
@@ -554,6 +613,9 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
 	struct send_pack_args args;
 	int ret;
 
+	if (transport_color_config() < 0)
+		return -1;
+
 	if (!data->got_remote_heads) {
 		struct ref *tmp_refs;
 		connect_setup(transport, 1);
@@ -998,6 +1060,9 @@ int transport_push(struct transport *transport,
 	*reject_reasons = 0;
 	transport_verify_remote_names(refspec_nr, refspec);
 
+	if (transport_color_config() < 0)
+		return -1;
+
 	if (transport->vtable->push_refs) {
 		struct ref *remote_refs;
 		struct ref *local_refs = get_local_heads();
-- 
2.17.0.windows.1.15.gaa56ade3205



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

* [PATCH v3 3/4] Add a test to verify that push errors are colorful
  2018-04-21 10:09   ` [PATCH v3 0/4] Colorize push errors Johannes Schindelin
  2018-04-21 10:09     ` [PATCH v3 1/4] color: introduce support for colorizing stderr Johannes Schindelin
  2018-04-21 10:10     ` [PATCH v3 2/4] push: colorize errors Johannes Schindelin
@ 2018-04-21 10:10     ` Johannes Schindelin
  2018-04-21 10:10     ` [PATCH v3 4/4] Document the new color.* settings to colorize push errors/hints Johannes Schindelin
  3 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-21 10:10 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Eric Sunshine, Jacob Keller,
	Ævar Arnfjörð Bjarmason

This actually only tests whether the push errors/hints are colored if
the respective color.* config settings are `always`, but in the regular
case they default to `auto` (in which case we color the messages when
stderr is connected to an interactive terminal), therefore these tests
should suffice.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 t/t5541-http-push-smart.sh | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index 21340e89c96..a2af693068f 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -377,5 +377,17 @@ test_expect_success 'push status output scrubs password' '
 	grep "^To $HTTPD_URL/smart/test_repo.git" status
 '
 
+test_expect_success 'colorize errors/hints' '
+	cd "$ROOT_PATH"/test_repo_clone &&
+	test_must_fail git -c color.transport=always -c color.advice=always \
+		-c color.push=always \
+		push origin origin/master^:master 2>act &&
+	test_decode_color <act >decoded &&
+	test_i18ngrep "<RED>.*rejected.*<RESET>" decoded &&
+	test_i18ngrep "<RED>error: failed to push some refs" decoded &&
+	test_i18ngrep "<YELLOW>hint: " decoded &&
+	test_i18ngrep ! "^hint: " decoded
+'
+
 stop_httpd
 test_done
-- 
2.17.0.windows.1.15.gaa56ade3205



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

* [PATCH v3 4/4] Document the new color.* settings to colorize push errors/hints
  2018-04-21 10:09   ` [PATCH v3 0/4] Colorize push errors Johannes Schindelin
                       ` (2 preceding siblings ...)
  2018-04-21 10:10     ` [PATCH v3 3/4] Add a test to verify that push errors are colorful Johannes Schindelin
@ 2018-04-21 10:10     ` Johannes Schindelin
  3 siblings, 0 replies; 22+ messages in thread
From: Johannes Schindelin @ 2018-04-21 10:10 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Eric Sunshine, Jacob Keller,
	Ævar Arnfjörð Bjarmason

Let's make it easier for users to find out how to customize these colors.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---
 Documentation/config.txt | 28 ++++++++++++++++++++++++++++
 1 file changed, 28 insertions(+)

diff --git a/Documentation/config.txt b/Documentation/config.txt
index 2659153cb37..2cea0c6c899 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1088,6 +1088,16 @@ clean.requireForce::
 	A boolean to make git-clean do nothing unless given -f,
 	-i or -n.   Defaults to true.
 
+color.advice::
+	A boolean to enable/disable color in hints (e.g. when a push
+	failed, see `advice.*` for a list).  May be set to `always`,
+	`false` (or `never`) or `auto` (or `true`), in which case colors
+	are used only when the error output goes to a terminal. If
+	unset, then the value of `color.ui` is used (`auto` by default).
+
+color.advice.hint::
+	Use customized color for hints.
+
 color.branch::
 	A boolean to enable/disable color in the output of
 	linkgit:git-branch[1]. May be set to `always`,
@@ -1190,6 +1200,15 @@ color.pager::
 	A boolean to enable/disable colored output when the pager is in
 	use (default is true).
 
+color.push::
+	A boolean to enable/disable color in push errors. May be set to
+	`always`, `false` (or `never`) or `auto` (or `true`), in which
+	case colors are used only when the error output goes to a terminal.
+	If unset, then the value of `color.ui` is used (`auto` by default).
+
+color.push.error::
+	Use customized color for push errors.
+
 color.showBranch::
 	A boolean to enable/disable color in the output of
 	linkgit:git-show-branch[1]. May be set to `always`,
@@ -1218,6 +1237,15 @@ color.status.<slot>::
 	status short-format), or
 	`unmerged` (files which have unmerged changes).
 
+color.transport::
+	A boolean to enable/disable color when pushes are rejected. May be
+	set to `always`, `false` (or `never`) or `auto` (or `true`), in which
+	case colors are used only when the error output goes to a terminal.
+	If unset, then the value of `color.ui` is used (`auto` by default).
+
+color.transport.rejected::
+	Use customized color when a push was rejected.
+
 color.ui::
 	This variable determines the default value for variables such
 	as `color.diff` and `color.grep` that control the use of color
-- 
2.17.0.windows.1.15.gaa56ade3205

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

end of thread, other threads:[~2018-04-21 10:10 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-16 12:25 [PATCH 0/1] Colorize some errors on stderr Johannes Schindelin
2018-02-16 12:25 ` [PATCH 1/1] Colorize push errors Johannes Schindelin
2018-02-16 19:21 ` [PATCH 0/1] Colorize some errors on stderr Junio C Hamano
2018-04-06 11:21   ` Johannes Schindelin
2018-04-05 22:48 ` [PATCH v2 0/4] Colorize push errors Johannes Schindelin
2018-04-05 22:48   ` [PATCH v2 1/4] color: introduce support for colorizing stderr Johannes Schindelin
2018-04-05 22:48   ` [PATCH v2 2/4] push: colorize errors Johannes Schindelin
2018-04-05 23:37     ` Jacob Keller
2018-04-06 11:15       ` Johannes Schindelin
2018-04-05 22:48   ` [PATCH v2 3/4] Add a test to verify that push errors are colorful Johannes Schindelin
2018-04-06 10:50     ` Eric Sunshine
2018-04-06 12:13       ` Johannes Schindelin
2018-04-05 22:48   ` [PATCH v2 4/4] Document the new color.* settings to colorize push errors/hints Johannes Schindelin
2018-04-06 10:56     ` Eric Sunshine
2018-04-06 12:15       ` Johannes Schindelin
2018-04-07  6:55         ` Eric Sunshine
2018-04-21 10:09   ` [PATCH v3 0/4] Colorize push errors Johannes Schindelin
2018-04-21 10:09     ` [PATCH v3 1/4] color: introduce support for colorizing stderr Johannes Schindelin
2018-04-21 10:10     ` [PATCH v3 2/4] push: colorize errors Johannes Schindelin
2018-04-21 10:10     ` [PATCH v3 3/4] Add a test to verify that push errors are colorful Johannes Schindelin
2018-04-21 10:10     ` [PATCH v3 4/4] Document the new color.* settings to colorize push errors/hints Johannes Schindelin
2018-04-06 18:48 ` [PATCH 0/1] Colorize some errors on stderr Ævar Arnfjörð Bjarmason

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).