2 * libgit2 "describe" example - shows how to describe commits
4 * Written by the libgit2 contributors
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.
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/>.
18 * The following example partially reimplements the `git describe` command
19 * and some of its options.
21 * These commands should work:
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`)
35 * The command line parsing logic is simplified and doesn't handle
36 * all of the use cases.
39 /** describe_options represents the parsed command line options */
40 struct describe_options
{
43 git_describe_options describe_options
;
44 git_describe_format_options format_options
;
47 static void opts_add_commit(struct describe_options
*opts
, const char *commit
)
53 sz
= ++opts
->commit_count
* sizeof(opts
->commits
[0]);
54 opts
->commits
= xrealloc((void *) opts
->commits
, sz
);
55 opts
->commits
[opts
->commit_count
- 1] = commit
;
58 static void do_describe_single(git_repository
*repo
, struct describe_options
*opts
, const char *rev
)
61 git_describe_result
*describe_result
;
65 check_lg2(git_revparse_single(&commit
, repo
, rev
),
66 "Failed to lookup rev", rev
);
68 check_lg2(git_describe_commit(&describe_result
, commit
, &opts
->describe_options
),
69 "Failed to describe rev", rev
);
72 check_lg2(git_describe_workdir(&describe_result
, repo
, &opts
->describe_options
),
73 "Failed to describe workdir", NULL
);
75 check_lg2(git_describe_format(&buf
, describe_result
, &opts
->format_options
),
76 "Failed to format describe rev", rev
);
78 printf("%s\n", buf
.ptr
);
81 static void do_describe(git_repository
*repo
, struct describe_options
*opts
)
83 if (opts
->commit_count
== 0)
84 do_describe_single(repo
, opts
, NULL
);
88 for (i
= 0; i
< opts
->commit_count
; i
++)
89 do_describe_single(repo
, opts
, opts
->commits
[i
]);
93 static void print_usage(void)
95 fprintf(stderr
, "usage: see `git help describe`\n");
99 /** Parse command line arguments */
100 static void parse_options(struct describe_options
*opts
, int argc
, char **argv
)
102 struct args_info args
= ARGS_INFO_INIT
;
104 for (args
.pos
= 1; args
.pos
< argc
; ++args
.pos
) {
105 const char *curr
= argv
[args
.pos
];
107 if (curr
[0] != '-') {
108 opts_add_commit(opts
, curr
);
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")) {
130 if (opts
->commit_count
> 0) {
131 if (opts
->format_options
.dirty_suffix
)
132 fatal("--dirty is incompatible with commit-ishes", NULL
);
135 if (!opts
->format_options
.dirty_suffix
|| !opts
->format_options
.dirty_suffix
[0]) {
136 opts_add_commit(opts
, "HEAD");
141 /** Initialize describe_options struct */
142 static void describe_options_init(struct describe_options
*opts
)
144 memset(opts
, 0, sizeof(*opts
));
146 opts
->commits
= NULL
;
147 opts
->commit_count
= 0;
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
);
152 int lg2_describe(git_repository
*repo
, int argc
, char **argv
)
154 struct describe_options opts
;
156 describe_options_init(&opts
);
157 parse_options(&opts
, argc
, argv
);
159 do_describe(repo
, &opts
);