Skip to content

Commit 81c6b38

Browse files
committed
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 <[email protected]>
1 parent da24b10 commit 81c6b38

File tree

4 files changed

+83
-1
lines changed

4 files changed

+83
-1
lines changed

Documentation/rev-list-options.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,10 @@ By default, the commits are shown in reverse chronological order.
617617
Show no parents before all of its children are shown, but
618618
otherwise show commits in the commit timestamp order.
619619

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+
620624
--topo-order::
621625
Show no parents before all of its children are shown, and
622626
avoid showing commits on multiple lines of history

commit.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,68 @@ struct commit *pop_commit(struct commit_list **stack)
510510
/* count number of children that have not been emitted */
511511
define_commit_slab(indegree_slab, int);
512512

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+
513575
static int compare_commits_by_commit_date(const void *a_, const void *b_, void *unused)
514576
{
515577
const struct commit *a = a_, *b = b_;
@@ -531,26 +593,36 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
531593
struct indegree_slab indegree;
532594
struct prio_queue queue;
533595
struct commit *commit;
596+
struct author_date_slab author_date;
534597

535598
if (!orig)
536599
return;
537600
*list = NULL;
538601

539602
init_indegree_slab(&indegree);
540603
memset(&queue, '\0', sizeof(queue));
604+
541605
switch (sort_order) {
542606
default: /* REV_SORT_IN_GRAPH_ORDER */
543607
queue.compare = NULL;
544608
break;
545609
case REV_SORT_BY_COMMIT_DATE:
546610
queue.compare = compare_commits_by_commit_date;
547611
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;
548617
}
549618

550619
/* Mark them and clear the indegree */
551620
for (next = orig; next; next = next->next) {
552621
struct commit *commit = next->item;
553622
*(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);
554626
}
555627

556628
/* update the indegree */
@@ -621,6 +693,8 @@ void sort_in_topological_order(struct commit_list **list, enum rev_sort_order so
621693

622694
clear_indegree_slab(&indegree);
623695
clear_prio_queue(&queue);
696+
if (sort_order == REV_SORT_BY_AUTHOR_DATE)
697+
clear_author_date_slab(&author_date);
624698
}
625699

626700
/* merge-base stuff */

commit.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,8 @@ void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
142142

143143
enum rev_sort_order {
144144
REV_SORT_IN_GRAPH_ORDER = 0,
145-
REV_SORT_BY_COMMIT_DATE
145+
REV_SORT_BY_COMMIT_DATE,
146+
REV_SORT_BY_AUTHOR_DATE
146147
};
147148

148149
/*

revision.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1393,6 +1393,9 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
13931393
} else if (!strcmp(arg, "--date-order")) {
13941394
revs->sort_order = REV_SORT_BY_COMMIT_DATE;
13951395
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;
13961399
} else if (!prefixcmp(arg, "--early-output")) {
13971400
int count = 100;
13981401
switch (arg[14]) {

0 commit comments

Comments
 (0)