]> git.ipfire.org Git - thirdparty/git.git/blobdiff - revision.c
git-log --author and --committer are not left-anchored by default
[thirdparty/git.git] / revision.c
index db01682750a4dfa820ea3f0e4a99e306aa6b075a..bca122961e0fded660f34e65659d93f00c91bdfc 100644 (file)
@@ -6,6 +6,8 @@
 #include "diff.h"
 #include "refs.h"
 #include "revision.h"
+#include <regex.h>
+#include "grep.h"
 
 static char *path_name(struct name_path *path, const char *name)
 {
@@ -416,7 +418,8 @@ static void limit_list(struct rev_info *revs)
 
                if (revs->max_age != -1 && (commit->date < revs->max_age))
                        obj->flags |= UNINTERESTING;
-               if (revs->unpacked && has_sha1_pack(obj->sha1))
+               if (revs->unpacked &&
+                   has_sha1_pack(obj->sha1, revs->ignore_packed))
                        obj->flags |= UNINTERESTING;
                add_parents_to_list(revs, commit, &list);
                if (obj->flags & UNINTERESTING) {
@@ -671,6 +674,56 @@ int handle_revision_arg(const char *arg, struct rev_info *revs,
        return 0;
 }
 
+static void add_header_grep(struct rev_info *revs, const char *field, const char *pattern)
+{
+       char *pat;
+       const char *prefix;
+       int patlen, fldlen;
+
+       if (!revs->header_filter) {
+               struct grep_opt *opt = xcalloc(1, sizeof(*opt));
+               opt->status_only = 1;
+               opt->pattern_tail = &(opt->pattern_list);
+               opt->regflags = REG_NEWLINE;
+               revs->header_filter = opt;
+       }
+
+       fldlen = strlen(field);
+       patlen = strlen(pattern);
+       pat = xmalloc(patlen + fldlen + 10);
+       prefix = ".*";
+       if (*pattern == '^') {
+               prefix = "";
+               pattern++;
+       }
+       sprintf(pat, "^%s %s%s", field, prefix, pattern);
+       append_grep_pattern(revs->header_filter, pat,
+                           "command line", 0, GREP_PATTERN);
+}
+
+static void add_message_grep(struct rev_info *revs, const char *pattern)
+{
+       if (!revs->message_filter) {
+               struct grep_opt *opt = xcalloc(1, sizeof(*opt));
+               opt->status_only = 1;
+               opt->pattern_tail = &(opt->pattern_list);
+               opt->regflags = REG_NEWLINE;
+               revs->message_filter = opt;
+       }
+       append_grep_pattern(revs->message_filter, pattern,
+                           "command line", 0, GREP_PATTERN);
+}
+
+static void add_ignore_packed(struct rev_info *revs, const char *name)
+{
+       int num = ++revs->num_ignore_packed;
+
+       revs->ignore_packed = xrealloc(revs->ignore_packed,
+                                      sizeof(const char **) * (num + 1));
+       revs->ignore_packed[num-1] = name;
+       revs->ignore_packed[num] = NULL;
+}
+
 /*
  * Parse revision information, filling in the "rev_info" structure,
  * and removing the used arguments from the argument list.
@@ -811,6 +864,14 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                        }
                        if (!strcmp(arg, "--unpacked")) {
                                revs->unpacked = 1;
+                               free(revs->ignore_packed);
+                               revs->ignore_packed = NULL;
+                               revs->num_ignore_packed = 0;
+                               continue;
+                       }
+                       if (!strncmp(arg, "--unpacked=", 11)) {
+                               revs->unpacked = 1;
+                               add_ignore_packed(revs, arg+11);
                                continue;
                        }
                        if (!strcmp(arg, "-r")) {
@@ -894,6 +955,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
                                revs->relative_date = 1;
                                continue;
                        }
+                       if (!strncmp(arg, "--author=", 9)) {
+                               add_header_grep(revs, "author", arg+9);
+                               continue;
+                       }
+                       if (!strncmp(arg, "--committer=", 12)) {
+                               add_header_grep(revs, "committer", arg+12);
+                               continue;
+                       }
+                       if (!strncmp(arg, "--grep=", 7)) {
+                               add_message_grep(revs, arg+7);
+                               continue;
+                       }
                        opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
                        if (opts > 0) {
                                revs->diff = 1;
@@ -954,6 +1027,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
        if (diff_setup_done(&revs->diffopt) < 0)
                die("diff_setup_done failed");
 
+       if (revs->header_filter)
+               compile_grep_patterns(revs->header_filter);
+       if (revs->message_filter)
+               compile_grep_patterns(revs->message_filter);
+
        return left;
 }
 
@@ -1026,6 +1104,38 @@ static void mark_boundary_to_show(struct commit *commit)
        }
 }
 
+static int commit_match(struct commit *commit, struct rev_info *opt)
+{
+       char *header, *message;
+       unsigned long header_len, message_len;
+
+       if (!opt->header_filter && !opt->message_filter)
+               return 1;
+
+       header = commit->buffer;
+       message = strstr(header, "\n\n");
+       if (message) {
+               message += 2;
+               header_len = message - header - 1;
+               message_len = strlen(message);
+       }
+       else {
+               header_len = strlen(header);
+               message = header;
+               message_len = 0;
+       }
+
+       if (opt->header_filter &&
+           !grep_buffer(opt->header_filter, NULL, header, header_len))
+               return 0;
+
+       if (opt->message_filter &&
+           !grep_buffer(opt->message_filter, NULL, message, message_len))
+               return 0;
+
+       return 1;
+}
+
 struct commit *get_revision(struct rev_info *revs)
 {
        struct commit_list *list = revs->commits;
@@ -1057,7 +1167,8 @@ struct commit *get_revision(struct rev_info *revs)
                 */
                if (!revs->limited) {
                        if ((revs->unpacked &&
-                            has_sha1_pack(commit->object.sha1)) ||
+                            has_sha1_pack(commit->object.sha1,
+                                          revs->ignore_packed)) ||
                            (revs->max_age != -1 &&
                             (commit->date < revs->max_age)))
                                continue;
@@ -1085,6 +1196,8 @@ struct commit *get_revision(struct rev_info *revs)
                if (revs->no_merges &&
                    commit->parents && commit->parents->next)
                        continue;
+               if (!commit_match(commit, revs))
+                       continue;
                if (revs->prune_fn && revs->dense) {
                        /* Commit without changes? */
                        if (!(commit->object.flags & TREECHANGE)) {