Skip to content

Commit 2927a50

Browse files
committed
Merge branch 'ar/decorate-color'
* ar/decorate-color: Add test for correct coloring of git log --decoration Allow customizable commit decorations colors log --decorate: Colorize commit decorations log-tree.c: Use struct name_decoration's type for classifying decoration commit.h: add 'type' to struct name_decoration
2 parents 54ed6a9 + 5671028 commit 2927a50

File tree

6 files changed

+176
-8
lines changed

6 files changed

+176
-8
lines changed

Documentation/config.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,11 @@ color.diff.<slot>::
690690
(highlighting whitespace errors). The values of these variables may be
691691
specified as in color.branch.<slot>.
692692

693+
color.decorate.<slot>::
694+
Use customized color for 'git log --decorate' output. `<slot>` is one
695+
of `branch`, `remoteBranch`, `tag`, `stash` or `HEAD` for local
696+
branches, remote tracking branches, tags, stash and HEAD, respectively.
697+
693698
color.grep::
694699
When set to `always`, always highlight matches. When `false` (or
695700
`never`), never. When set to `true` or `auto`, use color only

builtin/log.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ static int git_log_config(const char *var, const char *value, void *cb)
296296
default_show_root = git_config_bool(var, value);
297297
return 0;
298298
}
299+
if (!prefixcmp(var, "color.decorate."))
300+
return parse_decorate_color_config(var, 15, value);
301+
299302
return git_diff_ui_config(var, value, cb);
300303
}
301304

commit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ extern const char *commit_type;
2828
extern struct decoration name_decoration;
2929
struct name_decoration {
3030
struct name_decoration *next;
31+
int type;
3132
char name[1];
3233
};
3334

log-tree.c

Lines changed: 100 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,32 +7,113 @@
77
#include "reflog-walk.h"
88
#include "refs.h"
99
#include "string-list.h"
10+
#include "color.h"
1011

1112
struct decoration name_decoration = { "object names" };
1213

13-
static void add_name_decoration(const char *prefix, const char *name, struct object *obj)
14+
enum decoration_type {
15+
DECORATION_NONE = 0,
16+
DECORATION_REF_LOCAL,
17+
DECORATION_REF_REMOTE,
18+
DECORATION_REF_TAG,
19+
DECORATION_REF_STASH,
20+
DECORATION_REF_HEAD,
21+
};
22+
23+
static char decoration_colors[][COLOR_MAXLEN] = {
24+
GIT_COLOR_RESET,
25+
GIT_COLOR_BOLD_GREEN, /* REF_LOCAL */
26+
GIT_COLOR_BOLD_RED, /* REF_REMOTE */
27+
GIT_COLOR_BOLD_YELLOW, /* REF_TAG */
28+
GIT_COLOR_BOLD_MAGENTA, /* REF_STASH */
29+
GIT_COLOR_BOLD_CYAN, /* REF_HEAD */
30+
};
31+
32+
static const char *decorate_get_color(int decorate_use_color, enum decoration_type ix)
33+
{
34+
if (decorate_use_color)
35+
return decoration_colors[ix];
36+
return "";
37+
}
38+
39+
static int parse_decorate_color_slot(const char *slot)
40+
{
41+
/*
42+
* We're comparing with 'ignore-case' on
43+
* (because config.c sets them all tolower),
44+
* but let's match the letters in the literal
45+
* string values here with how they are
46+
* documented in Documentation/config.txt, for
47+
* consistency.
48+
*
49+
* We love being consistent, don't we?
50+
*/
51+
if (!strcasecmp(slot, "branch"))
52+
return DECORATION_REF_LOCAL;
53+
if (!strcasecmp(slot, "remoteBranch"))
54+
return DECORATION_REF_REMOTE;
55+
if (!strcasecmp(slot, "tag"))
56+
return DECORATION_REF_TAG;
57+
if (!strcasecmp(slot, "stash"))
58+
return DECORATION_REF_STASH;
59+
if (!strcasecmp(slot, "HEAD"))
60+
return DECORATION_REF_HEAD;
61+
return -1;
62+
}
63+
64+
int parse_decorate_color_config(const char *var, const int ofs, const char *value)
65+
{
66+
int slot = parse_decorate_color_slot(var + ofs);
67+
if (slot < 0)
68+
return 0;
69+
if (!value)
70+
return config_error_nonbool(var);
71+
color_parse(value, var, decoration_colors[slot]);
72+
return 0;
73+
}
74+
75+
/*
76+
* log-tree.c uses DIFF_OPT_TST for determining whether to use color
77+
* for showing the commit sha1, use the same check for --decorate
78+
*/
79+
#define decorate_get_color_opt(o, ix) \
80+
decorate_get_color(DIFF_OPT_TST((o), COLOR_DIFF), ix)
81+
82+
static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj)
1483
{
15-
int plen = strlen(prefix);
1684
int nlen = strlen(name);
17-
struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + plen + nlen);
18-
memcpy(res->name, prefix, plen);
19-
memcpy(res->name + plen, name, nlen + 1);
85+
struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen);
86+
memcpy(res->name, name, nlen + 1);
87+
res->type = type;
2088
res->next = add_decoration(&name_decoration, obj, res);
2189
}
2290

