Skip to content

Commit 960786e

Browse files
mapliongitster
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]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 295d949 commit 960786e

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

2373
static void set_upstreams(struct transport *transport, struct ref *refs,
2474
int pretend)
@@ -339,7 +389,13 @@ static void print_ref_status(char flag, const char *summary,
339389
else
340390
fprintf(stdout, "%s\n", summary);
341391
} else {
342-
fprintf(stderr, " %c %-*s ", flag, summary_width, summary);
392+
const char *red = "", *reset = "";
393+
if (push_had_errors(to)) {
394+
red = transport_get_color(TRANSPORT_COLOR_REJECTED);
395+
reset = transport_get_color(TRANSPORT_COLOR_RESET);
396+
}
397+
fprintf(stderr, " %s%c %-*s%s ", red, flag, summary_width,
398+
summary, reset);
343399
if (from)
344400
fprintf(stderr, "%s -> %s", prettify_refname(from->name), prettify_refname(to->name));
345401
else
@@ -488,6 +544,9 @@ void transport_print_push_status(const char *dest, struct ref *refs,
488544
char *head;
489545
int summary_width = transport_summary_width(refs);
490546

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

493552
if (verbose) {
@@ -554,6 +613,9 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
554613
struct send_pack_args args;
555614
int ret;
556615

616+
if (transport_color_config() < 0)
617+
return -1;
618+
557619
if (!data->got_remote_heads) {
558620
struct ref *tmp_refs;
559621
connect_setup(transport, 1);
@@ -998,6 +1060,9 @@ int transport_push(struct transport *transport,
9981060
*reject_reasons = 0;
9991061
transport_verify_remote_names(refspec_nr, refspec);
10001062

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

0 commit comments

Comments
 (0)