describe.con commit git-describe: use find_unique_abbrev() (4cdf78b)
   1#include "cache.h"
   2#include "commit.h"
   3#include "tag.h"
   4#include "refs.h"
   5
   6#define SEEN (1u << 0)
   7
   8static const char describe_usage[] = "git-describe [--all] <committish>*";
   9
  10static int all = 0;     /* Default to annotated tags only */
  11
  12static int names = 0, allocs = 0;
  13static struct commit_name {
  14        const struct commit *commit;
  15        char path[];
  16} **name_array = NULL;
  17
  18static struct commit_name *match(struct commit *cmit)
  19{
  20        int i = names;
  21        struct commit_name **p = name_array;
  22
  23        while (i-- > 0) {
  24                struct commit_name *n = *p++;
  25                if (n->commit == cmit)
  26                        return n;
  27        }
  28        return NULL;
  29}
  30
  31static void add_to_known_names(const char *path, const struct commit *commit)
  32{
  33        int idx;
  34        int len = strlen(path)+1;
  35        struct commit_name *name = xmalloc(sizeof(struct commit_name) + len);
  36
  37        name->commit = commit;
  38        memcpy(name->path, path, len);
  39        idx = names;
  40        if (idx >= allocs) {
  41                allocs = (idx + 50) * 3 / 2;
  42                name_array = xrealloc(name_array, allocs*sizeof(*name_array));
  43        }
  44        name_array[idx] = name;
  45        names = ++idx;
  46}
  47
  48static int get_name(const char *path, const unsigned char *sha1)
  49{
  50        struct commit *commit = lookup_commit_reference_gently(sha1, 1);
  51        if (!commit)
  52                return 0;
  53        if (!all) {
  54                struct object *object;
  55                if (strncmp(path, "refs/tags/", 10))
  56                        return 0;
  57                object = parse_object(sha1);
  58                if (object->type != tag_type)
  59                        return 0;
  60        }
  61        add_to_known_names(all ? path : path + 10, commit);
  62        return 0;
  63}
  64
  65static int compare_names(const void *_a, const void *_b)
  66{
  67        struct commit_name *a = *(struct commit_name **)_a;
  68        struct commit_name *b = *(struct commit_name **)_b;
  69        unsigned long a_date = a->commit->date;
  70        unsigned long b_date = b->commit->date;
  71        return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
  72}
  73
  74static void describe(struct commit *cmit)
  75{
  76        struct commit_list *list;
  77        static int initialized = 0;
  78        struct commit_name *n;
  79
  80        if (!initialized) {
  81                initialized = 1;
  82                for_each_ref(get_name);
  83                qsort(name_array, names, sizeof(*name_array), compare_names);
  84        }
  85
  86        n = match(cmit);
  87        if (n) {
  88                printf("%s\n", n->path);
  89                return;
  90        }
  91
  92        list = NULL;
  93        commit_list_insert(cmit, &list);
  94        while (list) {
  95                struct commit *c = pop_most_recent_commit(&list, SEEN);
  96                n = match(c);
  97                if (n) {
  98                        printf("%s-g%s\n", n->path,
  99                               find_unique_abbrev(cmit->object.sha1, 8));
 100                        return;
 101                }
 102        }
 103}
 104
 105int main(int argc, char **argv)
 106{
 107        int i;
 108
 109        for (i = 1; i < argc; i++) {
 110                const char *arg = argv[i];
 111                unsigned char sha1[20];
 112                struct commit *cmit;
 113
 114                if (!strcmp(arg, "--all")) {
 115                        all = 1;
 116                        continue;
 117                }
 118                if (get_sha1(arg, sha1) < 0)
 119                        usage(describe_usage);
 120                cmit = lookup_commit_reference(sha1);
 121                if (!cmit)
 122                        usage(describe_usage);
 123                describe(cmit);
 124        }
 125        return 0;
 126}