mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-02 16:34:37 +00:00
Fix example/log.c pathspec handling of merges
This fixes the way the example log program decides if a merge commit should be shown when a pathspec is given. Also makes it easier to use the pathspec API to just check "does a tree match anything in the pathspec" without allocating a match list.
This commit is contained in:
parent
733c4f3aca
commit
a8b5f116bc
124
examples/log.c
124
examples/log.c
@ -158,15 +158,73 @@ struct log_options {
|
||||
char *committer;
|
||||
};
|
||||
|
||||
static void print_commit(git_commit *commit)
|
||||
{
|
||||
char buf[GIT_OID_HEXSZ + 1];
|
||||
int i, count;
|
||||
const git_signature *sig;
|
||||
const char *scan, *eol;
|
||||
|
||||
git_oid_tostr(buf, sizeof(buf), git_commit_id(commit));
|
||||
printf("commit %s\n", buf);
|
||||
|
||||
if ((count = (int)git_commit_parentcount(commit)) > 1) {
|
||||
printf("Merge:");
|
||||
for (i = 0; i < count; ++i) {
|
||||
git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
|
||||
printf(" %s", buf);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if ((sig = git_commit_author(commit)) != NULL) {
|
||||
printf("Author: %s <%s>\n", sig->name, sig->email);
|
||||
print_time(&sig->when, "Date: ");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (scan = git_commit_message(commit); scan && *scan; ) {
|
||||
for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */;
|
||||
|
||||
printf(" %.*s\n", (int)(eol - scan), scan);
|
||||
scan = *eol ? eol + 1 : NULL;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int match_with_parent(
|
||||
git_commit *commit, int i, git_diff_options *opts)
|
||||
{
|
||||
git_commit *parent;
|
||||
git_tree *a, *b;
|
||||
git_diff_list *diff;
|
||||
int ndeltas;
|
||||
|
||||
check(git_commit_parent(&parent, commit, (size_t)i), "Get parent", NULL);
|
||||
check(git_commit_tree(&a, parent), "Tree for parent", NULL);
|
||||
check(git_commit_tree(&b, commit), "Tree for commit", NULL);
|
||||
check(git_diff_tree_to_tree(&diff, git_commit_owner(commit), a, b, opts),
|
||||
"Checking diff between parent and commit", NULL);
|
||||
|
||||
ndeltas = (int)git_diff_num_deltas(diff);
|
||||
|
||||
git_diff_list_free(diff);
|
||||
git_tree_free(a);
|
||||
git_tree_free(b);
|
||||
git_commit_free(parent);
|
||||
|
||||
return ndeltas > 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int i, count = 0;
|
||||
int i, count = 0, parents;
|
||||
char *a;
|
||||
struct log_state s;
|
||||
git_strarray paths;
|
||||
git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
|
||||
git_oid oid;
|
||||
git_commit *commit;
|
||||
char buf[GIT_OID_HEXSZ + 1];
|
||||
git_pathspec *ps = NULL;
|
||||
|
||||
git_threads_init();
|
||||
|
||||
@ -200,45 +258,47 @@ int main(int argc, char *argv[])
|
||||
if (!count)
|
||||
add_revision(&s, NULL);
|
||||
|
||||
paths.strings = &argv[i];
|
||||
paths.count = argc - i;
|
||||
|
||||
while (!git_revwalk_next(&oid, s.walker)) {
|
||||
const git_signature *sig;
|
||||
const char *scan, *eol;
|
||||
diffopts.pathspec.strings = &argv[i];
|
||||
diffopts.pathspec.count = argc - i;
|
||||
count = 0;
|
||||
if (diffopts.pathspec.count > 0)
|
||||
check(git_pathspec_new(&ps, &diffopts.pathspec),
|
||||
"Building pathspec", NULL);
|
||||
|
||||
for (; !git_revwalk_next(&oid, s.walker); git_commit_free(commit)) {
|
||||
check(git_commit_lookup(&commit, s.repo, &oid),
|
||||
"Failed to look up commit", NULL);
|
||||
|
||||
git_oid_tostr(buf, sizeof(buf), &oid);
|
||||
printf("commit %s\n", buf);
|
||||
parents = (int)git_commit_parentcount(commit);
|
||||
|
||||
if ((count = (int)git_commit_parentcount(commit)) > 1) {
|
||||
printf("Merge:");
|
||||
for (i = 0; i < count; ++i) {
|
||||
git_oid_tostr(buf, 8, git_commit_parent_id(commit, i));
|
||||
printf(" %s", buf);
|
||||
if (diffopts.pathspec.count > 0) {
|
||||
int unmatched = parents;
|
||||
|
||||
if (parents == 0) {
|
||||
git_tree *tree;
|
||||
check(git_commit_tree(&tree, commit), "Get tree", NULL);
|
||||
if (git_pathspec_match_tree(
|
||||
NULL, tree, GIT_PATHSPEC_NO_MATCH_ERROR, ps) != 0)
|
||||
unmatched = 1;
|
||||
git_tree_free(tree);
|
||||
} else if (parents == 1) {
|
||||
unmatched = match_with_parent(commit, 0, &diffopts) ? 0 : 1;
|
||||
} else {
|
||||
for (i = 0; i < parents; ++i) {
|
||||
if (match_with_parent(commit, i, &diffopts))
|
||||
unmatched--;
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if ((sig = git_commit_author(commit)) != NULL) {
|
||||
printf("Author: %s <%s>\n", sig->name, sig->email);
|
||||
print_time(&sig->when, "Date: ");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
for (scan = git_commit_message(commit); scan && *scan; ) {
|
||||
for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */;
|
||||
|
||||
printf(" %.*s\n", (int)(eol - scan), scan);
|
||||
scan = *eol ? eol + 1 : NULL;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
git_commit_free(commit);
|
||||
if (unmatched > 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
print_commit(commit);
|
||||
++count;
|
||||
}
|
||||
|
||||
git_pathspec_free(ps);
|
||||
git_revwalk_free(s.walker);
|
||||
git_repository_free(s.repo);
|
||||
git_threads_shutdown();
|
||||
|
@ -56,5 +56,6 @@
|
||||
#include "git2/message.h"
|
||||
#include "git2/pack.h"
|
||||
#include "git2/stash.h"
|
||||
#include "git2/pathspec.h"
|
||||
|
||||
#endif
|
||||
|
@ -311,7 +311,7 @@ static int pathspec_match_from_iterator(
|
||||
git_pathspec *ps)
|
||||
{
|
||||
int error = 0;
|
||||
git_pathspec_match_list *m;
|
||||
git_pathspec_match_list *m = NULL;
|
||||
const git_index_entry *entry = NULL;
|
||||
struct pathspec_match_context ctxt;
|
||||
git_vector *patterns = &ps->pathspec;
|
||||
@ -322,8 +322,13 @@ static int pathspec_match_from_iterator(
|
||||
uint8_t *used_patterns = NULL;
|
||||
char **file;
|
||||
|
||||
if (out) {
|
||||
*out = m = pathspec_match_alloc(ps);
|
||||
GITERR_CHECK_ALLOC(m);
|
||||
} else {
|
||||
failures_only = true;
|
||||
find_failures = false;
|
||||
}
|
||||
|
||||
if ((error = git_iterator_reset(iter, ps->prefix, ps->prefix)) < 0)
|
||||
goto done;
|
||||
@ -385,7 +390,7 @@ static int pathspec_match_from_iterator(
|
||||
}
|
||||
|
||||
/* if only looking at failures, exit early or just continue */
|
||||
if (failures_only) {
|
||||
if (failures_only || !out) {
|
||||
if (used_ct == patterns->length)
|
||||
break;
|
||||
continue;
|
||||
@ -429,7 +434,7 @@ done:
|
||||
|
||||
if (error < 0) {
|
||||
pathspec_match_free(m);
|
||||
*out = NULL;
|
||||
if (out) *out = NULL;
|
||||
}
|
||||
|
||||
return error;
|
||||
@ -456,7 +461,7 @@ int git_pathspec_match_workdir(
|
||||
int error = 0;
|
||||
git_iterator *iter;
|
||||
|
||||
assert(out && repo);
|
||||
assert(repo);
|
||||
|
||||
if (!(error = git_iterator_for_workdir(
|
||||
&iter, repo, pathspec_match_iter_flags(flags), NULL, NULL))) {
|
||||
@ -478,7 +483,7 @@ int git_pathspec_match_index(
|
||||
int error = 0;
|
||||
git_iterator *iter;
|
||||
|
||||
assert(out && index);
|
||||
assert(index);
|
||||
|
||||
if (!(error = git_iterator_for_index(
|
||||
&iter, index, pathspec_match_iter_flags(flags), NULL, NULL))) {
|
||||
@ -500,7 +505,7 @@ int git_pathspec_match_tree(
|
||||
int error = 0;
|
||||
git_iterator *iter;
|
||||
|
||||
assert(out && tree);
|
||||
assert(tree);
|
||||
|
||||
if (!(error = git_iterator_for_tree(
|
||||
&iter, tree, pathspec_match_iter_flags(flags), NULL, NULL))) {
|
||||
|
Loading…
Reference in New Issue
Block a user