diff options
Diffstat (limited to 'builtin/describe.c')
-rw-r--r-- | builtin/describe.c | 121 |
1 files changed, 94 insertions, 27 deletions
diff --git a/builtin/describe.c b/builtin/describe.c index e14e162ef6..3b0b204b1e 100644 --- a/builtin/describe.c +++ b/builtin/describe.c @@ -3,6 +3,7 @@ #include "lockfile.h" #include "commit.h" #include "tag.h" +#include "blob.h" #include "refs.h" #include "builtin.h" #include "exec_cmd.h" @@ -12,6 +13,8 @@ #include "hashmap.h" #include "argv-array.h" #include "run-command.h" +#include "revision.h" +#include "list-objects.h" #define MAX_TAGS (FLAG_BITS - 1) @@ -256,7 +259,7 @@ static unsigned long finish_depth_computation( return seen_commits; } -static void display_name(struct commit_name *n) +static void append_name(struct commit_name *n, struct strbuf *dst) { if (n->prio == 2 && !n->tag) { n->tag = lookup_tag(&n->oid); @@ -272,19 +275,18 @@ static void display_name(struct commit_name *n) } if (n->tag) - printf("%s", n->tag->tag); + strbuf_addstr(dst, n->tag->tag); else - printf("%s", n->path); + strbuf_addstr(dst, n->path); } -static void show_suffix(int depth, const struct object_id *oid) +static void append_suffix(int depth, const struct object_id *oid, struct strbuf *dst) { - printf("-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev)); + strbuf_addf(dst, "-%d-g%s", depth, find_unique_abbrev(oid->hash, abbrev)); } -static void describe(const char *arg, int last_one) +static void describe_commit(struct object_id *oid, struct strbuf *dst) { - struct object_id oid; struct commit *cmit, *gave_up_on = NULL; struct commit_list *list; struct commit_name *n; @@ -293,30 +295,25 @@ static void describe(const char *arg, int last_one) unsigned long seen_commits = 0; unsigned int unannotated_cnt = 0; - if (get_oid(arg, &oid)) - die(_("Not a valid object name %s"), arg); - cmit = lookup_commit_reference(&oid); - if (!cmit) - die(_("%s is not a valid '%s' object"), arg, commit_type); + cmit = lookup_commit_reference(oid); n = find_commit_name(&cmit->object.oid); if (n && (tags || all || n->prio == 2)) { /* * Exact match to an existing ref. */ - display_name(n); + append_name(n, dst); if (longformat) - show_suffix(0, n->tag ? &n->tag->tagged->oid : &oid); + append_suffix(0, n->tag ? &n->tag->tagged->oid : oid, dst); if (suffix) - printf("%s", suffix); - printf("\n"); + strbuf_addstr(dst, suffix); return; } if (!max_candidates) die(_("no tag exactly matches '%s'"), oid_to_hex(&cmit->object.oid)); if (debug) - fprintf(stderr, _("searching to describe %s\n"), arg); + fprintf(stderr, _("No exact match on refs or tags, searching to describe\n")); if (!have_util) { struct hashmap_iter iter; @@ -381,22 +378,21 @@ static void describe(const char *arg, int last_one) } if (!match_cnt) { - struct object_id *oid = &cmit->object.oid; + struct object_id *cmit_oid = &cmit->object.oid; if (always) { - printf("%s", find_unique_abbrev(oid->hash, abbrev)); + strbuf_addstr(dst, find_unique_abbrev(cmit_oid->hash, abbrev)); if (suffix) - printf("%s", suffix); - printf("\n"); + strbuf_addstr(dst, suffix); return; } if (unannotated_cnt) die(_("No annotated tags can describe '%s'.\n" "However, there were unannotated tags: try --tags."), - oid_to_hex(oid)); + oid_to_hex(cmit_oid)); else die(_("No tags can describe '%s'.\n" "Try --always, or create some tags."), - oid_to_hex(oid)); + oid_to_hex(cmit_oid)); } QSORT(all_matches, match_cnt, compare_pt); @@ -434,15 +430,86 @@ static void describe(const char *arg, int last_one) } } - display_name(all_matches[0].name); + append_name(all_matches[0].name, dst); if (abbrev) - show_suffix(all_matches[0].depth, &cmit->object.oid); + append_suffix(all_matches[0].depth, &cmit->object.oid, dst); if (suffix) - printf("%s", suffix); - printf("\n"); + strbuf_addstr(dst, suffix); +} + +struct process_commit_data { + struct object_id current_commit; + struct object_id looking_for; + struct strbuf *dst; + struct rev_info *revs; +}; + +static void process_commit(struct commit *commit, void *data) +{ + struct process_commit_data *pcd = data; + pcd->current_commit = commit->object.oid; +} + +static void process_object(struct object *obj, const char *path, void *data) +{ + struct process_commit_data *pcd = data; + + if (!oidcmp(&pcd->looking_for, &obj->oid) && !pcd->dst->len) { + reset_revision_walk(); + describe_commit(&pcd->current_commit, pcd->dst); + strbuf_addf(pcd->dst, ":%s", path); + free_commit_list(pcd->revs->commits); + pcd->revs->commits = NULL; + } +} + +static void describe_blob(struct object_id oid, struct strbuf *dst) +{ + struct rev_info revs; + struct argv_array args = ARGV_ARRAY_INIT; + struct process_commit_data pcd = { null_oid, oid, dst, &revs}; + + argv_array_pushl(&args, "internal: The first arg is not parsed", + "--objects", "--in-commit-order", "--reverse", "HEAD", + NULL); + + init_revisions(&revs, NULL); + if (setup_revisions(args.argc, args.argv, &revs, NULL) > 1) + BUG("setup_revisions could not handle all args?"); + + if (prepare_revision_walk(&revs)) + die("revision walk setup failed"); + + traverse_commit_list(&revs, process_commit, process_object, &pcd); + reset_revision_walk(); +} + +static void describe(const char *arg, int last_one) +{ + struct object_id oid; + struct commit *cmit; + struct strbuf sb = STRBUF_INIT; + + if (debug) + fprintf(stderr, _("describe %s\n"), arg); + + if (get_oid(arg, &oid)) + die(_("Not a valid object name %s"), arg); + cmit = lookup_commit_reference_gently(&oid, 1); + + if (cmit) + describe_commit(&oid, &sb); + else if (lookup_blob(&oid)) + describe_blob(oid, &sb); + else + die(_("%s is neither a commit nor blob"), arg); + + puts(sb.buf); if (!last_one) clear_commit_marks(cmit, -1); + + strbuf_release(&sb); } int cmd_describe(int argc, const char **argv, const char *prefix) |