This is most useful when you fork your branches off a remote ref and rely on ref decoration to show your fork points in `git log`. Then you do a "git fetch" and suddenly the remote decoration is gone because remote refs are moved forward. With this, we can still see something like "origin/foo@{1}" This is for remote refs only because based on my experience, docorating local reflog is just too noisy. You will most likely see HEAD@{1}, HEAD@{2} and so on. We can add that as a separate option in future if we see a need for it. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- I've been using this for many weeks and it has proven its usefulness (to me). Looks like good material to send upstream. Documentation/git-log.txt | 5 +++++ builtin/log.c | 10 +++++++++- log-tree.c | 43 +++++++++++++++++++++++++++++++++++++++---- log-tree.h | 2 +- pretty.c | 4 ++-- revision.c | 2 +- 6 files changed, 57 insertions(+), 9 deletions(-) diff --git a/Documentation/git-log.txt b/Documentation/git-log.txt index 32246fd..f5ee575 100644 --- a/Documentation/git-log.txt +++ b/Documentation/git-log.txt @@ -38,6 +38,11 @@ OPTIONS are shown as if 'short' were given, otherwise no ref names are shown. The default option is 'short'. +--decorate-remote-reflog[=<n>]:: + Decorate `<n>` most recent reflog entries on remote refs, up + to the specified number of entries. By default, only the most + recent reflog entry is decorated. + --source:: Print out the ref name given on the command line by which each commit was reached. diff --git a/builtin/log.c b/builtin/log.c index 55d20cc..c208703 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -36,6 +36,7 @@ static int default_follow; static int default_show_signature; static int decoration_style; static int decoration_given; +static int decorate_remote_reflog; static int use_mailmap_config; static const char *fmt_patch_subject_prefix = "PATCH"; static const char *fmt_pretty; @@ -141,6 +142,10 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, OPT_BOOL(0, "use-mailmap", &mailmap, N_("Use mail map file")), { OPTION_CALLBACK, 0, "decorate", NULL, NULL, N_("decorate options"), PARSE_OPT_OPTARG, decorate_callback}, + { OPTION_INTEGER, 0, "decorate-remote-reflog", + &decorate_remote_reflog, N_("n"), + N_("decorate the last <n> reflog entries of remote refs"), + PARSE_OPT_OPTARG | PARSE_OPT_NONEG, NULL, 1 }, OPT_CALLBACK('L', NULL, &line_cb, "n,m:file", N_("Process line range n,m in file, counting from 1"), log_line_range_callback), @@ -195,9 +200,12 @@ static void cmd_log_init_finish(int argc, const char **argv, const char *prefix, rev->abbrev_commit = 0; } + if (decorate_remote_reflog > 0 && !decoration_style) + decoration_style = DECORATE_SHORT_REFS; if (decoration_style) { rev->show_decorations = 1; - load_ref_decorations(decoration_style); + load_ref_decorations(decoration_style, + decorate_remote_reflog); } if (rev->line_level_traverse) diff --git a/log-tree.c b/log-tree.c index 8c24157..3d85ebc 100644 --- a/log-tree.c +++ b/log-tree.c @@ -88,14 +88,37 @@ const struct name_decoration *get_name_decoration(const struct object *obj) return lookup_decoration(&name_decoration, obj); } +struct reflog_cb { + int type; + int count; + int nth; + const char *refname; +}; + +static int add_nth_reflog(unsigned char *osha1, unsigned char *nsha1, + const char *email, unsigned long timestamp, int tz, + const char *message, void *cb_data) +{ + struct reflog_cb *cb = cb_data; + struct commit *commit; + + commit = lookup_commit(nsha1); + if (commit && cb->nth) { + struct strbuf sb = STRBUF_INIT; + strbuf_addf(&sb, "%s@{%d}", cb->refname, cb->nth); + add_name_decoration(cb->type, sb.buf, &commit->object); + strbuf_release(&sb); + } + cb->nth++; + return cb->nth >= cb->count; +} + static int add_ref_decoration(const char *refname, const struct object_id *oid, int flags, void *cb_data) { struct object *obj; enum decoration_type type = DECORATION_NONE; - assert(cb_data == NULL); - if (starts_with(refname, git_replace_ref_base)) { struct object_id original_oid; if (!check_replace_refs) @@ -135,6 +158,17 @@ static int add_ref_decoration(const char *refname, const struct object_id *oid, parse_object(obj->oid.hash); add_name_decoration(DECORATION_REF_TAG, refname, obj); } + + if (cb_data && type == DECORATION_REF_REMOTE) { + struct reflog_cb cb; + + memset(&cb, 0, sizeof(cb)); + cb.refname = refname; + cb.type = type; + cb.count = *(int *)cb_data + 1 /* for @{0} */; + + for_each_reflog_ent_reverse(refname, add_nth_reflog, &cb); + } return 0; } @@ -147,13 +181,14 @@ static int add_graft_decoration(const struct commit_graft *graft, void *cb_data) return 0; } -void load_ref_decorations(int flags) +void load_ref_decorations(int flags, int remote_reflog) { if (!decoration_loaded) { + void *cb = remote_reflog ? &remote_reflog : NULL; decoration_loaded = 1; decoration_flags = flags; - for_each_ref(add_ref_decoration, NULL); + for_each_ref(add_ref_decoration, cb); head_ref(add_ref_decoration, NULL); for_each_commit_graft(add_graft_decoration, NULL); } diff --git a/log-tree.h b/log-tree.h index c8116e6..bb46c53 100644 --- a/log-tree.h +++ b/log-tree.h @@ -25,7 +25,7 @@ void log_write_email_headers(struct rev_info *opt, struct commit *commit, const char **subject_p, const char **extra_headers_p, int *need_8bit_cte_p); -void load_ref_decorations(int flags); +void load_ref_decorations(int flags, int reflog); #define FORMAT_PATCH_NAME_MAX 64 void fmt_output_commit(struct strbuf *, struct commit *, struct rev_info *); diff --git a/pretty.c b/pretty.c index 5e68383..ec8e1cc 100644 --- a/pretty.c +++ b/pretty.c @@ -1189,11 +1189,11 @@ static size_t format_commit_one(struct strbuf *sb, /* in UTF-8 */ strbuf_addstr(sb, get_revision_mark(NULL, commit)); return 1; case 'd': - load_ref_decorations(DECORATE_SHORT_REFS); + load_ref_decorations(DECORATE_SHORT_REFS, 0); format_decorations(sb, commit, c->auto_color); return 1; case 'D': - load_ref_decorations(DECORATE_SHORT_REFS); + load_ref_decorations(DECORATE_SHORT_REFS, 0); format_decorations_extended(sb, commit, c->auto_color, "", ", ", ""); return 1; case 'g': /* reflog info */ diff --git a/revision.c b/revision.c index b37dbec..4d5cbf5 100644 --- a/revision.c +++ b/revision.c @@ -1743,7 +1743,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg revs->simplify_by_decoration = 1; revs->limited = 1; revs->prune = 1; - load_ref_decorations(DECORATE_SHORT_REFS); + load_ref_decorations(DECORATE_SHORT_REFS, 0); } else if (!strcmp(arg, "--date-order")) { revs->sort_order = REV_SORT_BY_COMMIT_DATE; revs->topo_order = 1; -- 2.8.2.524.g6ff3d78