]> git.proxmox.com Git - libgit2.git/blame - examples/describe.c
Update changelog for 1.1.0+dfsg.1-4.1 release
[libgit2.git] / examples / describe.c
CommitLineData
d6bbcefc
L
1/*
2 * libgit2 "describe" example - shows how to describe commits
3 *
4 * Written by the libgit2 contributors
5 *
6 * To the extent possible under law, the author(s) have dedicated all copyright
7 * and related and neighboring rights to this software to the public domain
8 * worldwide. This software is distributed without any warranty.
9 *
10 * You should have received a copy of the CC0 Public Domain Dedication along
11 * with this software. If not, see
12 * <http://creativecommons.org/publicdomain/zero/1.0/>.
13 */
14
15#include "common.h"
16
17/**
18 * The following example partially reimplements the `git describe` command
19 * and some of its options.
20 *
21 * These commands should work:
22
23 * - Describe HEAD with default options (`describe`)
24 * - Describe specified revision (`describe master~2`)
25 * - Describe specified revisions (`describe master~2 HEAD~3`)
26 * - Describe HEAD with dirty state suffix (`describe --dirty=*`)
27 * - Describe consider all refs (`describe --all master`)
28 * - Describe consider lightweight tags (`describe --tags temp-tag`)
29 * - Describe show non-default abbreviated size (`describe --abbrev=10`)
30 * - Describe always output the long format if matches a tag (`describe --long v1.0`)
31 * - Describe consider only tags of specified pattern (`describe --match v*-release`)
32 * - Describe show the fallback result (`describe --always`)
33 * - Describe follow only the first parent commit (`describe --first-parent`)
34 *
35 * The command line parsing logic is simplified and doesn't handle
36 * all of the use cases.
37 */
38
39/** describe_options represents the parsed command line options */
0c9c969a 40struct describe_options {
d6bbcefc
L
41 const char **commits;
42 size_t commit_count;
43 git_describe_options describe_options;
44 git_describe_format_options format_options;
0c9c969a 45};
d6bbcefc 46
0c9c969a 47static void opts_add_commit(struct describe_options *opts, const char *commit)
23d1dbe9
BE
48{
49 size_t sz;
50
51 assert(opts != NULL);
52
53 sz = ++opts->commit_count * sizeof(opts->commits[0]);
0c9c969a 54 opts->commits = xrealloc((void *) opts->commits, sz);
23d1dbe9
BE
55 opts->commits[opts->commit_count - 1] = commit;
56}
57
0c9c969a 58static void do_describe_single(git_repository *repo, struct describe_options *opts, const char *rev)
d6bbcefc
L
59{
60 git_object *commit;
61 git_describe_result *describe_result;
62 git_buf buf = { 0 };
0c9c969a 63
d6bbcefc
L
64 if (rev) {
65 check_lg2(git_revparse_single(&commit, repo, rev),
66 "Failed to lookup rev", rev);
67
68 check_lg2(git_describe_commit(&describe_result, commit, &opts->describe_options),
69 "Failed to describe rev", rev);
70 }
71 else
72 check_lg2(git_describe_workdir(&describe_result, repo, &opts->describe_options),
73 "Failed to describe workdir", NULL);
74
75 check_lg2(git_describe_format(&buf, describe_result, &opts->format_options),
76 "Failed to format describe rev", rev);
77
78 printf("%s\n", buf.ptr);
79}
80
0c9c969a 81static void do_describe(git_repository *repo, struct describe_options *opts)
d6bbcefc
L
82{
83 if (opts->commit_count == 0)
84 do_describe_single(repo, opts, NULL);
85 else
86 {
87 size_t i;
88 for (i = 0; i < opts->commit_count; i++)
89 do_describe_single(repo, opts, opts->commits[i]);
90 }
91}
92
93static void print_usage(void)
94{
95 fprintf(stderr, "usage: see `git help describe`\n");
96 exit(1);
97}
98
99/** Parse command line arguments */
0c9c969a 100static void parse_options(struct describe_options *opts, int argc, char **argv)
d6bbcefc 101{
0c9c969a 102 struct args_info args = ARGS_INFO_INIT;
d6bbcefc
L
103
104 for (args.pos = 1; args.pos < argc; ++args.pos) {
105 const char *curr = argv[args.pos];
106
107 if (curr[0] != '-') {
23d1dbe9 108 opts_add_commit(opts, curr);
d6bbcefc
L
109 } else if (!strcmp(curr, "--all")) {
110 opts->describe_options.describe_strategy = GIT_DESCRIBE_ALL;
111 } else if (!strcmp(curr, "--tags")) {
112 opts->describe_options.describe_strategy = GIT_DESCRIBE_TAGS;
113 } else if (!strcmp(curr, "--exact-match")) {
114 opts->describe_options.max_candidates_tags = 0;
115 } else if (!strcmp(curr, "--long")) {
116 opts->format_options.always_use_long_format = 1;
117 } else if (!strcmp(curr, "--always")) {
118 opts->describe_options.show_commit_oid_as_fallback = 1;
119 } else if (!strcmp(curr, "--first-parent")) {
120 opts->describe_options.only_follow_first_parent = 1;
121 } else if (optional_str_arg(&opts->format_options.dirty_suffix, &args, "--dirty", "-dirty")) {
122 } else if (match_int_arg((int *)&opts->format_options.abbreviated_size, &args, "--abbrev", 0)) {
123 } else if (match_int_arg((int *)&opts->describe_options.max_candidates_tags, &args, "--candidates", 0)) {
124 } else if (match_str_arg(&opts->describe_options.pattern, &args, "--match")) {
9334c86f
AB
125 } else {
126 print_usage();
d6bbcefc
L
127 }
128 }
129
130 if (opts->commit_count > 0) {
131 if (opts->format_options.dirty_suffix)
132 fatal("--dirty is incompatible with commit-ishes", NULL);
133 }
134 else {
135 if (!opts->format_options.dirty_suffix || !opts->format_options.dirty_suffix[0]) {
23d1dbe9 136 opts_add_commit(opts, "HEAD");
d6bbcefc
L
137 }
138 }
139}
140
141/** Initialize describe_options struct */
0c9c969a 142static void describe_options_init(struct describe_options *opts)
d6bbcefc
L
143{
144 memset(opts, 0, sizeof(*opts));
145
146 opts->commits = NULL;
147 opts->commit_count = 0;
0c9c969a
UG
148 git_describe_options_init(&opts->describe_options, GIT_DESCRIBE_OPTIONS_VERSION);
149 git_describe_format_options_init(&opts->format_options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
d6bbcefc
L
150}
151
0c9c969a 152int lg2_describe(git_repository *repo, int argc, char **argv)
d6bbcefc 153{
0c9c969a 154 struct describe_options opts;
d6bbcefc
L
155
156 describe_options_init(&opts);
157 parse_options(&opts, argc, argv);
158
159 do_describe(repo, &opts);
160
d6bbcefc
L
161 return 0;
162}