log: --author-date-order
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>
Junio C Hamano committed
Jun 7, 2013 at 10:35 UTC
81c6b38b67019eff48e8e5c324bb77f6c796c0b5
4 files changed
+83
-1
Documentation/rev-list-options.txt
+4
@@ -617,6 +617,10 @@ By default, the commits are shown in reverse chronological order.
617
Show no parents before all of its children are shown, but
618
otherwise show commits in the commit timestamp order.
619
620
+--author-date-order::
621
+ Show no parents before all of its children are shown, but
622
+ otherwise show commits in the author timestamp order.
623
+
624
--topo-order::
625
Show no parents before all of its children are shown, and
626
avoid showing commits on multiple lines of history
commit.c
+74
@@ -510,6 +510,68 @@ struct commit *pop_commit(struct commit_list **stack)
510
/* count number of children that have not been emitted */
511
define_commit_slab(indegree_slab, int);
512
513
+/* record author-date for each commit object */
514
+define_commit_slab(author_date_slab, unsigned long);
515
+
516
+static void record_author_date(struct author_date_slab *author_date,
517
+ struct commit *commit)
518
+{
519
+ const char *buf, *line_end;
520
+ char *buffer = NULL;
521
+ struct ident_split ident;
522
+ char *date_end;
523
+ unsigned long date;
524
+
525
+ if (!commit->buffer) {
526
+ unsigned long size;
527
+ enum object_type type;
528
+ buffer = read_sha1_file(commit->object.sha1, &type, &size);
529
+ if (!buffer)
530
+ return;
531
+ }
532
+
533
+ for (buf = commit->buffer ? commit->buffer : buffer;
534
+ buf;
535
+ buf = line_end + 1) {
536
+ line_end = strchrnul(buf, '\n');
537
+ if (prefixcmp(buf, "author ")) {
538
+ if (!line_end[0] || line_end[1] == '\n')
539
+ return; /* end of header */
540
+ continue;
541
+ }
542
+ if (split_ident_line(&ident,
543
+ buf + strlen("author "),
544
+ line_end - (buf + strlen("author "))) ||
545
+ !ident.date_begin || !ident.date_end)
546
+ goto fail_exit; /* malformed "author" line */
547
+ break;
548
+ }
549
+
550
+ date = strtoul(ident.date_begin, &date_end, 10);
551
+ if (date_end != ident.date_end)
552
+ goto fail_exit; /* malformed date */
553
+ *(author_date_slab_at(author_date, commit)) = date;
554
+
555
+fail_exit:
556
+ free(buffer);
557
+}
558
+
559
+static int compare_commits_by_author_date(const void *a_, const void *b_,
560
+ void *cb_data)
561
+{
562
+ const struct commit *a = a_, *b = b_;
563
+ struct author_date_slab *author_date = cb_data;
564
+ unsigned long a_date = *(author_date_slab_at(author_date, a));
565
+ unsigned long b_date = *(author_date_slab_at(author_date, b));
566
+
567
+ /* newer commits with larger date first */
568
+ if (a_date < b_date)
569
+ return 1;
570
+ else if (a_date > b_date)
571
+ return -1;
572
+ return 0;
573
+}
574
+
575
static int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
576
{
577
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
593
struct indegree_slab indegree;
594
struct prio_queue queue;
595
struct commit *commit;
596
+ struct author_date_slab author_date;
597
598
if (!orig)
599
return;
@@ -538,6 +601,7 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
601
602
init_indegree_slab(&indegree);
603
memset(&queue, '\0', sizeof(queue));
604
+
605
switch (sort_order) {
606
default: /* REV_SORT_IN_GRAPH_ORDER */
607
queue.compare = NULL;
@@ -545,12 +609,20 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
609
case REV_SORT_BY_COMMIT_DATE:
610
queue.compare = compare_commits_by_commit_date;
611
break;
612
+ case REV_SORT_BY_AUTHOR_DATE:
613
+ init_author_date_slab(&author_date);
614
+ queue.compare = compare_commits_by_author_date;
615
+ queue.cb_data = &author_date;
616
+ break;
617
}
618
619
/* Mark them and clear the indegree */
620
for (next = orig; next; next = next->next) {
621
struct commit *commit = next->item;
622
*(indegree_slab_at(&indegree, commit)) = 1;
623
+ /* also record the author dates, if needed */
624
+ if (sort_order == REV_SORT_BY_AUTHOR_DATE)
625
+ record_author_date(&author_date, commit);
626
}
627
628
/* update the indegree */
@@ -621,6 +693,8 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
693
694
clear_indegree_slab(&indegree);
695
clear_prio_queue(&queue);
696
+ if (sort_order == REV_SORT_BY_AUTHOR_DATE)
697
+ clear_author_date_slab(&author_date);
698
}
699
700
/* merge-base stuff */
commit.h
+2
-1
@@ -142,7 +142,8 @@ void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
142
143
enum rev_sort_order {
144
REV_SORT_IN_GRAPH_ORDER = 0,
145
- REV_SORT_BY_COMMIT_DATE
145
+ REV_SORT_BY_COMMIT_DATE,
146
+ REV_SORT_BY_AUTHOR_DATE
147
};
148
149
/*
revision.c
+3
@@ -1393,6 +1393,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
1393
} else if (!strcmp(arg, "--date-order")) {
1394
revs->sort_order = REV_SORT_BY_COMMIT_DATE;
1395
revs->topo_order = 1;
1396
+ } else if (!strcmp(arg, "--author-date-order")) {
1397
+ revs->sort_order = REV_SORT_BY_AUTHOR_DATE;
1398
+ revs->topo_order = 1;
1399
} else if (!prefixcmp(arg, "--early-output")) {
1400
int count = 100;
1401
switch (arg[14]) {