remote-hg: force remote push
[gitweb.git] / revision.c
index 95d21e6472921ab993373ef1848357379440d46e..71e62d831229773a9af2c4a81d72be5b33d3c921 100644 (file)
@@ -13,6 +13,7 @@
 #include "decorate.h"
 #include "log-tree.h"
 #include "string-list.h"
+#include "mailmap.h"
 
 volatile show_early_output_fn_t show_early_output;
 
@@ -708,7 +709,7 @@ static int still_interesting(struct commit_list *src, unsigned long date, int sl
         * Does the destination list contain entries with a date
         * before the source list? Definitely _not_ done.
         */
-       if (date < src->item->date)
+       if (date <= src->item->date)
                return SLOP;
 
        /*
@@ -1969,6 +1970,22 @@ static struct merge_simplify_state *locate_simplify_state(struct rev_info *revs,
        return st;
 }
 
+static void remove_treesame_parents(struct commit *commit)
+{
+       struct commit_list **pp, *p;
+
+       pp = &commit->parents;
+       while ((p = *pp) != NULL) {
+               struct commit *parent = p->item;
+               if (parent->object.flags & TREESAME) {
+                       *pp = p->next;
+                       free(p);
+                       continue;
+               }
+               pp = &p->next;
+       }
+}
+
 static struct commit_list **simplify_one(struct rev_info *revs, struct commit *commit, struct commit_list **tail)
 {
        struct commit_list *p;
@@ -2021,10 +2038,18 @@ static struct commit_list **simplify_one(struct rev_info *revs, struct commit *c
                if (revs->first_parent_only)
                        break;
        }
-       if (!revs->first_parent_only)
-               cnt = remove_duplicate_parents(commit);
-       else
+
+       if (revs->first_parent_only) {
                cnt = 1;
+       } else {
+               /*
+                * A merge with a tree-same parent is useless
+                */
+               if (commit->parents && commit->parents->next)
+                       remove_treesame_parents(commit);
+
+               cnt = remove_duplicate_parents(commit);
+       }
 
        /*
         * It is possible that we are a merge and one side branch
@@ -2219,10 +2244,58 @@ static int rewrite_parents(struct rev_info *revs, struct commit *commit)
        return 0;
 }
 
+static int commit_rewrite_person(struct strbuf *buf, const char *what, struct string_list *mailmap)
+{
+       char *person, *endp;
+       size_t len, namelen, maillen;
+       const char *name;
+       const char *mail;
+       struct ident_split ident;
+
+       person = strstr(buf->buf, what);
+       if (!person)
+               return 0;
+
+       person += strlen(what);
+       endp = strchr(person, '\n');
+       if (!endp)
+               return 0;
+
+       len = endp - person;
+
+       if (split_ident_line(&ident, person, len))
+               return 0;
+
+       mail = ident.mail_begin;
+       maillen = ident.mail_end - ident.mail_begin;
+       name = ident.name_begin;
+       namelen = ident.name_end - ident.name_begin;
+
+       if (map_user(mailmap, &mail, &maillen, &name, &namelen)) {
+               struct strbuf namemail = STRBUF_INIT;
+
+               strbuf_addf(&namemail, "%.*s <%.*s>",
+                           (int)namelen, name, (int)maillen, mail);
+
+               strbuf_splice(buf, ident.name_begin - buf->buf,
+                             ident.mail_end - ident.name_begin + 1,
+                             namemail.buf, namemail.len);
+
+               strbuf_release(&namemail);
+
+               return 1;
+       }
+
+       return 0;
+}
+
 static int commit_match(struct commit *commit, struct rev_info *opt)
 {
        int retval;
+       const char *encoding;
+       char *message;
        struct strbuf buf = STRBUF_INIT;
+
        if (!opt->grep_filter.pattern_list && !opt->grep_filter.header_list)
                return 1;
 
@@ -2233,25 +2306,43 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
                strbuf_addch(&buf, '\n');
        }
 
+       /*
+        * We grep in the user's output encoding, under the assumption that it
+        * is the encoding they are most likely to write their grep pattern
+        * for. In addition, it means we will match the "notes" encoding below,
+        * so we will not end up with a buffer that has two different encodings
+        * in it.
+        */
+       encoding = get_log_output_encoding();
+       message = logmsg_reencode(commit, encoding);
+
        /* Copy the commit to temporary if we are using "fake" headers */
        if (buf.len)
-               strbuf_addstr(&buf, commit->buffer);
+               strbuf_addstr(&buf, message);
+
+       if (opt->grep_filter.header_list && opt->mailmap) {
+               if (!buf.len)
+                       strbuf_addstr(&buf, message);
+
+               commit_rewrite_person(&buf, "\nauthor ", opt->mailmap);
+               commit_rewrite_person(&buf, "\ncommitter ", opt->mailmap);
+       }
 
        /* Append "fake" message parts as needed */
        if (opt->show_notes) {
                if (!buf.len)
-                       strbuf_addstr(&buf, commit->buffer);
-               format_display_notes(commit->object.sha1, &buf,
-                                    get_log_output_encoding(), 1);
+                       strbuf_addstr(&buf, message);
+               format_display_notes(commit->object.sha1, &buf, encoding, 1);
        }
 
-       /* Find either in the commit object, or in the temporary */
+       /* Find either in the original commit message, or in the temporary */
        if (buf.len)
                retval = grep_buffer(&opt->grep_filter, buf.buf, buf.len);
        else
                retval = grep_buffer(&opt->grep_filter,
-                                    commit->buffer, strlen(commit->buffer));
+                                    message, strlen(message));
        strbuf_release(&buf);
+       logmsg_free(message, commit);
        return retval;
 }