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 {
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);
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);
parents = (int)git_commit_parentcount(commit);
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: ");
if (unmatched > 0)
continue;
}
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);
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;
*out = m = pathspec_match_alloc(ps);
GITERR_CHECK_ALLOC(m);
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))) {
......
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