log: decorate HEAD with branch name

Currently, log decorations do not indicate which branch is checked out
and whether HEAD is detached.

When branch foo is checked out, change the "HEAD, foo" part of the
decorations to "HEAD -> foo". This serves to indicate both ref
decorations (helped by the spacing) as well as their relationshsip.
As a consequence, "HEAD" without any " -> " denotes a detached HEAD now.

Signed-off-by: Michael J Gruber <git@drmicha.warpmail.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2015-03-10 14:53:21 +01:00
parent 4ab682e213
commit 51ff0f27bc
3 changed files with 72 additions and 13 deletions

View File

@ -172,6 +172,43 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre
}
}
/*
* Do we have HEAD in the output, and also the branch it points at?
* If so, find that decoration entry for that current branch.
*/
static const struct name_decoration *current_pointed_by_HEAD(const struct name_decoration *decoration)
{
const struct name_decoration *list, *head = NULL;
const char *branch_name = NULL;
unsigned char unused[20];
int rru_flags;
/* First find HEAD */
for (list = decoration; list; list = list->next)
if (list->type == DECORATION_REF_HEAD) {
head = list;
break;
}
if (!head)
return NULL;
/* Now resolve and find the matching current branch */
branch_name = resolve_ref_unsafe("HEAD", 0, unused, &rru_flags);
if (!(rru_flags & REF_ISSYMREF))
return NULL;
if (!skip_prefix(branch_name, "refs/heads/", &branch_name))
return NULL;
/* OK, do we have that ref in the list? */
for (list = decoration; list; list = list->next)
if ((list->type == DECORATION_REF_LOCAL) &&
!strcmp(branch_name, list->name)) {
return list;
}
return NULL;
}
/*
* The caller makes sure there is no funny color before calling.
* format_decorations_extended makes sure the same after return.
@ -184,6 +221,7 @@ void format_decorations_extended(struct strbuf *sb,
const char *suffix)
{
const struct name_decoration *decoration;
const struct name_decoration *current_and_HEAD;
const char *color_commit =
diff_get_color(use_color, DIFF_COMMIT);
const char *color_reset =
@ -192,16 +230,37 @@ void format_decorations_extended(struct strbuf *sb,
decoration = get_name_decoration(&commit->object);
if (!decoration)
return;
current_and_HEAD = current_pointed_by_HEAD(decoration);
while (decoration) {
strbuf_addstr(sb, color_commit);
strbuf_addstr(sb, prefix);
strbuf_addstr(sb, color_reset);
strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
if (decoration->type == DECORATION_REF_TAG)
strbuf_addstr(sb, "tag: ");
strbuf_addstr(sb, decoration->name);
strbuf_addstr(sb, color_reset);
prefix = separator;
/*
* When both current and HEAD are there, only
* show HEAD->current where HEAD would have
* appeared, skipping the entry for current.
*/
if (decoration != current_and_HEAD) {
strbuf_addstr(sb, color_commit);
strbuf_addstr(sb, prefix);
strbuf_addstr(sb, color_reset);
strbuf_addstr(sb, decorate_get_color(use_color, decoration->type));
if (decoration->type == DECORATION_REF_TAG)
strbuf_addstr(sb, "tag: ");
strbuf_addstr(sb, decoration->name);
if (current_and_HEAD &&
decoration->type == DECORATION_REF_HEAD) {
strbuf_addstr(sb, color_reset);
strbuf_addstr(sb, color_commit);
strbuf_addstr(sb, " -> ");
strbuf_addstr(sb, color_reset);
strbuf_addstr(sb, decorate_get_color(use_color, current_and_HEAD->type));
strbuf_addstr(sb, current_and_HEAD->name);
}
strbuf_addstr(sb, color_reset);
prefix = separator;
}
decoration = decoration->next;
}
strbuf_addstr(sb, color_commit);

View File

@ -5,7 +5,7 @@ Date: Mon Jun 26 00:06:00 2006 +0000
Rearranged lines in dir/sub
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD, master)
commit 59d314ad6f356dd08601a4cd5e530381da3e3c64 (HEAD -> master)
Merge: 9a6d494 c7a2ab9
Author: A U Thor <author@example.com>
Date: Mon Jun 26 00:04:00 2006 +0000

View File

@ -44,10 +44,10 @@ test_expect_success setup '
'
cat >expected <<EOF
${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit},\
${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_HEAD}HEAD${c_reset}${c_commit} ->\
${c_reset}${c_branch}master${c_reset}${c_commit},\
${c_reset}${c_tag}tag: v1.0${c_reset}${c_commit},\
${c_reset}${c_tag}tag: B${c_reset}${c_commit},\
${c_reset}${c_branch}master${c_reset}${c_commit})${c_reset} B
${c_reset}${c_tag}tag: B${c_reset}${c_commit})${c_reset} B
${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_tag}tag: A1${c_reset}${c_commit},\
${c_reset}${c_remoteBranch}other/master${c_reset}${c_commit})${c_reset} A1
${c_commit}COMMIT_ID${c_reset}${c_commit} (${c_reset}${c_stash}refs/stash${c_reset}${c_commit})${c_reset}\