]> git.proxmox.com Git - libgit2.git/blob - src/describe.c
Merge pull request #2972 from libgit2/cmn/pack-objects-walk
[libgit2.git] / src / describe.c
1 /*
2 * Copyright (C) the libgit2 contributors. All rights reserved.
3 *
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
6 */
7 #include "git2/describe.h"
8 #include "git2/strarray.h"
9 #include "git2/diff.h"
10 #include "git2/status.h"
11
12 #include "common.h"
13 #include "commit.h"
14 #include "commit_list.h"
15 #include "oidmap.h"
16 #include "refs.h"
17 #include "revwalk.h"
18 #include "tag.h"
19 #include "vector.h"
20 #include "repository.h"
21
22 GIT__USE_OIDMAP;
23
24 /* Ported from https://github.com/git/git/blob/89dde7882f71f846ccd0359756d27bebc31108de/builtin/describe.c */
25
26 struct commit_name {
27 git_tag *tag;
28 unsigned prio:2; /* annotated tag = 2, tag = 1, head = 0 */
29 unsigned name_checked:1;
30 git_oid sha1;
31 char *path;
32
33 /* Khash workaround. They original key has to still be reachable */
34 git_oid peeled;
35 };
36
37 static void *oidmap_value_bykey(git_oidmap *map, const git_oid *key)
38 {
39 khint_t pos = git_oidmap_lookup_index(map, key);
40
41 if (!git_oidmap_valid_index(map, pos))
42 return NULL;
43
44 return git_oidmap_value_at(map, pos);
45 }
46
47 static struct commit_name *find_commit_name(
48 git_oidmap *names,
49 const git_oid *peeled)
50 {
51 return (struct commit_name *)(oidmap_value_bykey(names, peeled));
52 }
53
54 static int replace_name(
55 git_tag **tag,
56 git_repository *repo,
57 struct commit_name *e,
58 unsigned int prio,
59 const git_oid *sha1)
60 {
61 git_time_t e_time = 0, t_time = 0;
62
63 if (!e || e->prio < prio)
64 return 1;
65
66 if (e->prio == 2 && prio == 2) {
67 /* Multiple annotated tags point to the same commit.
68 * Select one to keep based upon their tagger date.
69 */
70 git_tag *t = NULL;
71
72 if (!e->tag) {
73 if (git_tag_lookup(&t, repo, &e->sha1) < 0)
74 return 1;
75 e->tag = t;
76 }
77
78 if (git_tag_lookup(&t, repo, sha1) < 0)
79 return 0;
80
81 *tag = t;
82
83 if (e->tag->tagger)
84 e_time = e->tag->tagger->when.time;
85
86 if (t->tagger)
87 t_time = t->tagger->when.time;
88
89 if (e_time < t_time)
90 return 1;
91 }
92
93 return 0;
94 }
95
96 static int add_to_known_names(
97 git_repository *repo,
98 git_oidmap *names,
99 const char *path,
100 const git_oid *peeled,
101 unsigned int prio,
102 const git_oid *sha1)
103 {
104 struct commit_name *e = find_commit_name(names, peeled);
105 bool found = (e != NULL);
106
107 git_tag *tag = NULL;
108 if (replace_name(&tag, repo, e, prio, sha1)) {
109 if (!found) {
110 e = git__malloc(sizeof(struct commit_name));
111 GITERR_CHECK_ALLOC(e);
112
113 e->path = NULL;
114 e->tag = NULL;
115 }
116
117 if (e->tag)
118 git_tag_free(e->tag);
119 e->tag = tag;
120 e->prio = prio;
121 e->name_checked = 0;
122 git_oid_cpy(&e->sha1, sha1);
123 git__free(e->path);
124 e->path = git__strdup(path);
125 git_oid_cpy(&e->peeled, peeled);
126
127 if (!found) {
128 int ret;
129
130 git_oidmap_insert(names, &e->peeled, e, ret);
131 if (ret < 0)
132 return -1;
133 }
134 }
135 else
136 git_tag_free(tag);
137
138 return 0;
139 }
140
141 static int retrieve_peeled_tag_or_object_oid(
142 git_oid *peeled_out,
143 git_oid *ref_target_out,
144 git_repository *repo,
145 const char *refname)
146 {
147 git_reference *ref;
148 git_object *peeled = NULL;
149 int error;
150
151 if ((error = git_reference_lookup_resolved(&ref, repo, refname, -1)) < 0)
152 return error;
153
154 if ((error = git_reference_peel(&peeled, ref, GIT_OBJ_ANY)) < 0)
155 goto cleanup;
156
157 git_oid_cpy(ref_target_out, git_reference_target(ref));
158 git_oid_cpy(peeled_out, git_object_id(peeled));
159
160 if (git_oid_cmp(ref_target_out, peeled_out) != 0)
161 error = 1; /* The reference was pointing to a annotated tag */
162 else
163 error = 0; /* Any other object */
164
165 cleanup:
166 git_reference_free(ref);
167 git_object_free(peeled);
168 return error;
169 }
170
171 struct git_describe_result {
172 int dirty;
173 int exact_match;
174 int fallback_to_id;
175 git_oid commit_id;
176 git_repository *repo;
177 struct commit_name *name;
178 struct possible_tag *tag;
179 };
180
181 struct get_name_data
182 {
183 git_describe_options *opts;
184 git_repository *repo;
185 git_oidmap *names;
186 git_describe_result *result;
187 };
188
189 static int commit_name_dup(struct commit_name **out, struct commit_name *in)
190 {
191 struct commit_name *name;
192
193 name = git__malloc(sizeof(struct commit_name));
194 GITERR_CHECK_ALLOC(name);
195
196 memcpy(name, in, sizeof(struct commit_name));
197 name->tag = NULL;
198 name->path = NULL;
199
200 if (in->tag && git_object_dup((git_object **) &name->tag, (git_object *) in->tag) < 0)
201 return -1;
202
203 name->path = git__strdup(in->path);
204 GITERR_CHECK_ALLOC(name->path);
205
206 *out = name;
207 return 0;
208 }
209
210 static int get_name(const char *refname, void *payload)
211 {
212 struct get_name_data *data;
213 bool is_tag, is_annotated, all;
214 git_oid peeled, sha1;
215 unsigned int prio;
216 int error = 0;
217
218 data = (struct get_name_data *)payload;
219 is_tag = !git__prefixcmp(refname, GIT_REFS_TAGS_DIR);
220 all = data->opts->describe_strategy == GIT_DESCRIBE_ALL;
221
222 /* Reject anything outside refs/tags/ unless --all */
223 if (!all && !is_tag)
224 return 0;
225
226 /* Accept only tags that match the pattern, if given */
227 if (data->opts->pattern && (!is_tag || p_fnmatch(data->opts->pattern,
228 refname + strlen(GIT_REFS_TAGS_DIR), 0)))
229 return 0;
230
231 /* Is it annotated? */
232 if ((error = retrieve_peeled_tag_or_object_oid(
233 &peeled, &sha1, data->repo, refname)) < 0)
234 return error;
235
236 is_annotated = error;
237
238 /*
239 * By default, we only use annotated tags, but with --tags
240 * we fall back to lightweight ones (even without --tags,
241 * we still remember lightweight ones, only to give hints
242 * in an error message). --all allows any refs to be used.
243 */
244 if (is_annotated)
245 prio = 2;
246 else if (is_tag)
247 prio = 1;
248 else
249 prio = 0;
250
251 add_to_known_names(data->repo, data->names,
252 all ? refname + strlen(GIT_REFS_DIR) : refname + strlen(GIT_REFS_TAGS_DIR),
253 &peeled, prio, &sha1);
254 return 0;
255 }
256
257 struct possible_tag {
258 struct commit_name *name;
259 int depth;
260 int found_order;
261 unsigned flag_within;
262 };
263
264 static int possible_tag_dup(struct possible_tag **out, struct possible_tag *in)
265 {
266 struct possible_tag *tag;
267 int error;
268
269 tag = git__malloc(sizeof(struct possible_tag));
270 GITERR_CHECK_ALLOC(tag);
271
272 memcpy(tag, in, sizeof(struct possible_tag));
273 tag->name = NULL;
274
275 if ((error = commit_name_dup(&tag->name, in->name)) < 0) {
276 git__free(tag);
277 *out = NULL;
278 return error;
279 }
280
281 *out = tag;
282 return 0;
283 }
284
285 static int compare_pt(const void *a_, const void *b_)
286 {
287 struct possible_tag *a = (struct possible_tag *)a_;
288 struct possible_tag *b = (struct possible_tag *)b_;
289 if (a->depth != b->depth)
290 return a->depth - b->depth;
291 if (a->found_order != b->found_order)
292 return a->found_order - b->found_order;
293 return 0;
294 }
295
296 #define SEEN (1u << 0)
297
298 static unsigned long finish_depth_computation(
299 git_pqueue *list,
300 git_revwalk *walk,
301 struct possible_tag *best)
302 {
303 unsigned long seen_commits = 0;
304 int error, i;
305
306 while (git_pqueue_size(list) > 0) {
307 git_commit_list_node *c = git_pqueue_pop(list);
308 seen_commits++;
309 if (c->flags & best->flag_within) {
310 size_t index = 0;
311 while (git_pqueue_size(list) > index) {
312 git_commit_list_node *i = git_pqueue_get(list, index);
313 if (!(i->flags & best->flag_within))
314 break;
315 index++;
316 }
317 if (index > git_pqueue_size(list))
318 break;
319 } else
320 best->depth++;
321 for (i = 0; i < c->out_degree; i++) {
322 git_commit_list_node *p = c->parents[i];
323 if ((error = git_commit_list_parse(walk, p)) < 0)
324 return error;
325 if (!(p->flags & SEEN))
326 if ((error = git_pqueue_insert(list, p)) < 0)
327 return error;
328 p->flags |= c->flags;
329 }
330 }
331 return seen_commits;
332 }
333
334 static int display_name(git_buf *buf, git_repository *repo, struct commit_name *n)
335 {
336 if (n->prio == 2 && !n->tag) {
337 if (git_tag_lookup(&n->tag, repo, &n->sha1) < 0) {
338 giterr_set(GITERR_TAG, "Annotated tag '%s' not available", n->path);
339 return -1;
340 }
341 }
342
343 if (n->tag && !n->name_checked) {
344 if (!git_tag_name(n->tag)) {
345 giterr_set(GITERR_TAG, "Annotated tag '%s' has no embedded name", n->path);
346 return -1;
347 }
348
349 /* TODO: Cope with warnings
350 if (strcmp(n->tag->tag, all ? n->path + 5 : n->path))
351 warning(_("tag '%s' is really '%s' here"), n->tag->tag, n->path);
352 */
353
354 n->name_checked = 1;
355 }
356
357 if (n->tag)
358 git_buf_printf(buf, "%s", git_tag_name(n->tag));
359 else
360 git_buf_printf(buf, "%s", n->path);
361
362 return 0;
363 }
364
365 static int find_unique_abbrev_size(
366 int *out,
367 git_repository *repo,
368 const git_oid *oid_in,
369 int abbreviated_size)
370 {
371 size_t size = abbreviated_size;
372 git_odb *odb;
373 git_oid dummy;
374 int error;
375
376 if ((error = git_repository_odb__weakptr(&odb, repo)) < 0)
377 return error;
378
379 while (size < GIT_OID_HEXSZ) {
380 if ((error = git_odb_exists_prefix(&dummy, odb, oid_in, size)) == 0) {
381 *out = (int) size;
382 return 0;
383 }
384
385 /* If the error wasn't that it's not unique, then it's a proper error */
386 if (error != GIT_EAMBIGUOUS)
387 return error;
388
389 /* Try again with a larger size */
390 size++;
391 }
392
393 /* If we didn't find any shorter prefix, we have to do the whole thing */
394 *out = GIT_OID_HEXSZ;
395
396 return 0;
397 }
398
399 static int show_suffix(
400 git_buf *buf,
401 int depth,
402 git_repository *repo,
403 const git_oid* id,
404 size_t abbrev_size)
405 {
406 int error, size = 0;
407
408 char hex_oid[GIT_OID_HEXSZ];
409
410 if ((error = find_unique_abbrev_size(&size, repo, id, abbrev_size)) < 0)
411 return error;
412
413 git_oid_fmt(hex_oid, id);
414
415 git_buf_printf(buf, "-%d-g", depth);
416
417 git_buf_put(buf, hex_oid, size);
418
419 return git_buf_oom(buf) ? -1 : 0;
420 }
421
422 #define MAX_CANDIDATES_TAGS FLAG_BITS - 1
423
424 static int describe_not_found(const git_oid *oid, const char *message_format) {
425 char oid_str[GIT_OID_HEXSZ + 1];
426 git_oid_tostr(oid_str, sizeof(oid_str), oid);
427
428 giterr_set(GITERR_DESCRIBE, message_format, oid_str);
429 return GIT_ENOTFOUND;
430 }
431
432 static int describe(
433 struct get_name_data *data,
434 git_commit *commit)
435 {
436 struct commit_name *n;
437 struct possible_tag *best;
438 bool all, tags;
439 git_revwalk *walk = NULL;
440 git_pqueue list;
441 git_commit_list_node *cmit, *gave_up_on = NULL;
442 git_vector all_matches = GIT_VECTOR_INIT;
443 unsigned int match_cnt = 0, annotated_cnt = 0, cur_match;
444 unsigned long seen_commits = 0; /* TODO: Check long */
445 unsigned int unannotated_cnt = 0;
446 int error;
447
448 if (git_vector_init(&all_matches, MAX_CANDIDATES_TAGS, compare_pt) < 0)
449 return -1;
450
451 if ((error = git_pqueue_init(&list, 0, 2, git_commit_list_time_cmp)) < 0)
452 goto cleanup;
453
454 all = data->opts->describe_strategy == GIT_DESCRIBE_ALL;
455 tags = data->opts->describe_strategy == GIT_DESCRIBE_TAGS;
456
457 git_oid_cpy(&data->result->commit_id, git_commit_id(commit));
458
459 n = find_commit_name(data->names, git_commit_id(commit));
460 if (n && (tags || all || n->prio == 2)) {
461 /*
462 * Exact match to an existing ref.
463 */
464 data->result->exact_match = 1;
465 if ((error = commit_name_dup(&data->result->name, n)) < 0)
466 goto cleanup;
467
468 goto cleanup;
469 }
470
471 if (!data->opts->max_candidates_tags) {
472 error = describe_not_found(
473 git_commit_id(commit),
474 "Cannot describe - no tag exactly matches '%s'");
475
476 goto cleanup;
477 }
478
479 if ((error = git_revwalk_new(&walk, git_commit_owner(commit))) < 0)
480 goto cleanup;
481
482 if ((cmit = git_revwalk__commit_lookup(walk, git_commit_id(commit))) == NULL)
483 goto cleanup;
484
485 if ((error = git_commit_list_parse(walk, cmit)) < 0)
486 goto cleanup;
487
488 cmit->flags = SEEN;
489
490 if ((error = git_pqueue_insert(&list, cmit)) < 0)
491 goto cleanup;
492
493 while (git_pqueue_size(&list) > 0)
494 {
495 int i;
496
497 git_commit_list_node *c = (git_commit_list_node *)git_pqueue_pop(&list);
498 seen_commits++;
499
500 n = find_commit_name(data->names, &c->oid);
501
502 if (n) {
503 if (!tags && !all && n->prio < 2) {
504 unannotated_cnt++;
505 } else if (match_cnt < data->opts->max_candidates_tags) {
506 struct possible_tag *t = git__malloc(sizeof(struct commit_name));
507 GITERR_CHECK_ALLOC(t);
508 if ((error = git_vector_insert(&all_matches, t)) < 0)
509 goto cleanup;
510
511 match_cnt++;
512
513 t->name = n;
514 t->depth = seen_commits - 1;
515 t->flag_within = 1u << match_cnt;
516 t->found_order = match_cnt;
517 c->flags |= t->flag_within;
518 if (n->prio == 2)
519 annotated_cnt++;
520 }
521 else {
522 gave_up_on = c;
523 break;
524 }
525 }
526
527 for (cur_match = 0; cur_match < match_cnt; cur_match++) {
528 struct possible_tag *t = git_vector_get(&all_matches, cur_match);
529 if (!(c->flags & t->flag_within))
530 t->depth++;
531 }
532
533 if (annotated_cnt && (git_pqueue_size(&list) == 0)) {
534 /*
535 if (debug) {
536 char oid_str[GIT_OID_HEXSZ + 1];
537 git_oid_tostr(oid_str, sizeof(oid_str), &c->oid);
538
539 fprintf(stderr, "finished search at %s\n", oid_str);
540 }
541 */
542 break;
543 }
544 for (i = 0; i < c->out_degree; i++) {
545 git_commit_list_node *p = c->parents[i];
546 if ((error = git_commit_list_parse(walk, p)) < 0)
547 goto cleanup;
548 if (!(p->flags & SEEN))
549 if ((error = git_pqueue_insert(&list, p)) < 0)
550 goto cleanup;
551 p->flags |= c->flags;
552
553 if (data->opts->only_follow_first_parent)
554 break;
555 }
556 }
557
558 if (!match_cnt) {
559 if (data->opts->show_commit_oid_as_fallback) {
560 data->result->fallback_to_id = 1;
561 git_oid_cpy(&data->result->commit_id, &cmit->oid);
562
563 goto cleanup;
564 }
565 if (unannotated_cnt) {
566 error = describe_not_found(git_commit_id(commit),
567 "Cannot describe - "
568 "No annotated tags can describe '%s'."
569 "However, there were unannotated tags.");
570 goto cleanup;
571 }
572 else {
573 error = describe_not_found(git_commit_id(commit),
574 "Cannot describe - "
575 "No tags can describe '%s'.");
576 goto cleanup;
577 }
578 }
579
580 git_vector_sort(&all_matches);
581
582 best = (struct possible_tag *)git_vector_get(&all_matches, 0);
583
584 if (gave_up_on) {
585 git_pqueue_insert(&list, gave_up_on);
586 seen_commits--;
587 }
588 if ((error = finish_depth_computation(
589 &list, walk, best)) < 0)
590 goto cleanup;
591
592 seen_commits += error;
593 if ((error = possible_tag_dup(&data->result->tag, best)) < 0)
594 goto cleanup;
595
596 /*
597 {
598 static const char *prio_names[] = {
599 "head", "lightweight", "annotated",
600 };
601
602 char oid_str[GIT_OID_HEXSZ + 1];
603
604 if (debug) {
605 for (cur_match = 0; cur_match < match_cnt; cur_match++) {
606 struct possible_tag *t = (struct possible_tag *)git_vector_get(&all_matches, cur_match);
607 fprintf(stderr, " %-11s %8d %s\n",
608 prio_names[t->name->prio],
609 t->depth, t->name->path);
610 }
611 fprintf(stderr, "traversed %lu commits\n", seen_commits);
612 if (gave_up_on) {
613 git_oid_tostr(oid_str, sizeof(oid_str), &gave_up_on->oid);
614 fprintf(stderr,
615 "more than %i tags found; listed %i most recent\n"
616 "gave up search at %s\n",
617 data->opts->max_candidates_tags, data->opts->max_candidates_tags,
618 oid_str);
619 }
620 }
621 }
622 */
623
624 git_oid_cpy(&data->result->commit_id, &cmit->oid);
625
626 cleanup:
627 {
628 size_t i;
629 struct possible_tag *match;
630 git_vector_foreach(&all_matches, i, match) {
631 git__free(match);
632 }
633 }
634 git_vector_free(&all_matches);
635 git_pqueue_free(&list);
636 git_revwalk_free(walk);
637 return error;
638 }
639
640 static int normalize_options(
641 git_describe_options *dst,
642 const git_describe_options *src)
643 {
644 git_describe_options default_options = GIT_DESCRIBE_OPTIONS_INIT;
645 if (!src) src = &default_options;
646
647 *dst = *src;
648
649 if (dst->max_candidates_tags > GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS)
650 dst->max_candidates_tags = GIT_DESCRIBE_DEFAULT_MAX_CANDIDATES_TAGS;
651
652 return 0;
653 }
654
655 int git_describe_commit(
656 git_describe_result **result,
657 git_object *committish,
658 git_describe_options *opts)
659 {
660 struct get_name_data data;
661 struct commit_name *name;
662 git_commit *commit;
663 int error = -1;
664 git_describe_options normalized;
665
666 assert(committish);
667
668 data.result = git__calloc(1, sizeof(git_describe_result));
669 GITERR_CHECK_ALLOC(data.result);
670 data.result->repo = git_object_owner(committish);
671
672 data.repo = git_object_owner(committish);
673
674 if ((error = normalize_options(&normalized, opts)) < 0)
675 return error;
676
677 GITERR_CHECK_VERSION(
678 &normalized,
679 GIT_DESCRIBE_OPTIONS_VERSION,
680 "git_describe_options");
681 data.opts = &normalized;
682
683 data.names = git_oidmap_alloc();
684 GITERR_CHECK_ALLOC(data.names);
685
686 /** TODO: contains to be implemented */
687
688 if ((error = git_object_peel((git_object **)(&commit), committish, GIT_OBJ_COMMIT)) < 0)
689 goto cleanup;
690
691 if ((error = git_reference_foreach_name(
692 git_object_owner(committish),
693 get_name, &data)) < 0)
694 goto cleanup;
695
696 if (git_oidmap_size(data.names) == 0) {
697 giterr_set(GITERR_DESCRIBE, "Cannot describe - "
698 "No reference found, cannot describe anything.");
699 error = -1;
700 goto cleanup;
701 }
702
703 if ((error = describe(&data, commit)) < 0)
704 goto cleanup;
705
706 cleanup:
707 git_commit_free(commit);
708
709 git_oidmap_foreach_value(data.names, name, {
710 git_tag_free(name->tag);
711 git__free(name->path);
712 git__free(name);
713 });
714
715 git_oidmap_free(data.names);
716
717 if (error < 0)
718 git_describe_result_free(data.result);
719 else
720 *result = data.result;
721
722 return error;
723 }
724
725 int git_describe_workdir(
726 git_describe_result **out,
727 git_repository *repo,
728 git_describe_options *opts)
729 {
730 int error;
731 git_oid current_id;
732 git_status_list *status = NULL;
733 git_status_options status_opts = GIT_STATUS_OPTIONS_INIT;
734 git_describe_result *result = NULL;
735 git_object *commit;
736
737 if ((error = git_reference_name_to_id(&current_id, repo, GIT_HEAD_FILE)) < 0)
738 return error;
739
740 if ((error = git_object_lookup(&commit, repo, &current_id, GIT_OBJ_COMMIT)) < 0)
741 return error;
742
743 /* The first step is to perform a describe of HEAD, so we can leverage this */
744 if ((error = git_describe_commit(&result, commit, opts)) < 0)
745 goto out;
746
747 if ((error = git_status_list_new(&status, repo, &status_opts)) < 0)
748 goto out;
749
750
751 if (git_status_list_entrycount(status) > 0)
752 result->dirty = 1;
753
754 out:
755 git_object_free(commit);
756 git_status_list_free(status);
757
758 if (error < 0)
759 git_describe_result_free(result);
760 else
761 *out = result;
762
763 return error;
764 }
765
766 static int normalize_format_options(
767 git_describe_format_options *dst,
768 const git_describe_format_options *src)
769 {
770 if (!src) {
771 git_describe_init_format_options(dst, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
772 return 0;
773 }
774
775 memcpy(dst, src, sizeof(git_describe_format_options));
776 return 0;
777 }
778
779 int git_describe_format(git_buf *out, const git_describe_result *result, const git_describe_format_options *given)
780 {
781 int error;
782 git_repository *repo;
783 struct commit_name *name;
784 git_describe_format_options opts;
785
786 assert(out && result);
787
788 GITERR_CHECK_VERSION(given, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION, "git_describe_format_options");
789 normalize_format_options(&opts, given);
790
791 git_buf_sanitize(out);
792
793
794 if (opts.always_use_long_format && opts.abbreviated_size == 0) {
795 giterr_set(GITERR_DESCRIBE, "Cannot describe - "
796 "'always_use_long_format' is incompatible with a zero"
797 "'abbreviated_size'");
798 return -1;
799 }
800
801
802 repo = result->repo;
803
804 /* If we did find an exact match, then it's the easier method */
805 if (result->exact_match) {
806 name = result->name;
807 if ((error = display_name(out, repo, name)) < 0)
808 return error;
809
810 if (opts.always_use_long_format) {
811 const git_oid *id = name->tag ? git_tag_target_id(name->tag) : &result->commit_id;
812 if ((error = show_suffix(out, 0, repo, id, opts.abbreviated_size)) < 0)
813 return error;
814 }
815
816 if (result->dirty && opts.dirty_suffix)
817 git_buf_puts(out, opts.dirty_suffix);
818
819 return git_buf_oom(out) ? -1 : 0;
820 }
821
822 /* If we didn't find *any* tags, we fall back to the commit's id */
823 if (result->fallback_to_id) {
824 char hex_oid[GIT_OID_HEXSZ + 1] = {0};
825 int size = 0;
826
827 if ((error = find_unique_abbrev_size(
828 &size, repo, &result->commit_id, opts.abbreviated_size)) < 0)
829 return -1;
830
831 git_oid_fmt(hex_oid, &result->commit_id);
832 git_buf_put(out, hex_oid, size);
833
834 if (result->dirty && opts.dirty_suffix)
835 git_buf_puts(out, opts.dirty_suffix);
836
837 return git_buf_oom(out) ? -1 : 0;
838 }
839
840 /* Lastly, if we found a matching tag, we show that */
841 name = result->tag->name;
842
843 if ((error = display_name(out, repo, name)) < 0)
844 return error;
845
846 if (opts.abbreviated_size) {
847 if ((error = show_suffix(out, result->tag->depth, repo,
848 &result->commit_id, opts.abbreviated_size)) < 0)
849 return error;
850 }
851
852 if (result->dirty && opts.dirty_suffix) {
853 git_buf_puts(out, opts.dirty_suffix);
854 }
855
856 return git_buf_oom(out) ? -1 : 0;
857 }
858
859 void git_describe_result_free(git_describe_result *result)
860 {
861 if (result == NULL)
862 return;
863
864 if (result->name) {
865 git_tag_free(result->name->tag);
866 git__free(result->name->path);
867 git__free(result->name);
868 }
869
870 if (result->tag) {
871 git_tag_free(result->tag->name->tag);
872 git__free(result->tag->name->path);
873 git__free(result->tag->name);
874 git__free(result->tag);
875 }
876
877 git__free(result);
878 }
879
880 int git_describe_init_options(git_describe_options *opts, unsigned int version)
881 {
882 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
883 opts, version, git_describe_options, GIT_DESCRIBE_OPTIONS_INIT);
884 return 0;
885 }
886
887 int git_describe_init_format_options(git_describe_format_options *opts, unsigned int version)
888 {
889 GIT_INIT_STRUCTURE_FROM_TEMPLATE(
890 opts, version, git_describe_format_options, GIT_DESCRIBE_FORMAT_OPTIONS_INIT);
891 return 0;
892 }