diff options
Diffstat (limited to 'log-tree.c')
-rw-r--r-- | log-tree.c | 168 |
1 files changed, 114 insertions, 54 deletions
diff --git a/log-tree.c b/log-tree.c index f87b7e891a..c931615d92 100644 --- a/log-tree.c +++ b/log-tree.c @@ -12,17 +12,9 @@ #include "sequencer.h" #include "line-log.h" -struct decoration name_decoration = { "object names" }; - -enum decoration_type { - DECORATION_NONE = 0, - DECORATION_REF_LOCAL, - DECORATION_REF_REMOTE, - DECORATION_REF_TAG, - DECORATION_REF_STASH, - DECORATION_REF_HEAD, - DECORATION_GRAFTED, -}; +static struct decoration name_decoration = { "object names" }; +static int decoration_loaded; +static int decoration_flags; static char decoration_colors[][COLOR_MAXLEN] = { GIT_COLOR_RESET, @@ -66,15 +58,14 @@ static int parse_decorate_color_slot(const char *slot) return -1; } -int parse_decorate_color_config(const char *var, const int ofs, const char *value) +int parse_decorate_color_config(const char *var, const char *slot_name, const char *value) { - int slot = parse_decorate_color_slot(var + ofs); + int slot = parse_decorate_color_slot(slot_name); if (slot < 0) return 0; if (!value) return config_error_nonbool(var); - color_parse(value, var, decoration_colors[slot]); - return 0; + return color_parse(value, decoration_colors[slot]); } /* @@ -84,20 +75,27 @@ int parse_decorate_color_config(const char *var, const int ofs, const char *valu #define decorate_get_color_opt(o, ix) \ decorate_get_color((o)->use_color, ix) -static void add_name_decoration(enum decoration_type type, const char *name, struct object *obj) +void add_name_decoration(enum decoration_type type, const char *name, struct object *obj) { int nlen = strlen(name); - struct name_decoration *res = xmalloc(sizeof(struct name_decoration) + nlen); + struct name_decoration *res = xmalloc(sizeof(*res) + nlen + 1); memcpy(res->name, name, nlen + 1); res->type = type; res->next = add_decoration(&name_decoration, obj, res); } +const struct name_decoration *get_name_decoration(const struct object *obj) +{ + return lookup_decoration(&name_decoration, obj); +} + static int add_ref_decoration(const char *refname, const unsigned char *sha1, int flags, void *cb_data) { struct object *obj; enum decoration_type type = DECORATION_NONE; + assert(cb_data == NULL); + if (starts_with(refname, "refs/replace/")) { unsigned char original_sha1[20]; if (!check_replace_refs) @@ -127,8 +125,6 @@ static int add_ref_decoration(const char *refname, const unsigned char *sha1, in else if (!strcmp(refname, "HEAD")) type = DECORATION_REF_HEAD; - if (!cb_data || *(int *)cb_data == DECORATE_SHORT_REFS) - refname = prettify_refname(refname); add_name_decoration(type, refname, obj); while (obj->type == OBJ_TAG) { obj = ((struct tag *)obj)->tagged; @@ -152,11 +148,11 @@ static int add_graft_decoration(const struct commit_graft *graft, void *cb_data) void load_ref_decorations(int flags) { - static int loaded; - if (!loaded) { - loaded = 1; - for_each_ref(add_ref_decoration, &flags); - head_ref(add_ref_decoration, &flags); + if (!decoration_loaded) { + decoration_loaded = 1; + decoration_flags = flags; + for_each_ref(add_ref_decoration, NULL); + head_ref(add_ref_decoration, NULL); for_each_commit_graft(add_graft_decoration, NULL); } } @@ -179,37 +175,107 @@ static void show_children(struct rev_info *opt, struct commit *commit, int abbre } /* - * The caller makes sure there is no funny color before - * calling. format_decorations makes sure the same after return. + * Do we have HEAD in the output, and also the branch it points at? + * If so, find that decoration entry for that current branch. */ -void format_decorations(struct strbuf *sb, +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 (!starts_with(branch_name, "refs/")) + 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; +} + +static void show_name(struct strbuf *sb, const struct name_decoration *decoration) +{ + if (decoration_flags == DECORATE_SHORT_REFS) + strbuf_addstr(sb, prettify_refname(decoration->name)); + else + strbuf_addstr(sb, decoration->name); +} + +/* + * The caller makes sure there is no funny color before calling. + * format_decorations_extended makes sure the same after return. + */ +void format_decorations_extended(struct strbuf *sb, const struct commit *commit, - int use_color) + int use_color, + const char *prefix, + const char *separator, + const char *suffix) { - const char *prefix; - struct name_decoration *decoration; + 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 = decorate_get_color(use_color, DECORATION_NONE); - decoration = lookup_decoration(&name_decoration, &commit->object); + decoration = get_name_decoration(&commit->object); if (!decoration) return; - prefix = " ("; + + current_and_HEAD = current_pointed_by_HEAD(decoration); while (decoration) { - strbuf_addstr(sb, color_commit); - strbuf_addstr(sb, prefix); - 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 = ", "; + /* + * 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: "); + + show_name(sb, decoration); + + 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)); + show_name(sb, current_and_HEAD); + } + strbuf_addstr(sb, color_reset); + + prefix = separator; + } decoration = decoration->next; } strbuf_addstr(sb, color_commit); - strbuf_addch(sb, ')'); + strbuf_addstr(sb, suffix); strbuf_addstr(sb, color_reset); } @@ -414,10 +480,11 @@ static int is_common_merge(const struct commit *commit) && !commit->parents->next->next); } -static void show_one_mergetag(struct rev_info *opt, +static void show_one_mergetag(struct commit *commit, struct commit_extra_header *extra, - struct commit *commit) + void *data) { + struct rev_info *opt = (struct rev_info *)data; unsigned char sha1[20]; struct tag *tag; struct strbuf verify_message; @@ -465,15 +532,7 @@ static void show_one_mergetag(struct rev_info *opt, static void show_mergetag(struct rev_info *opt, struct commit *commit) { - struct commit_extra_header *extra, *to_free; - - to_free = read_commit_extra_headers(commit, NULL); - for (extra = to_free; extra; extra = extra->next) { - if (strcmp(extra->key, "mergetag")) - continue; /* not a merge tag */ - show_one_mergetag(opt, extra, commit); - } - free_commit_extra_headers(to_free); + for_each_mergetag(show_one_mergetag, commit, opt); } void show_log(struct rev_info *opt) @@ -656,7 +715,7 @@ void show_log(struct rev_info *opt) graph_show_commit_msg(opt->graph, &msgbuf); else fwrite(msgbuf.buf, sizeof(char), msgbuf.len, stdout); - if (opt->use_terminator) { + if (opt->use_terminator && !commit_format_is_empty(opt->commit_format)) { if (!opt->missing_newline) graph_show_padding(opt->graph); putchar(opt->diffopt.line_termination); @@ -683,7 +742,8 @@ int log_tree_diff_flush(struct rev_info *opt) show_log(opt); if ((opt->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) && opt->verbose_header && - opt->commit_format != CMIT_FMT_ONELINE) { + opt->commit_format != CMIT_FMT_ONELINE && + !commit_format_is_empty(opt->commit_format)) { /* * When showing a verbose header (i.e. log message), * and not in --pretty=oneline format, we would want |