Skip to content

Commit

Permalink
log: --author-date-order
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Junio C Hamano committed Jun 11, 2013
1 parent da24b10 commit 81c6b38
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Documentation/rev-list-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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.

--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
Expand Down
74 changes: 74 additions & 0 deletions commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/* 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_;
Expand All @@ -531,26 +593,36 @@ 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 author_date_slab author_date;

if (!orig)
return;
*list = NULL;

init_indegree_slab(&indegree);
memset(&queue, '\0', sizeof(queue));

switch (sort_order) {
default: /* REV_SORT_IN_GRAPH_ORDER */
queue.compare = NULL;
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;
/* also record the author dates, if needed */
if (sort_order == REV_SORT_BY_AUTHOR_DATE)
record_author_date(&author_date, commit);
}

/* update the indegree */
Expand Down Expand Up @@ -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);
if (sort_order == REV_SORT_BY_AUTHOR_DATE)
clear_author_date_slab(&author_date);
}

/* merge-base stuff */
Expand Down
3 changes: 2 additions & 1 deletion commit.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
REV_SORT_BY_COMMIT_DATE
REV_SORT_BY_COMMIT_DATE,
REV_SORT_BY_AUTHOR_DATE
};

/*
Expand Down
3 changes: 3 additions & 0 deletions revision.c
Original file line number Diff line number Diff line change
Expand Up @@ -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, "--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]) {
Expand Down

0 comments on commit 81c6b38

Please sign in to comment.