/*
* libgit2 "rev-list" example - shows how to transform a rev-spec into a list
* of commit ids
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* .
*/
#include "common.h"
#include
static int revwalk_parse_options(git_sort_t *sort, struct args_info *args);
static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args);
int lg2_rev_list(git_repository *repo, int argc, char **argv)
{
struct args_info args = ARGS_INFO_INIT;
git_revwalk *walk;
git_oid oid;
git_sort_t sort;
char buf[GIT_OID_SHA1_HEXSIZE+1];
check_lg2(revwalk_parse_options(&sort, &args), "parsing options", NULL);
check_lg2(git_revwalk_new(&walk, repo), "allocating revwalk", NULL);
git_revwalk_sorting(walk, sort);
check_lg2(revwalk_parse_revs(repo, walk, &args), "parsing revs", NULL);
while (!git_revwalk_next(&oid, walk)) {
git_oid_fmt(buf, &oid);
buf[GIT_OID_SHA1_HEXSIZE] = '\0';
printf("%s\n", buf);
}
git_revwalk_free(walk);
return 0;
}
static int push_commit(git_revwalk *walk, const git_oid *oid, int hide)
{
if (hide)
return git_revwalk_hide(walk, oid);
else
return git_revwalk_push(walk, oid);
}
static int push_spec(git_repository *repo, git_revwalk *walk, const char *spec, int hide)
{
int error;
git_object *obj;
if ((error = git_revparse_single(&obj, repo, spec)) < 0)
return error;
error = push_commit(walk, git_object_id(obj), hide);
git_object_free(obj);
return error;
}
static int push_range(git_repository *repo, git_revwalk *walk, const char *range, int hide)
{
git_revspec revspec;
int error = 0;
if ((error = git_revparse(&revspec, repo, range)))
return error;
if (revspec.flags & GIT_REVSPEC_MERGE_BASE) {
/* TODO: support "..." */
return GIT_EINVALIDSPEC;
}
if ((error = push_commit(walk, git_object_id(revspec.from), !hide)))
goto out;
error = push_commit(walk, git_object_id(revspec.to), hide);
out:
git_object_free(revspec.from);
git_object_free(revspec.to);
return error;
}
static void print_usage(void)
{
fprintf(stderr, "rev-list [--git-dir=dir] [--topo-order|--date-order] [--reverse] \n");
exit(-1);
}
static int revwalk_parse_options(git_sort_t *sort, struct args_info *args)
{
assert(sort && args);
*sort = GIT_SORT_NONE;
if (args->argc < 1)
print_usage();
for (args->pos = 1; args->pos < args->argc; ++args->pos) {
const char *curr = args->argv[args->pos];
if (!strcmp(curr, "--topo-order")) {
*sort |= GIT_SORT_TOPOLOGICAL;
} else if (!strcmp(curr, "--date-order")) {
*sort |= GIT_SORT_TIME;
} else if (!strcmp(curr, "--reverse")) {
*sort |= (*sort & ~GIT_SORT_REVERSE) ^ GIT_SORT_REVERSE;
} else {
break;
}
}
return 0;
}
static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args)
{
int hide, error;
git_oid oid;
hide = 0;
for (; args->pos < args->argc; ++args->pos) {
const char *curr = args->argv[args->pos];
if (!strcmp(curr, "--not")) {
hide = !hide;
} else if (curr[0] == '^') {
if ((error = push_spec(repo, walk, curr + 1, !hide)))
return error;
} else if (strstr(curr, "..")) {
if ((error = push_range(repo, walk, curr, hide)))
return error;
} else {
if (push_spec(repo, walk, curr, hide) == 0)
continue;
#ifdef GIT_EXPERIMENTAL_SHA256
if ((error = git_oid_fromstr(&oid, curr, GIT_OID_SHA1)))
return error;
#else
if ((error = git_oid_fromstr(&oid, curr)))
return error;
#endif
if ((error = push_commit(walk, &oid, hide)))
return error;
}
}
return 0;
}