Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Belfer <rb@github.com>2013-07-04 04:00:50 +0400
committerVicent Marti <tanoku@gmail.com>2013-07-10 22:50:32 +0400
commita8b5f116bc39f884c8888adae2fd3f9b96d972c0 (patch)
tree698a9df61ec2853dcb52e8bbc393d09a5c46a00c
parent733c4f3aca212d90459fb21cfbc137f09ff6c951 (diff)
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.
-rw-r--r--examples/log.c124
-rw-r--r--include/git2.h1
-rw-r--r--src/pathspec.c21
3 files changed, 106 insertions, 40 deletions
diff --git a/examples/log.c b/examples/log.c
index ba411d7a4..50e81efad 100644
--- a/examples/log.c
+++ b/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);
-
- 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();
diff --git a/include/git2.h b/include/git2.h
index 5f9fc4824..e8638a830 100644
--- a/include/git2.h
+++ b/include/git2.h
@@ -56,5 +56,6 @@
#include "git2/message.h"
#include "git2/pack.h"
#include "git2/stash.h"
+#include "git2/pathspec.h"
#endif
diff --git a/src/pathspec.c b/src/pathspec.c
index 35421dbef..021f38f1c 100644
--- a/src/pathspec.c
+++ b/src/pathspec.c
@@ -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))) {