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;
|
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[])
|
|||||||
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));
|
if (parents == 0) {
|
||||||
printf(" %s", buf);
|
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 (unmatched > 0)
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((sig = git_commit_author(commit)) != NULL) {
|
print_commit(commit);
|
||||||
printf("Author: %s <%s>\n", sig->name, sig->email);
|
++count;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 @@
|
|||||||
#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(
|
|||||||
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(
|
|||||||
uint8_t *used_patterns = NULL;
|
uint8_t *used_patterns = NULL;
|
||||||
char **file;
|
char **file;
|
||||||
|
|
||||||
*out = m = pathspec_match_alloc(ps);
|
if (out) {
|
||||||
GITERR_CHECK_ALLOC(m);
|
*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)
|
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(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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:
|
|||||||
|
|
||||||
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(
|
|||||||
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(
|
|||||||
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(
|
|||||||
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))) {
|
||||||
|
Loading…
Reference in New Issue
Block a user