2391
static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data)
2492
{
2593
struct object *obj = parse_object(sha1);
94+
enum decoration_type type = DECORATION_NONE;
2695
if (!obj)
2796
return 0;
97+
98+
if (!prefixcmp(refname, "refs/heads"))
99+
type = DECORATION_REF_LOCAL;
100+
else if (!prefixcmp(refname, "refs/remotes"))
101+
type = DECORATION_REF_REMOTE;
102+
else if (!prefixcmp(refname, "refs/tags"))
103+
type = DECORATION_REF_TAG;
104+
else if (!prefixcmp(refname, "refs/stash"))
105+
type = DECORATION_REF_STASH;
106+
else if (!prefixcmp(refname, "HEAD"))
107+
type = DECORATION_REF_HEAD;
108+
28109
if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS)
29110
refname = prettify_refname(refname);
30-
add_name_decoration("", refname, obj);
111+
add_name_decoration(type, refname, obj);
31112
while (obj->type == OBJ_TAG) {
32113
obj = ((struct tag *)obj)->tagged;
33114
if (!obj)
34115
break;
35-
add_name_decoration("tag: ", refname, obj);
116+
add_name_decoration(DECORATION_REF_TAG, refname, obj);
36117
}
37118
return 0;
38119
}
@@ -60,6 +141,10 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
60141
{
61142
const char *prefix;
62143
struct name_decoration *decoration;
144+
const char *color_commit =
145+
diff_get_color_opt(&opt->diffopt, DIFF_COMMIT);
146+
const char *color_reset =
147+
decorate_get_color_opt(&opt->diffopt, DECORATION_NONE);
63148

64149
if (opt->show_source && commit->util)
65150
printf("\t%s", (char *) commit->util);
@@ -70,7 +155,14 @@ void show_decorations(struct rev_info *opt, struct commit *commit)
70155
return;
71156
prefix = " (";
72157
while (decoration) {
73-
printf("%s%s", prefix, decoration->name);
158+
printf("%s", prefix);
159+
fputs(decorate_get_color_opt(&opt->diffopt, decoration->type),
160+
stdout);
161+
if (decoration->type == DECORATION_REF_TAG)
162+
fputs("tag: ", stdout);
163+
printf("%s", decoration->name);
164+
fputs(color_reset, stdout);
165+
fputs(color_commit, stdout);
74166
prefix = ", ";
75167
decoration = decoration->next;
76168
}

log-tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ struct log_info {
77
struct commit *commit, *parent;
88
};
99

10+
int parse_decorate_color_config(const char *var, const int ofs, const char *value);
1011
void init_log_tree_opt(struct rev_info *);
1112
int log_tree_diff_flush(struct rev_info *);
1213
int log_tree_commit(struct rev_info *, struct commit *);

t/t4207-log-decoration-colors.sh

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) 2010 Nazri Ramliy
4+
#
5+
6+
test_description='Test for "git log --decorate" colors'
7+
8+
. ./test-lib.sh
9+
10+
get_color ()
11+
{
12+
git config --get-color no.such.slot "$1"
13+
}
14+
15+
test_expect_success setup '
16+
git config diff.color.commit yellow &&
17+
git config color.decorate.branch green &&
18+
git config color.decorate.remoteBranch red &&
19+
git config color.decorate.tag "reverse bold yellow" &&
20+
git config color.decorate.stash magenta &&
21+
git config color.decorate.HEAD cyan &&
22+
23+
c_reset=$(get_color reset) &&
24+
25+
c_commit=$(get_color yellow) &&
26+
c_branch=$(get_color green) &&
27+
c_remoteBranch=$(get_color red) &&
28+
c_tag=$(get_color "reverse bold yellow") &&
29+
c_stash=$(get_color magenta) &&
30+
c_HEAD=$(get_color cyan) &&
31+
32+
test_commit A &&
33+
git clone . other &&
34+
(
35+
cd other &&
36+
test_commit A1
37+
) &&
38+
39+
git remote add -f other ./other &&
40+
test_commit B &&
41+
git tag v1.0 &&
42+
echo >>A.t &&
43+
git stash save Changes to A.t
44+
'
45+
46+
cat >expected <<EOF
47+
${c_commit}COMMIT_ID (${c_HEAD}HEAD${c_reset}${c_commit},\
48+
${c_tag}tag: v1.0${c_reset}${c_commit},\
49+
${c_tag}tag: B${c_reset}${c_commit},\
50+
${c_branch}master${c_reset}${c_commit})${c_reset} B
51+
${c_commit}COMMIT_ID (${c_tag}tag: A1${c_reset}${c_commit},\
52+
${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
53+
${c_commit}COMMIT_ID (${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\
54+
On master: Changes to A.t
55+
${c_commit}COMMIT_ID (${c_tag}tag: A${c_reset}${c_commit})${c_reset} A
56+
EOF
57+
58+
# We want log to show all, but the second parent to refs/stash is irrelevant
59+
# to this test since it does not contain any decoration, hence --first-parent
60+
test_expect_success 'Commit Decorations Colored Correctly' '
61+
git log --first-parent --abbrev=10 --all --decorate --oneline --color=always |
62+
sed "s/[0-9a-f]\{10,10\}/COMMIT_ID/" >out &&
63+
test_cmp expected out
64+
'
65+
66+
test_done

0 commit comments

Comments
 (0)