Skip to content

Commit 86e345f

Browse files
mapliondscho
authored andcommitted
push: colorize errors
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 [email protected] Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 43265bc commit 86e345f

File tree

4 files changed

+157
-5
lines changed

4 files changed

+157
-5
lines changed

advice.c

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include "cache.h"
22
#include "config.h"
3+
#include "color.h"
34

45
int advice_push_update_rejected = 1;
56
int advice_push_non_ff_current = 1;
@@ -20,6 +21,33 @@ int advice_add_embedded_repo = 1;
2021
int advice_ignored_hook = 1;
2122
int advice_waiting_for_editor = 1;
2223

24+
static int advice_use_color = -1;
25+
static char advice_colors[][COLOR_MAXLEN] = {
26+
GIT_COLOR_RESET,
27+
GIT_COLOR_YELLOW, /* HINT */
28+
};
29+
30+
enum color_advice {
31+
ADVICE_COLOR_RESET = 0,
32+
ADVICE_COLOR_HINT = 1,
33+
};
34+
35+
static int parse_advise_color_slot(const char *slot)
36+
{
37+
if (!strcasecmp(slot, "reset"))
38+
return ADVICE_COLOR_RESET;
39+
if (!strcasecmp(slot, "hint"))
40+
return ADVICE_COLOR_HINT;
41+
return -1;
42+
}
43+
44+
static const char *advise_get_color(enum color_advice ix)
45+
{
46+
if (want_color_stderr(advice_use_color))
47+
return advice_colors[ix];
48+
return "";
49+
}
50+
2351
static struct {
2452
const char *name;
2553
int *preference;
@@ -59,7 +87,10 @@ void advise(const char *advice, ...)
5987

6088
for (cp = buf.buf; *cp; cp = np) {
6189
np = strchrnul(cp, '\n');
62-
fprintf(stderr, _("hint: %.*s\n"), (int)(np - cp), cp);
90+
fprintf(stderr, _("%shint: %.*s%s\n"),
91+
advise_get_color(ADVICE_COLOR_HINT),
92+
(int)(np - cp), cp,
93+
advise_get_color(ADVICE_COLOR_RESET));
6394
if (*np)
6495
np++;
6596
}
@@ -68,9 +99,23 @@ void advise(const char *advice, ...)
6899

69100
int git_default_advice_config(const char *var, const char *value)
70101
{
71-
const char *k;
102+
const char *k, *slot_name;
72103
int i;
73104

105+
if (!strcmp(var, "color.advice")) {
106+
advice_use_color = git_config_colorbool(var, value);
107+
return 0;
108+
}
109+
110+
if (skip_prefix(var, "color.advice.", &slot_name)) {
111+
int slot = parse_advise_color_slot(slot_name);
112+
if (slot < 0)
113+
return 0;
114+
if (!value)
115+
return config_error_nonbool(var);
116+
return color_parse(value, advice_colors[slot]);
117+
}
118+
74119
if (!skip_prefix(var, "advice.", &k))
75120
return 0;
76121

builtin/push.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,40 @@
1212
#include "submodule.h"
1313
#include "submodule-config.h"
1414
#include "send-pack.h"
15+
#include "color.h"
1516

1617
static const char * const push_usage[] = {
1718
N_("git push [<options>] [<repository> [<refspec>...]]"),
1819
NULL,
1920
};
2021

22+
static int push_use_color = -1;
23+
static char push_colors[][COLOR_MAXLEN] = {
24+
GIT_COLOR_RESET,
25+
GIT_COLOR_RED, /* ERROR */
26+
};
27+
28+
enum color_push {
29+
PUSH_COLOR_RESET = 0,
30+
PUSH_COLOR_ERROR = 1
31+
};
32+
33+
static int parse_push_color_slot(const char *slot)
34+
{
35+
if (!strcasecmp(slot, "reset"))
36+
return PUSH_COLOR_RESET;
37+
if (!strcasecmp(slot, "error"))
38+
return PUSH_COLOR_ERROR;
39+
return -1;
40+
}
41+
42+
static const char *push_get_color(enum color_push ix)
43+
{
44+
if (want_color_stderr(push_use_color))
45+
return push_colors[ix];
46+
return "";
47+
}
48+
2149
static int thin = 1;
2250
static int deleterefs;
2351
static const char *receivepack;
@@ -337,8 +365,11 @@ static int push_with_options(struct transport *transport, int flags)
337365
fprintf(stderr, _("Pushing to %s\n"), transport->url);
338366
err = transport_push(transport, refspec_nr, refspec, flags,
339367
&reject_reasons);
340-
if (err != 0)
368+
if (err != 0) {
369+
fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
341370
error(_("failed to push some refs to '%s'"), transport->url);
371+
fprintf(stderr, "%s", push_get_color(PUSH_COLOR_RESET));
372+
}
342373

343374
err |= transport_disconnect(transport);
344375
if (!err)
@@ -467,6 +498,7 @@ static void set_push_cert_flags(int *flags, int v)
467498

468499
static int git_push_config(const char *k, const char *v, void *cb)
469500
{
501+
const char *slot_name;
470502
int *flags = cb;
471503
int status;
472504

@@ -514,6 +546,16 @@ static int git_push_config(const char *k, const char *v, void *cb)
514546
else
515547
string_list_append(&push_options_config, v);
516548
return 0;
549+
} else if (!strcmp(k, "color.push")) {
550+
push_use_color = git_config_colorbool(k, v);
551+
return 0;
552+
} else if (skip_prefix(k, "color.push.", &slot_name)) {
553+
int slot = parse_push_color_slot(slot_name);
554+
if (slot < 0)
555+
return 0;
556+
if (!v)
557+
return config_error_nonbool(k);
558+
return color_parse(v, push_colors[slot]);
517559
}
518560

519561
return git_default_config(k, v, NULL);

config.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1365,7 +1365,7 @@ int git_default_config(const char *var, const char *value, void *dummy)
13651365
if (starts_with(var, "mailmap."))
13661366
return git_default_mailmap_config(var, value);
13671367

1368-
if (starts_with(var, "advice."))
1368+
if (starts_with(var, "advice.") || starts_with(var, "color.advice"))
13691369
return git_default_advice_config(var, value);
13701370

13711371
if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {

transport.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,56 @@
1818
#include "sha1-array.h"
1919
#include "sigchain.h"
2020
#include "transport-internal.h"
21+
#include "color.h"
22+
23+
static int transport_use_color = -1;
24+
static char transport_colors[][COLOR_MAXLEN] = {
25+
GIT_COLOR_RESET,
26+
GIT_COLOR_RED /* REJECTED */
27+
};
28+
29+
enum color_transport {
30+
TRANSPORT_COLOR_RESET = 0,
31+
TRANSPORT_COLOR_REJECTED = 1
32+
};
33+
34+
static int transport_color_config(void)
35+
{
36+
const char *keys[] = {
37+
"color.transport.reset",
38+
"color.transport.rejected"
39+
}, *key = "color.transport";
40+
char *value;
41+
int i;
42+
static int initialized;
43+
44+
if (initialized)
45+
return 0;
46+
initialized = 1;
47+
48+
if (!git_config_get_string(key, &value))
49+
transport_use_color = git_config_colorbool(key, value);
50+
51+
if (!want_color_stderr(transport_use_color))
52+
return 0;
53+
54+
for (i = 0; i < ARRAY_SIZE(keys); i++)
55+
if (!git_config_get_string(keys[i], &value)) {
56+
if (!value)
57+
return config_error_nonbool(keys[i]);
58+
if (color_parse(value, transport_colors[i]) < 0)
59+
return -1;
60+
}
61+
62+
return 0;
63+
}
64+
65+
static const char *transport_get_color(enum color_transport ix)
66+
{
67+
if (want_color_stderr(transport_use_color))
68+
return transport_colors[ix];
69+
return "";
70+
}
2171

2272
static void set_upstreams(struct transport *transport, struct ref *refs,
2373
int pretend)
@@ -338,7 +388,13 @@ static void print_ref_status(char flag, const char *summary,
338388
else
339389
fprintf(stdout, "%s\n", summary);
340390
} else {
341-
fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
391+
const char *red = "", *reset = "";
392+
if (push_had_errors(to)) {
393+
red = transport_get_color(TRANSPORT_COLOR_REJECTED);
394+
reset = transport_get_color(TRANSPORT_COLOR_RESET);
395+
}
396+
fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
397+
summary, reset);
342398
if (from)
343399
fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
344400
else
@@ -487,6 +543,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,
487543
char *head;
488544
int summary_width = transport_summary_width(refs);
489545

546+
if (transport_color_config() < 0)
547+
warning(_("could not parse transport.color.* config"));
548+
490549
head = resolve_refdup("HEAD", RESOLVE_REF_READING, NULL, NULL);
491550

492551
if (verbose) {
@@ -553,6 +612,9 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
553612
struct send_pack_args args;
554613
int ret;
555614

615+
if (transport_color_config() < 0)
616+
return -1;
617+
556618
if (!data->got_remote_heads) {
557619
struct ref *tmp_refs;
558620
connect_setup(transport, 1);
@@ -997,6 +1059,9 @@ int transport_push(struct transport *transport,
9971059
*reject_reasons = 0;
9981060
transport_verify_remote_names(refspec_nr, refspec);
9991061

1062+
if (transport_color_config() < 0)
1063+
return -1;
1064+
10001065
if (transport->vtable->push_refs) {
10011066
struct ref *remote_refs;
10021067
struct ref *local_refs = get_local_heads();

0 commit comments

Comments
 (0)