log: --author-date-order
authorJunio C Hamano <gitster@pobox.com>
Fri, 7 Jun 2013 17:35:54 +0000 (10:35 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 11 Jun 2013 22:15:21 +0000 (15:15 -0700)
Sometimes people would want to view the commits in parallel
histories in the order of author dates, not committer dates.

Teach "topo-order" sort machinery to do so, using a commit-info slab
to record the author dates of each commit, and prio-queue to sort
them.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/rev-list-options.txt
commit.c
commit.h
revision.c
index 3bdbf5e856b68692745a91304d80b09186d487b4..8302402c7db8dc585ce3865fb55b36e1f8d8ed07 100644 (file)
@@ -617,6 +617,10 @@ By default, the commits are shown in reverse chronological order.
        Show no parents before all of its children are shown, but
        otherwise show commits in the commit timestamp order.
 
        Show no parents before all of its children are shown, but
        otherwise show commits in the commit timestamp order.
 
+--author-date-order::
+       Show no parents before all of its children are shown, but
+       otherwise show commits in the author timestamp order.
+
 --topo-order::
        Show no parents before all of its children are shown, and
        avoid showing commits on multiple lines of history
 --topo-order::
        Show no parents before all of its children are shown, and
        avoid showing commits on multiple lines of history
index 8b84ebf2b70561dc4b3bd4a13afa4fcfcc5c5aea..076c1fa606b3541d34b45a7cf67be1eb4bae9626 100644 (file)
--- a/commit.c
+++ b/commit.c
@@ -510,6 +510,68 @@ struct commit *pop_commit(struct commit_list **stack)
 /* count number of children that have not been emitted */
 define_commit_slab(indegree_slab, int);
 
 /* count number of children that have not been emitted */
 define_commit_slab(indegree_slab, int);
 
+/* record author-date for each commit object */
+define_commit_slab(author_date_slab, unsigned long);
+
+static void record_author_date(struct author_date_slab *author_date,
+                              struct commit *commit)
+{
+       const char *buf, *line_end;
+       char *buffer = NULL;
+       struct ident_split ident;
+       char *date_end;
+       unsigned long date;
+
+       if (!commit->buffer) {
+               unsigned long size;
+               enum object_type type;
+               buffer = read_sha1_file(commit->object.sha1, &type, &size);
+               if (!buffer)
+                       return;
+       }
+
+       for (buf = commit->buffer ? commit->buffer : buffer;
+            buf;
+            buf = line_end + 1) {
+               line_end = strchrnul(buf, '\n');
+               if (prefixcmp(buf, "author ")) {
+                       if (!line_end[0] || line_end[1] == '\n')
+                               return; /* end of header */
+                       continue;
+               }
+               if (split_ident_line(&ident,
+                                    buf + strlen("author "),
+                                    line_end - (buf + strlen("author "))) ||
+                   !ident.date_begin || !ident.date_end)
+                       goto fail_exit; /* malformed "author" line */
+               break;
+       }
+
+       date = strtoul(ident.date_begin, &date_end, 10);
+       if (date_end != ident.date_end)
+               goto fail_exit; /* malformed date */
+       *(author_date_slab_at(author_date, commit)) = date;
+
+fail_exit:
+       free(buffer);
+}
+
+static int compare_commits_by_author_date(const void *a_, const void *b_,
+                                         void *cb_data)
+{
+       const struct commit *a = a_, *b = b_;
+       struct author_date_slab *author_date = cb_data;
+       unsigned long a_date = *(author_date_slab_at(author_date, a));
+       unsigned long b_date = *(author_date_slab_at(author_date, b));
+
+       /* newer commits with larger date first */
+       if (a_date < b_date)
+               return 1;
+       else if (a_date > b_date)
+               return -1;
+       return 0;
+}
+
 static int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
 {
        const struct commit *a = a_, *b = b_;
 static int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
 {
        const struct commit *a = a_, *b = b_;
@@ -531,6 +593,7 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
        struct indegree_slab indegree;
        struct prio_queue queue;
        struct commit *commit;
        struct indegree_slab indegree;
        struct prio_queue queue;
        struct commit *commit;
+       struct author_date_slab author_date;
 
        if (!orig)
                return;
 
        if (!orig)
                return;
@@ -538,6 +601,7 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
 
        init_indegree_slab(&indegree);
        memset(&queue, '\0', sizeof(queue));
 
        init_indegree_slab(&indegree);
        memset(&queue, '\0', sizeof(queue));
+
        switch (sort_order) {
        default: /* REV_SORT_IN_GRAPH_ORDER */
                queue.compare = NULL;
        switch (sort_order) {
        default: /* REV_SORT_IN_GRAPH_ORDER */
                queue.compare = NULL;
@@ -545,12 +609,20 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
        case REV_SORT_BY_COMMIT_DATE:
                queue.compare = compare_commits_by_commit_date;
                break;
        case REV_SORT_BY_COMMIT_DATE:
                queue.compare = compare_commits_by_commit_date;
                break;
+       case REV_SORT_BY_AUTHOR_DATE:
+               init_author_date_slab(&author_date);
+               queue.compare = compare_commits_by_author_date;
+               queue.cb_data = &author_date;
+               break;
        }
 
        /* Mark them and clear the indegree */
        for (next = orig; next; next = next->next) {
                struct commit *commit = next->item;
                *(indegree_slab_at(&indegree, commit)) = 1;
        }
 
        /* Mark them and clear the indegree */
        for (next = orig; next; next = next->next) {
                struct commit *commit = next->item;
                *(indegree_slab_at(&indegree, commit)) = 1;
+               /* also record the author dates, if needed */
+               if (sort_order == REV_SORT_BY_AUTHOR_DATE)
+                       record_author_date(&author_date, commit);
        }
 
        /* update the indegree */
        }
 
        /* update the indegree */
@@ -621,6 +693,8 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
 
        clear_indegree_slab(&indegree);
        clear_prio_queue(&queue);
 
        clear_indegree_slab(&indegree);
        clear_prio_queue(&queue);
+       if (sort_order == REV_SORT_BY_AUTHOR_DATE)
+               clear_author_date_slab(&author_date);
 }
 
 /* merge-base stuff */
 }
 
 /* merge-base stuff */
index 247e474e447aac63bb8bcd7563b1446b8a7fc654..e43dfd01823481a23b542e0a4ab1a5df8b493e70 100644 (file)
--- a/commit.h
+++ b/commit.h
@@ -142,7 +142,8 @@ void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
 
 enum rev_sort_order {
        REV_SORT_IN_GRAPH_ORDER = 0,
 
 enum rev_sort_order {
        REV_SORT_IN_GRAPH_ORDER = 0,
-       REV_SORT_BY_COMMIT_DATE
+       REV_SORT_BY_COMMIT_DATE,
+       REV_SORT_BY_AUTHOR_DATE
 };
 
 /*
 };
 
 /*
index 966ebbc542d52f12fc6d044f85e8ac34a25a1a2a..12d9b64b3aeb86818352c13e35588e6c673a1ff2 100644 (file)
@@ -1393,6 +1393,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
        } else if (!strcmp(arg, "--date-order")) {
                revs->sort_order = REV_SORT_BY_COMMIT_DATE;
                revs->topo_order = 1;
        } else if (!strcmp(arg, "--date-order")) {
                revs->sort_order = REV_SORT_BY_COMMIT_DATE;
                revs->topo_order = 1;
+       } else if (!strcmp(arg, "--author-date-order")) {
+               revs->sort_order = REV_SORT_BY_AUTHOR_DATE;
+               revs->topo_order = 1;
        } else if (!prefixcmp(arg, "--early-output")) {
                int count = 100;
                switch (arg[14]) {
        } else if (!prefixcmp(arg, "--early-output")) {
                int count = 100;
                switch (arg[14]) {