Merge branch 'sb/describe-blob'

"git describe" was taught to dig trees deeper to find a
<commit-ish>:<path> that refers to a given blob object.

* sb/describe-blob:
  builtin/describe.c: describe a blob
  builtin/describe.c: factor out describe_commit
  builtin/describe.c: print debug statements earlier
  builtin/describe.c: rename `oid` to avoid variable shadowing
  revision.h: introduce blob/tree walking in order of the commits
  list-objects.c: factor out traverse_trees_and_blobs
  t6120: fix typo in test name
This commit is contained in:
Junio C Hamano
2017-12-28 14:08:50 -08:00
8 changed files with 277 additions and 52 deletions

View File

@ -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)