Commit a8b5f116 by Russell Belfer Committed by Vicent Marti

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.
parent 733c4f3a
...@@ -158,15 +158,73 @@ struct log_options { ...@@ -158,15 +158,73 @@ struct log_options {
char *committer; 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 main(int argc, char *argv[])
{ {
int i, count = 0; int i, count = 0, parents;
char *a; char *a;
struct log_state s; struct log_state s;
git_strarray paths; git_diff_options diffopts = GIT_DIFF_OPTIONS_INIT;
git_oid oid; git_oid oid;
git_commit *commit; git_commit *commit;
char buf[GIT_OID_HEXSZ + 1]; git_pathspec *ps = NULL;
git_threads_init(); git_threads_init();
...@@ -200,45 +258,47 @@ int main(int argc, char *argv[]) ...@@ -200,45 +258,47 @@ int main(int argc, char *argv[])
if (!count) if (!count)
add_revision(&s, NULL); add_revision(&s, NULL);
paths.strings = &argv[i]; diffopts.pathspec.strings = &argv[i];
paths.count = argc - i; diffopts.pathspec.count = argc - i;
count = 0;
while (!git_revwalk_next(&oid, s.walker)) { if (diffopts.pathspec.count > 0)
const git_signature *sig; check(git_pathspec_new(&ps, &diffopts.pathspec),
const char *scan, *eol; "Building pathspec", NULL);
for (; !git_revwalk_next(&oid, s.walker); git_commit_free(commit)) {
check(git_commit_lookup(&commit, s.repo, &oid), check(git_commit_lookup(&commit, s.repo, &oid),
"Failed to look up commit", NULL); "Failed to look up commit", NULL);
git_oid_tostr(buf, sizeof(buf), &oid); parents = (int)git_commit_parentcount(commit);
printf("commit %s\n", buf);
if ((count = (int)git_commit_parentcount(commit)) > 1) { if (diffopts.pathspec.count > 0) {
printf("Merge:"); int unmatched = parents;
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) { if (parents == 0) {
printf("Author: %s <%s>\n", sig->name, sig->email); git_tree *tree;
print_time(&sig->when, "Date: "); 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");
for (scan = git_commit_message(commit); scan && *scan; ) {
for (eol = scan; *eol && *eol != '\n'; ++eol) /* find eol */;
printf(" %.*s\n", (int)(eol - scan), scan); if (unmatched > 0)
scan = *eol ? eol + 1 : NULL; continue;
} }
printf("\n");
git_commit_free(commit); print_commit(commit);
++count;
} }
git_pathspec_free(ps);
git_revwalk_free(s.walker); git_revwalk_free(s.walker);
git_repository_free(s.repo); git_repository_free(s.repo);
git_threads_shutdown(); git_threads_shutdown();
......
...@@ -56,5 +56,6 @@ ...@@ -56,5 +56,6 @@
#include "git2/message.h" #include "git2/message.h"
#include "git2/pack.h" #include "git2/pack.h"
#include "git2/stash.h" #include "git2/stash.h"
#include "git2/pathspec.h"
#endif #endif
...@@ -311,7 +311,7 @@ static int pathspec_match_from_iterator( ...@@ -311,7 +311,7 @@ static int pathspec_match_from_iterator(
git_pathspec *ps) git_pathspec *ps)
{ {
int error = 0; int error = 0;
git_pathspec_match_list *m; git_pathspec_match_list *m = NULL;
const git_index_entry *entry = NULL; const git_index_entry *entry = NULL;
struct pathspec_match_context ctxt; struct pathspec_match_context ctxt;
git_vector *patterns = &ps->pathspec; git_vector *patterns = &ps->pathspec;
...@@ -322,8 +322,13 @@ static int pathspec_match_from_iterator( ...@@ -322,8 +322,13 @@ static int pathspec_match_from_iterator(
uint8_t *used_patterns = NULL; uint8_t *used_patterns = NULL;
char **file; char **file;
if (out) {
*out = m = pathspec_match_alloc(ps); *out = m = pathspec_match_alloc(ps);
GITERR_CHECK_ALLOC(m); GITERR_CHECK_ALLOC(m);
} else {
failures_only = true;
find_failures = false;
}
if ((error = git_iterator_reset(iter, ps->prefix, ps->prefix)) < 0) if ((error = git_iterator_reset(iter, ps->prefix, ps->prefix)) < 0)
goto done; goto done;
...@@ -385,7 +390,7 @@ static int pathspec_match_from_iterator( ...@@ -385,7 +390,7 @@ static int pathspec_match_from_iterator(
} }
/* if only looking at failures, exit early or just continue */ /* if only looking at failures, exit early or just continue */
if (failures_only) { if (failures_only || !out) {
if (used_ct == patterns->length) if (used_ct == patterns->length)
break; break;
continue; continue;
...@@ -429,7 +434,7 @@ done: ...@@ -429,7 +434,7 @@ done:
if (error < 0) { if (error < 0) {
pathspec_match_free(m); pathspec_match_free(m);
*out = NULL; if (out) *out = NULL;
} }
return error; return error;
...@@ -456,7 +461,7 @@ int git_pathspec_match_workdir( ...@@ -456,7 +461,7 @@ int git_pathspec_match_workdir(
int error = 0; int error = 0;
git_iterator *iter; git_iterator *iter;
assert(out && repo); assert(repo);
if (!(error = git_iterator_for_workdir( if (!(error = git_iterator_for_workdir(
&iter, repo, pathspec_match_iter_flags(flags), NULL, NULL))) { &iter, repo, pathspec_match_iter_flags(flags), NULL, NULL))) {
...@@ -478,7 +483,7 @@ int git_pathspec_match_index( ...@@ -478,7 +483,7 @@ int git_pathspec_match_index(
int error = 0; int error = 0;
git_iterator *iter; git_iterator *iter;
assert(out && index); assert(index);
if (!(error = git_iterator_for_index( if (!(error = git_iterator_for_index(
&iter, index, pathspec_match_iter_flags(flags), NULL, NULL))) { &iter, index, pathspec_match_iter_flags(flags), NULL, NULL))) {
...@@ -500,7 +505,7 @@ int git_pathspec_match_tree( ...@@ -500,7 +505,7 @@ int git_pathspec_match_tree(
int error = 0; int error = 0;
git_iterator *iter; git_iterator *iter;
assert(out && tree); assert(tree);
if (!(error = git_iterator_for_tree( if (!(error = git_iterator_for_tree(
&iter, tree, pathspec_match_iter_flags(flags), NULL, NULL))) { &iter, tree, pathspec_match_iter_flags(flags), NULL, NULL))) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment