]> rtime.felk.cvut.cz Git - git.git/blob - builtin/describe.c
name-hash: retire unused index_name_exists()
[git.git] / builtin / describe.c
1 #include "cache.h"
2 #include "commit.h"
3 #include "tag.h"
4 #include "refs.h"
5 #include "builtin.h"
6 #include "exec_cmd.h"
7 #include "parse-options.h"
8 #include "diff.h"
9 #include "hashmap.h"
10 #include "argv-array.h"
11
12 #define SEEN            (1u<<0)
13 #define MAX_TAGS        (FLAG_BITS - 1)
14
15 static const char * const describe_usage[] = {
16         N_("git describe [options] <commit-ish>*"),
17         N_("git describe [options] --dirty"),
18         NULL
19 };
20
21 static int debug;       /* Display lots of verbose info */
22 static int all; /* Any valid ref can be used */
23 static int tags;        /* Allow lightweight tags */
24 static int longformat;
25 static int first_parent;
26 static int abbrev = -1; /* unspecified */
27 static int max_candidates = 10;
28 static struct hashmap names;
29 static int have_util;
30 static const char *pattern;
31 static int always;
32 static const char *dirty;
33
34 /* diff-index command arguments to check if working tree is dirty. */
35 static const char *diff_index_args[] = {
36         "diff-index", "--quiet", "HEAD", "--", NULL
37 };
38
39
40 struct commit_name {
41         struct hashmap_entry entry;
42         unsigned char peeled[20];
43         struct tag *tag;
44         unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
45         unsigned name_checked:1;
46         unsigned char sha1[20];
47         char *path;
48 };
49 static const char *prio_names[] = {
50         "head", "lightweight", "annotated",
51 };
52
53 static int commit_name_cmp(const struct commit_name *cn1,
54                 const struct commit_name *cn2, const void *peeled)
55 {
56         return hashcmp(cn1->peeled, peeled ? peeled : cn2->peeled);
57 }
58
59 static inline unsigned int hash_sha1(const unsigned char *sha1)
60 {
61         unsigned int hash;
62         memcpy(&hash, sha1, sizeof(hash));
63         return hash;
64 }
65
66 static inline struct commit_name *find_commit_name(const unsigned char *peeled)
67 {
68         struct commit_name key;
69         hashmap_entry_init(&key, hash_sha1(peeled));
70         return hashmap_get(&names, &key, peeled);
71 }
72
73 static int replace_name(struct commit_name *e,
74                                int prio,
75                                const unsigned char *sha1,
76                                struct tag **tag)
77 {
78         if (!e || e->prio < prio)
79                 return 1;
80
81         if (e->prio == 2 && prio == 2) {
82                 /* Multiple annotated tags point to the same commit.
83                  * Select one to keep based upon their tagger date.
84                  */
85                 struct tag *t;
86
87                 if (!e->tag) {
88                         t = lookup_tag(e->sha1);
89                         if (!t || parse_tag(t))
90                                 return 1;
91                         e->tag = t;
92                 }
93
94                 t = lookup_tag(sha1);
95                 if (!t || parse_tag(t))
96                         return 0;
97                 *tag = t;
98
99                 if (e->tag->date < t->date)
100                         return 1;
101         }
102
103         return 0;
104 }
105
106 static void add_to_known_names(const char *path,
107                                const unsigned char *peeled,
108                                int prio,
109                                const unsigned char *sha1)
110 {
111         struct commit_name *e = find_commit_name(peeled);
112         struct tag *tag = NULL;
113         if (replace_name(e, prio, sha1, &tag)) {
114                 if (!e) {
115                         e = xmalloc(sizeof(struct commit_name));
116                         hashcpy(e->peeled, peeled);
117                         hashmap_entry_init(e, hash_sha1(peeled));
118                         hashmap_add(&names, e);
119                         e->path = NULL;
120                 }
121                 e->tag = tag;
122                 e->prio = prio;
123                 e->name_checked = 0;
124                 hashcpy(e->sha1, sha1);
125                 free(e->path);
126                 e->path = xstrdup(path);
127         }
128 }
129
130 static int get_name(const char *path, const unsigned char *sha1, int flag, void *cb_data)
131 {
132         int is_tag = !prefixcmp(path, "refs/tags/");
133         unsigned char peeled[20];
134         int is_annotated, prio;
135
136         /* Reject anything outside refs/tags/ unless --all */
137         if (!all && !is_tag)
138                 return 0;
139
140         /* Accept only tags that match the pattern, if given */
141         if (pattern && (!is_tag || fnmatch(pattern, path + 10, 0)))
142                 return 0;
143
144         /* Is it annotated? */
145         if (!peel_ref(path, peeled)) {
146                 is_annotated = !!hashcmp(sha1, peeled);
147         } else {
148                 hashcpy(peeled, sha1);
149                 is_annotated = 0;
150         }
151
152         /*
153          * By default, we only use annotated tags, but with --tags
154          * we fall back to lightweight ones (even without --tags,
155          * we still remember lightweight ones, only to give hints
156          * in an error message).  --all allows any refs to be used.
157          */
158         if (is_annotated)
159                 prio = 2;
160         else if (is_tag)
161                 prio = 1;
162         else
163                 prio = 0;
164
165         add_to_known_names(all ? path + 5 : path + 10, peeled, prio, sha1);
166         return 0;
167 }
168
169 struct possible_tag {
170         struct commit_name *name;
171         int depth;
172         int found_order;
173         unsigned flag_within;
174 };
175
176 static int compare_pt(const void *a_, const void *b_)
177 {
178         struct possible_tag *a = (struct possible_tag *)a_;
179         struct possible_tag *b = (struct possible_tag *)b_;
180         if (a->depth != b->depth)
181                 return a->depth - b->depth;
182         if (a->found_order != b->found_order)
183                 return a->found_order - b->found_order;
184         return 0;
185 }
186
187 static unsigned long finish_depth_computation(
188         struct commit_list **list,
189         struct possible_tag *best)
190 {
191         unsigned long seen_commits = 0;
192         while (*list) {
193                 struct commit *c = pop_commit(list);
194                 struct commit_list *parents = c->parents;
195                 seen_commits++;
196                 if (c->object.flags & best->flag_within) {
197                         struct commit_list *a = *list;
198                         while (a) {
199                                 struct commit *i = a->item;
200                                 if (!(i->object.flags & best->flag_within))
201                                         break;
202                                 a = a->next;
203                         }
204                         if (!a)
205                                 break;
206                 } else
207                         best->depth++;
208                 while (parents) {
209                         struct commit *p = parents->item;
210                         parse_commit(p);
211                         if (!(p->object.flags & SEEN))
212                                 commit_list_insert_by_date(p, list);
213                         p->object.flags |= c->object.flags;
214                         parents = parents->next;
215                 }
216         }
217         return seen_commits;
218 }
219
220 static void display_name(struct commit_name *n)
221 {
222         if (n->prio == 2 && !n->tag) {
223                 n->tag = lookup_tag(n->sha1);
224                 if (!n->tag || parse_tag(n->tag))
225                         die(_("annotated tag %s not available"), n->path);
226         }
227         if (n->tag && !n->name_checked) {
228                 if (!n->tag->tag)
229                         die(_("annotated tag %s has no embedded name"), n->path);
230                 if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
231                         warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
232                 n->name_checked = 1;
233         }
234
235         if (n->tag)
236                 printf("%s", n->tag->tag);
237         else
238                 printf("%s", n->path);
239 }
240
241 static void show_suffix(int depth, const unsigned char *sha1)
242 {
243         printf("-%d-g%s", depth, find_unique_abbrev(sha1, abbrev));
244 }
245
246 static void describe(const char *arg, int last_one)
247 {
248         unsigned char sha1[20];
249         struct commit *cmit, *gave_up_on = NULL;
250         struct commit_list *list;
251         struct commit_name *n;
252         struct possible_tag all_matches[MAX_TAGS];
253         unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
254         unsigned long seen_commits = 0;
255         unsigned int unannotated_cnt = 0;
256
257         if (get_sha1(arg, sha1))
258                 die(_("Not a valid object name %s"), arg);
259         cmit = lookup_commit_reference(sha1);
260         if (!cmit)
261                 die(_("%s is not a valid '%s' object"), arg, commit_type);
262
263         n = find_commit_name(cmit->object.sha1);
264         if (n && (tags || all || n->prio == 2)) {
265                 /*
266                  * Exact match to an existing ref.
267                  */
268                 display_name(n);
269                 if (longformat)
270                         show_suffix(0, n->tag ? n->tag->tagged->sha1 : sha1);
271                 if (dirty)
272                         printf("%s", dirty);
273                 printf("\n");
274                 return;
275         }
276
277         if (!max_candidates)
278                 die(_("no tag exactly matches '%s'"), sha1_to_hex(cmit->object.sha1));
279         if (debug)
280                 fprintf(stderr, _("searching to describe %s\n"), arg);
281
282         if (!have_util) {
283                 struct hashmap_iter iter;
284                 struct commit *c;
285                 struct commit_name *n = hashmap_iter_first(&names, &iter);
286                 for (; n; n = hashmap_iter_next(&iter)) {
287                         c = lookup_commit_reference_gently(n->peeled, 1);
288                         if (c)
289                                 c->util = n;
290                 }
291                 have_util = 1;
292         }
293
294         list = NULL;
295         cmit->object.flags = SEEN;
296         commit_list_insert(cmit, &list);
297         while (list) {
298                 struct commit *c = pop_commit(&list);
299                 struct commit_list *parents = c->parents;
300                 seen_commits++;
301                 n = c->util;
302                 if (n) {
303                         if (!tags && !all && n->prio < 2) {
304                                 unannotated_cnt++;
305                         } else if (match_cnt < max_candidates) {
306                                 struct possible_tag *t = &all_matches[match_cnt++];
307                                 t->name = n;
308                                 t->depth = seen_commits - 1;
309                                 t->flag_within = 1u << match_cnt;
310                                 t->found_order = match_cnt;
311                                 c->object.flags |= t->flag_within;
312                                 if (n->prio == 2)
313                                         annotated_cnt++;
314                         }
315                         else {
316                                 gave_up_on = c;
317                                 break;
318                         }
319                 }
320                 for (cur_match = 0; cur_match < match_cnt; cur_match++) {
321                         struct possible_tag *t = &all_matches[cur_match];
322                         if (!(c->object.flags & t->flag_within))
323                                 t->depth++;
324                 }
325                 if (annotated_cnt && !list) {
326                         if (debug)
327                                 fprintf(stderr, _("finished search at %s\n"),
328                                         sha1_to_hex(c->object.sha1));
329                         break;
330                 }
331                 while (parents) {
332                         struct commit *p = parents->item;
333                         parse_commit(p);
334                         if (!(p->object.flags & SEEN))
335                                 commit_list_insert_by_date(p, &list);
336                         p->object.flags |= c->object.flags;
337                         parents = parents->next;
338
339                         if (first_parent)
340                                 break;
341                 }
342         }
343
344         if (!match_cnt) {
345                 const unsigned char *sha1 = cmit->object.sha1;
346                 if (always) {
347                         printf("%s", find_unique_abbrev(sha1, abbrev));
348                         if (dirty)
349                                 printf("%s", dirty);
350                         printf("\n");
351                         return;
352                 }
353                 if (unannotated_cnt)
354                         die(_("No annotated tags can describe '%s'.\n"
355                             "However, there were unannotated tags: try --tags."),
356                             sha1_to_hex(sha1));
357                 else
358                         die(_("No tags can describe '%s'.\n"
359                             "Try --always, or create some tags."),
360                             sha1_to_hex(sha1));
361         }
362
363         qsort(all_matches, match_cnt, sizeof(all_matches[0]), compare_pt);
364
365         if (gave_up_on) {
366                 commit_list_insert_by_date(gave_up_on, &list);
367                 seen_commits--;
368         }
369         seen_commits += finish_depth_computation(&list, &all_matches[0]);
370         free_commit_list(list);
371
372         if (debug) {
373                 for (cur_match = 0; cur_match < match_cnt; cur_match++) {
374                         struct possible_tag *t = &all_matches[cur_match];
375                         fprintf(stderr, " %-11s %8d %s\n",
376                                 prio_names[t->name->prio],
377                                 t->depth, t->name->path);
378                 }
379                 fprintf(stderr, _("traversed %lu commits\n"), seen_commits);
380                 if (gave_up_on) {
381                         fprintf(stderr,
382                                 _("more than %i tags found; listed %i most recent\n"
383                                 "gave up search at %s\n"),
384                                 max_candidates, max_candidates,
385                                 sha1_to_hex(gave_up_on->object.sha1));
386                 }
387         }
388
389         display_name(all_matches[0].name);
390         if (abbrev)
391                 show_suffix(all_matches[0].depth, cmit->object.sha1);
392         if (dirty)
393                 printf("%s", dirty);
394         printf("\n");
395
396         if (!last_one)
397                 clear_commit_marks(cmit, -1);
398 }
399
400 int cmd_describe(int argc, const char **argv, const char *prefix)
401 {
402         int contains = 0;
403         struct option options[] = {
404                 OPT_BOOL(0, "contains",   &contains, N_("find the tag that comes after the commit")),
405                 OPT_BOOL(0, "debug",      &debug, N_("debug search strategy on stderr")),
406                 OPT_BOOL(0, "all",        &all, N_("use any ref")),
407                 OPT_BOOL(0, "tags",       &tags, N_("use any tag, even unannotated")),
408                 OPT_BOOL(0, "long",       &longformat, N_("always use long format")),
409                 OPT_BOOL(0, "first-parent", &first_parent, N_("only follow first parent")),
410                 OPT__ABBREV(&abbrev),
411                 OPT_SET_INT(0, "exact-match", &max_candidates,
412                             N_("only output exact matches"), 0),
413                 OPT_INTEGER(0, "candidates", &max_candidates,
414                             N_("consider <n> most recent tags (default: 10)")),
415                 OPT_STRING(0, "match",       &pattern, N_("pattern"),
416                            N_("only consider tags matching <pattern>")),
417                 OPT_BOOL(0, "always",        &always,
418                         N_("show abbreviated commit object as fallback")),
419                 {OPTION_STRING, 0, "dirty",  &dirty, N_("mark"),
420                         N_("append <mark> on dirty working tree (default: \"-dirty\")"),
421                         PARSE_OPT_OPTARG, NULL, (intptr_t) "-dirty"},
422                 OPT_END(),
423         };
424
425         git_config(git_default_config, NULL);
426         argc = parse_options(argc, argv, prefix, options, describe_usage, 0);
427         if (abbrev < 0)
428                 abbrev = DEFAULT_ABBREV;
429
430         if (max_candidates < 0)
431                 max_candidates = 0;
432         else if (max_candidates > MAX_TAGS)
433                 max_candidates = MAX_TAGS;
434
435         save_commit_buffer = 0;
436
437         if (longformat && abbrev == 0)
438                 die(_("--long is incompatible with --abbrev=0"));
439
440         if (contains) {
441                 struct argv_array args;
442
443                 argv_array_init(&args);
444                 argv_array_pushl(&args, "name-rev",
445                                  "--peel-tag", "--name-only", "--no-undefined",
446                                  NULL);
447                 if (always)
448                         argv_array_push(&args, "--always");
449                 if (!all) {
450                         argv_array_push(&args, "--tags");
451                         if (pattern)
452                                 argv_array_pushf(&args, "--refs=refs/tags/%s", pattern);
453                 }
454                 while (*argv) {
455                         argv_array_push(&args, *argv);
456                         argv++;
457                 }
458                 return cmd_name_rev(args.argc, args.argv, prefix);
459         }
460
461         hashmap_init(&names, (hashmap_cmp_fn) commit_name_cmp, 0);
462         for_each_rawref(get_name, NULL);
463         if (!names.size && !always)
464                 die(_("No names found, cannot describe anything."));
465
466         if (argc == 0) {
467                 if (dirty) {
468                         static struct lock_file index_lock;
469                         int fd;
470
471                         read_cache_preload(NULL);
472                         refresh_index(&the_index, REFRESH_QUIET|REFRESH_UNMERGED,
473                                       NULL, NULL, NULL);
474                         fd = hold_locked_index(&index_lock, 0);
475                         if (0 <= fd)
476                                 update_index_if_able(&the_index, &index_lock);
477
478                         if (!cmd_diff_index(ARRAY_SIZE(diff_index_args) - 1,
479                                             diff_index_args, prefix))
480                                 dirty = NULL;
481                 }
482                 describe("HEAD", 1);
483         } else if (dirty) {
484                 die(_("--dirty is incompatible with commit-ishes"));
485         } else {
486                 while (argc-- > 0) {
487                         describe(*argv++, argc == 0);
488                 }
489         }
490         return 0;
491 }