builtin/describe.c: describe a blob
[git/git.git] / builtin / describe.c
index 9e9a5ed..5b4bfab 100644 (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"
@@ -11,8 +12,9 @@
 #include "hashmap.h"
 #include "argv-array.h"
 #include "run-command.h"
+#include "revision.h"
+#include "list-objects.h"
 
-#define SEEN           (1u << 0)
 #define MAX_TAGS       (FLAG_BITS - 1)
 
 static const char * const describe_usage[] = {
@@ -434,6 +436,53 @@ static void describe_commit(struct object_id *oid, struct strbuf *dst)
                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;
@@ -445,11 +494,14 @@ static void describe(const char *arg, int last_one)
 
        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_gently(&oid, 1);
 
-       describe_commit(&oid, &sb);
+       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);