[PATCH] Add --author match to git-rev-list and git-rev-tree.
Zack Brown wondered if handling author match at core GIT level would make cg-log -u go faster (JIT also can use this in jit-log --author). Here is a patch to implement it.
I considered adding author and committer strings to commit objects for general use as commit objects are parsed, but I was unsure about the lifetime rules of the commit objects (nobody seems to free them in the current code), so refrained from doing so for the time being. The code instead re-reads the commit object when it needs to filter them by the author.
Signed-off-by: Junio C Hamano <junkio@cox.net>
---
commit.c | 42 ++++++++++++++++++++++++++++++++++++++++++ commit.h | 2 ++ rev-list.c | 6 ++++++ rev-tree.c | 13 +++++++++++-- 4 files changed, 61 insertions(+), 2 deletions(-)
--- a/commit.c
+++ b/commit.c
@@ -152,3 +152,45 @@
}
return ret;
}
+
+int author_match(const struct commit *item, const char *author)
+{
+ char type[20];
+ void *buffer;
+ char *author_line, *ep;
+ unsigned long size;
+ int ret;
+
+ buffer = read_sha1_file(item->object.sha1, type, &size);
+ if (!buffer)
+ return error("Could not read %s",
+ sha1_to_hex(item->object.sha1));
+ if (strcmp(type, commit_type)) {
+ free(buffer);
+ error("Object %s not a commit",
+ sha1_to_hex(item->object.sha1));
+ return 0;
+ }
+ /* we do not care what is in the message; we do not
+ * want to overrun with strstr and strchr.
+ */
+ ep = buffer + (size -1);
+ *ep = 0;
+ if ((author_line = strstr(buffer, "\nauthor ")) == 0) {
+ free(buffer);
+ error("Commit %s does not have author.",
+ sha1_to_hex(item->object.sha1));
+ return 0;
+ }
+ author_line = strchr(author_line, ' ') + 1;
+ if ((ep = strchr(author_line, '>')) == 0) {
+ free(buffer);
+ error("Commit %s has a malformed author line.",
+ sha1_to_hex(item->object.sha1));
+ return 0;
+ }
+ *++ep = 0;
+ ret = (strstr(author_line, author) != 0);
+ free(buffer);
+ return ret;
+}
--- a/commit.h
+++ b/commit.h
@@ -36,4 +36,6 @@
struct commit *pop_most_recent_commit(struct commit_list **list,
unsigned int mark);
+int author_match(const struct commit *, const char *);
+
#endif /* COMMIT_H */
--- a/rev-list.c
+++ b/rev-list.c
@@ -11,6 +11,7 @@
unsigned long max_age = -1;
unsigned long min_age = -1;
int max_count = -1;
+ const char *author = NULL;
for (i = 1 ; i < argc; i++) {
char *arg = argv[i];
@@ -21,6 +22,8 @@
max_age = atoi(arg + 10);
} else if (!strncmp(arg, "--min-age=", 10)) {
min_age = atoi(arg + 10);
+ } else if (!strncmp(arg, "--author=", 9)) {
+ author = arg + 9;
} else {
commit_arg = arg;
}
@@ -28,6 +31,7 @@
if (!commit_arg || get_sha1(commit_arg, sha1))
usage("usage: rev-list [OPTION] commit-id\n"
+ " --author=author\n"
" --max-count=nr\n"
" --max-age=epoch\n"
" --min-age=epoch\n");
@@ -44,6 +48,8 @@
continue;
if (max_age != -1 && (commit->date < max_age))
break;
+ if (author && !author_match(commit, author))
+ continue;
if (max_count != -1 && !max_count--)
break;
printf("%s\n", sha1_to_hex(commit->object.sha1));
--- a/rev-tree.c
+++ b/rev-tree.c
@@ -64,7 +64,7 @@
}
/*
- * Usage: rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id2>]
+ * Usage: rev-tree [--edges] [--author <author>] [--cache <cache-file>] <commit-id> [<commit-id2>]
*
* The cache-file can be quite important for big trees. This is an
* expensive operation if you have to walk the whole chain of
@@ -75,6 +75,7 @@
int i;
int nr = 0;
unsigned char sha1[MAX_COMMITS][20];
+ const char *author = NULL;
/*
* First - pick up all the revisions we can (both from
@@ -83,6 +84,11 @@
for (i = 1; i < argc ; i++) {
char *arg = argv[i];
+ if (!strcmp(arg, "--author")) {
+ author = argv[++i];
+ continue;
+ }
+
if (!strcmp(arg, "--cache")) {
read_cache_file(argv[++i]);
continue;
@@ -98,7 +104,7 @@
basemask |= 1<<nr;
}
if (nr >= MAX_COMMITS || get_sha1(arg, sha1[nr]))
- usage("rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id>]");
+ usage("rev-tree [--edges] [--author <author>] [--cache <cache-file>] <commit-id> [<commit-id>]");
process_commit(sha1[nr]);
nr++;
}
@@ -125,6 +131,9 @@
if (!interesting(commit))
continue;
+ if (author && !author_match(commit, author))
+ continue;
+
printf("%lu %s:%d", commit->date, sha1_to_hex(obj->sha1),
obj->flags);
p = commit->parents;
------------------------------------------------