mirror of
https://github.com/git/git
synced 2024-08-25 02:35:46 +00:00
Merge branch 'jc/topo-author-date-sort'
"git log" learned the "--author-date-order" option, with which the output is topologically sorted and commits in parallel histories are shown intermixed together based on the author timestamp. * jc/topo-author-date-sort: t6003: add --author-date-order test topology tests: teach a helper to set author dates as well t6003: add --date-order test topology tests: teach a helper to take abbreviated timestamps t/lib-t6000: style fixes log: --author-date-order sort-in-topological-order: use prio-queue prio-queue: priority queue of pointers to structs toposort: rename "lifo" field
This commit is contained in:
commit
534f0e0996
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -191,6 +191,7 @@
|
||||||
/test-mktemp
|
/test-mktemp
|
||||||
/test-parse-options
|
/test-parse-options
|
||||||
/test-path-utils
|
/test-path-utils
|
||||||
|
/test-prio-queue
|
||||||
/test-read-cache
|
/test-read-cache
|
||||||
/test-regex
|
/test-regex
|
||||||
/test-revision-walking
|
/test-revision-walking
|
||||||
|
|
|
@ -625,6 +625,10 @@ By default, the commits are shown in reverse chronological order.
|
||||||
Show no parents before all of its children are shown, but
|
Show no parents before all of its children are shown, but
|
||||||
otherwise show commits in the commit timestamp order.
|
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::
|
--topo-order::
|
||||||
Show no parents before all of its children are shown, and
|
Show no parents before all of its children are shown, and
|
||||||
avoid showing commits on multiple lines of history
|
avoid showing commits on multiple lines of history
|
||||||
|
|
3
Makefile
3
Makefile
|
@ -569,6 +569,7 @@ TEST_PROGRAMS_NEED_X += test-mergesort
|
||||||
TEST_PROGRAMS_NEED_X += test-mktemp
|
TEST_PROGRAMS_NEED_X += test-mktemp
|
||||||
TEST_PROGRAMS_NEED_X += test-parse-options
|
TEST_PROGRAMS_NEED_X += test-parse-options
|
||||||
TEST_PROGRAMS_NEED_X += test-path-utils
|
TEST_PROGRAMS_NEED_X += test-path-utils
|
||||||
|
TEST_PROGRAMS_NEED_X += test-prio-queue
|
||||||
TEST_PROGRAMS_NEED_X += test-read-cache
|
TEST_PROGRAMS_NEED_X += test-read-cache
|
||||||
TEST_PROGRAMS_NEED_X += test-regex
|
TEST_PROGRAMS_NEED_X += test-regex
|
||||||
TEST_PROGRAMS_NEED_X += test-revision-walking
|
TEST_PROGRAMS_NEED_X += test-revision-walking
|
||||||
|
@ -705,6 +706,7 @@ LIB_H += parse-options.h
|
||||||
LIB_H += patch-ids.h
|
LIB_H += patch-ids.h
|
||||||
LIB_H += pathspec.h
|
LIB_H += pathspec.h
|
||||||
LIB_H += pkt-line.h
|
LIB_H += pkt-line.h
|
||||||
|
LIB_H += prio-queue.h
|
||||||
LIB_H += progress.h
|
LIB_H += progress.h
|
||||||
LIB_H += prompt.h
|
LIB_H += prompt.h
|
||||||
LIB_H += quote.h
|
LIB_H += quote.h
|
||||||
|
@ -846,6 +848,7 @@ LIB_OBJS += pathspec.o
|
||||||
LIB_OBJS += pkt-line.o
|
LIB_OBJS += pkt-line.o
|
||||||
LIB_OBJS += preload-index.o
|
LIB_OBJS += preload-index.o
|
||||||
LIB_OBJS += pretty.o
|
LIB_OBJS += pretty.o
|
||||||
|
LIB_OBJS += prio-queue.o
|
||||||
LIB_OBJS += progress.o
|
LIB_OBJS += progress.o
|
||||||
LIB_OBJS += prompt.o
|
LIB_OBJS += prompt.o
|
||||||
LIB_OBJS += quote.o
|
LIB_OBJS += quote.o
|
||||||
|
|
|
@ -237,7 +237,7 @@ static void log_show_early(struct rev_info *revs, struct commit_list *list)
|
||||||
int i = revs->early_output;
|
int i = revs->early_output;
|
||||||
int show_header = 1;
|
int show_header = 1;
|
||||||
|
|
||||||
sort_in_topological_order(&list, revs->lifo);
|
sort_in_topological_order(&list, revs->sort_order);
|
||||||
while (list && i) {
|
while (list && i) {
|
||||||
struct commit *commit = list->item;
|
struct commit *commit = list->item;
|
||||||
switch (simplify_commit(revs, commit)) {
|
switch (simplify_commit(revs, commit)) {
|
||||||
|
|
|
@ -630,7 +630,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||||
int num_rev, i, extra = 0;
|
int num_rev, i, extra = 0;
|
||||||
int all_heads = 0, all_remotes = 0;
|
int all_heads = 0, all_remotes = 0;
|
||||||
int all_mask, all_revs;
|
int all_mask, all_revs;
|
||||||
int lifo = 1;
|
enum rev_sort_order sort_order = REV_SORT_IN_GRAPH_ORDER;
|
||||||
char head[128];
|
char head[128];
|
||||||
const char *head_p;
|
const char *head_p;
|
||||||
int head_len;
|
int head_len;
|
||||||
|
@ -665,15 +665,17 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||||
N_("show possible merge bases")),
|
N_("show possible merge bases")),
|
||||||
OPT_BOOLEAN(0, "independent", &independent,
|
OPT_BOOLEAN(0, "independent", &independent,
|
||||||
N_("show refs unreachable from any other ref")),
|
N_("show refs unreachable from any other ref")),
|
||||||
OPT_BOOLEAN(0, "topo-order", &lifo,
|
OPT_SET_INT(0, "topo-order", &sort_order,
|
||||||
N_("show commits in topological order")),
|
N_("show commits in topological order"),
|
||||||
|
REV_SORT_IN_GRAPH_ORDER),
|
||||||
OPT_BOOLEAN(0, "topics", &topics,
|
OPT_BOOLEAN(0, "topics", &topics,
|
||||||
N_("show only commits not on the first branch")),
|
N_("show only commits not on the first branch")),
|
||||||
OPT_SET_INT(0, "sparse", &dense,
|
OPT_SET_INT(0, "sparse", &dense,
|
||||||
N_("show merges reachable from only one tip"), 0),
|
N_("show merges reachable from only one tip"), 0),
|
||||||
OPT_SET_INT(0, "date-order", &lifo,
|
OPT_SET_INT(0, "date-order", &sort_order,
|
||||||
N_("show commits where no parent comes before its "
|
N_("show commits where no parent comes before its "
|
||||||
"children"), 0),
|
"children"),
|
||||||
|
REV_SORT_BY_COMMIT_DATE),
|
||||||
{ OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
|
{ OPTION_CALLBACK, 'g', "reflog", &reflog_base, N_("<n>[,<base>]"),
|
||||||
N_("show <n> most recent ref-log entries starting at "
|
N_("show <n> most recent ref-log entries starting at "
|
||||||
"base"),
|
"base"),
|
||||||
|
@ -900,7 +902,7 @@ int cmd_show_branch(int ac, const char **av, const char *prefix)
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
||||||
/* Sort topologically */
|
/* Sort topologically */
|
||||||
sort_in_topological_order(&seen, lifo);
|
sort_in_topological_order(&seen, sort_order);
|
||||||
|
|
||||||
/* Give names to commits */
|
/* Give names to commits */
|
||||||
if (!sha1_name && !no_name)
|
if (!sha1_name && !no_name)
|
||||||
|
|
145
commit.c
145
commit.c
|
@ -9,6 +9,7 @@
|
||||||
#include "gpg-interface.h"
|
#include "gpg-interface.h"
|
||||||
#include "mergesort.h"
|
#include "mergesort.h"
|
||||||
#include "commit-slab.h"
|
#include "commit-slab.h"
|
||||||
|
#include "prio-queue.h"
|
||||||
|
|
||||||
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
|
static struct commit_extra_header *read_commit_extra_header_lines(const char *buf, size_t len, const char **);
|
||||||
|
|
||||||
|
@ -518,31 +519,124 @@ struct commit *pop_commit(struct commit_list **stack)
|
||||||
/* count number of children that have not been emitted */
|
/* count number of children that have not been emitted */
|
||||||
define_commit_slab(indegree_slab, int);
|
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_;
|
||||||
|
/* newer commits with larger date first */
|
||||||
|
if (a->date < b->date)
|
||||||
|
return 1;
|
||||||
|
else if (a->date > b->date)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Performs an in-place topological sort on the list supplied.
|
* Performs an in-place topological sort on the list supplied.
|
||||||
*/
|
*/
|
||||||
void sort_in_topological_order(struct commit_list ** list, int lifo)
|
void sort_in_topological_order(struct commit_list **list, enum rev_sort_order sort_order)
|
||||||
{
|
{
|
||||||
struct commit_list *next, *orig = *list;
|
struct commit_list *next, *orig = *list;
|
||||||
struct commit_list *work, **insert;
|
|
||||||
struct commit_list **pptr;
|
struct commit_list **pptr;
|
||||||
struct indegree_slab indegree;
|
struct indegree_slab indegree;
|
||||||
|
struct prio_queue queue;
|
||||||
|
struct commit *commit;
|
||||||
|
struct author_date_slab author_date;
|
||||||
|
|
||||||
if (!orig)
|
if (!orig)
|
||||||
return;
|
return;
|
||||||
*list = NULL;
|
*list = NULL;
|
||||||
|
|
||||||
init_indegree_slab(&indegree);
|
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 */
|
/* Mark them and clear the indegree */
|
||||||
for (next = orig; next; next = next->next) {
|
for (next = orig; next; next = next->next) {
|
||||||
struct commit *commit = next->item;
|
struct commit *commit = next->item;
|
||||||
*(indegree_slab_at(&indegree, commit)) = 1;
|
*(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 */
|
||||||
for (next = orig; next; next = next->next) {
|
for (next = orig; next; next = next->next) {
|
||||||
struct commit_list * parents = next->item->parents;
|
struct commit_list *parents = next->item->parents;
|
||||||
while (parents) {
|
while (parents) {
|
||||||
struct commit *parent = parents->item;
|
struct commit *parent = parents->item;
|
||||||
int *pi = indegree_slab_at(&indegree, parent);
|
int *pi = indegree_slab_at(&indegree, parent);
|
||||||
|
@ -560,30 +654,28 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
|
||||||
*
|
*
|
||||||
* the tips serve as a starting set for the work queue.
|
* the tips serve as a starting set for the work queue.
|
||||||
*/
|
*/
|
||||||
work = NULL;
|
|
||||||
insert = &work;
|
|
||||||
for (next = orig; next; next = next->next) {
|
for (next = orig; next; next = next->next) {
|
||||||
struct commit *commit = next->item;
|
struct commit *commit = next->item;
|
||||||
|
|
||||||
if (*(indegree_slab_at(&indegree, commit)) == 1)
|
if (*(indegree_slab_at(&indegree, commit)) == 1)
|
||||||
insert = &commit_list_insert(commit, insert)->next;
|
prio_queue_put(&queue, commit);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* process the list in topological order */
|
/*
|
||||||
if (!lifo)
|
* This is unfortunate; the initial tips need to be shown
|
||||||
commit_list_sort_by_date(&work);
|
* in the order given from the revision traversal machinery.
|
||||||
|
*/
|
||||||
|
if (sort_order == REV_SORT_IN_GRAPH_ORDER)
|
||||||
|
prio_queue_reverse(&queue);
|
||||||
|
|
||||||
|
/* We no longer need the commit list */
|
||||||
|
free_commit_list(orig);
|
||||||
|
|
||||||
pptr = list;
|
pptr = list;
|
||||||
*list = NULL;
|
*list = NULL;
|
||||||
while (work) {
|
while ((commit = prio_queue_get(&queue)) != NULL) {
|
||||||
struct commit *commit;
|
struct commit_list *parents;
|
||||||
struct commit_list *parents, *work_item;
|
|
||||||
|
|
||||||
work_item = work;
|
|
||||||
work = work_item->next;
|
|
||||||
work_item->next = NULL;
|
|
||||||
|
|
||||||
commit = work_item->item;
|
|
||||||
for (parents = commit->parents; parents ; parents = parents->next) {
|
for (parents = commit->parents; parents ; parents = parents->next) {
|
||||||
struct commit *parent = parents->item;
|
struct commit *parent = parents->item;
|
||||||
int *pi = indegree_slab_at(&indegree, parent);
|
int *pi = indegree_slab_at(&indegree, parent);
|
||||||
|
@ -596,23 +688,22 @@ void sort_in_topological_order(struct commit_list ** list, int lifo)
|
||||||
* when all their children have been emitted thereby
|
* when all their children have been emitted thereby
|
||||||
* guaranteeing topological order.
|
* guaranteeing topological order.
|
||||||
*/
|
*/
|
||||||
if (--(*pi) == 1) {
|
if (--(*pi) == 1)
|
||||||
if (!lifo)
|
prio_queue_put(&queue, parent);
|
||||||
commit_list_insert_by_date(parent, &work);
|
|
||||||
else
|
|
||||||
commit_list_insert(parent, &work);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
* work_item is a commit all of whose children
|
* all children of commit have already been
|
||||||
* have already been emitted. we can emit it now.
|
* emitted. we can emit it now.
|
||||||
*/
|
*/
|
||||||
*(indegree_slab_at(&indegree, commit)) = 0;
|
*(indegree_slab_at(&indegree, commit)) = 0;
|
||||||
*pptr = work_item;
|
|
||||||
pptr = &work_item->next;
|
pptr = &commit_list_insert(commit, pptr)->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
clear_indegree_slab(&indegree);
|
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 */
|
||||||
|
|
15
commit.h
15
commit.h
|
@ -142,15 +142,24 @@ void clear_commit_marks(struct commit *commit, unsigned int mark);
|
||||||
void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark);
|
void clear_commit_marks_many(int nr, struct commit **commit, unsigned int mark);
|
||||||
void clear_commit_marks_for_object_array(struct object_array *a, unsigned mark);
|
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_AUTHOR_DATE
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Performs an in-place topological sort of list supplied.
|
* Performs an in-place topological sort of list supplied.
|
||||||
*
|
*
|
||||||
* invariant of resulting list is:
|
* invariant of resulting list is:
|
||||||
* a reachable from b => ord(b) < ord(a)
|
* a reachable from b => ord(b) < ord(a)
|
||||||
* in addition, when lifo == 0, commits on parallel tracks are
|
* sort_order further specifies:
|
||||||
* sorted in the dates order.
|
* REV_SORT_IN_GRAPH_ORDER: try to show a commit on a single-parent
|
||||||
|
* chain together.
|
||||||
|
* REV_SORT_BY_COMMIT_DATE: show eligible commits in committer-date order.
|
||||||
*/
|
*/
|
||||||
void sort_in_topological_order(struct commit_list ** list, int lifo);
|
void sort_in_topological_order(struct commit_list **, enum rev_sort_order);
|
||||||
|
|
||||||
struct commit_graft {
|
struct commit_graft {
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
|
|
84
prio-queue.c
Normal file
84
prio-queue.c
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#include "cache.h"
|
||||||
|
#include "commit.h"
|
||||||
|
#include "prio-queue.h"
|
||||||
|
|
||||||
|
void prio_queue_reverse(struct prio_queue *queue)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
if (queue->compare != NULL)
|
||||||
|
die("BUG: prio_queue_reverse() on non-LIFO queue");
|
||||||
|
for (i = 0; i <= (j = (queue->nr - 1) - i); i++) {
|
||||||
|
struct commit *swap = queue->array[i];
|
||||||
|
queue->array[i] = queue->array[j];
|
||||||
|
queue->array[j] = swap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_prio_queue(struct prio_queue *queue)
|
||||||
|
{
|
||||||
|
free(queue->array);
|
||||||
|
queue->nr = 0;
|
||||||
|
queue->alloc = 0;
|
||||||
|
queue->array = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void prio_queue_put(struct prio_queue *queue, void *thing)
|
||||||
|
{
|
||||||
|
prio_queue_compare_fn compare = queue->compare;
|
||||||
|
int ix, parent;
|
||||||
|
|
||||||
|
/* Append at the end */
|
||||||
|
ALLOC_GROW(queue->array, queue->nr + 1, queue->alloc);
|
||||||
|
queue->array[queue->nr++] = thing;
|
||||||
|
if (!compare)
|
||||||
|
return; /* LIFO */
|
||||||
|
|
||||||
|
/* Bubble up the new one */
|
||||||
|
for (ix = queue->nr - 1; ix; ix = parent) {
|
||||||
|
parent = (ix - 1) / 2;
|
||||||
|
if (compare(queue->array[parent], queue->array[ix],
|
||||||
|
queue->cb_data) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
thing = queue->array[parent];
|
||||||
|
queue->array[parent] = queue->array[ix];
|
||||||
|
queue->array[ix] = thing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *prio_queue_get(struct prio_queue *queue)
|
||||||
|
{
|
||||||
|
void *result, *swap;
|
||||||
|
int ix, child;
|
||||||
|
prio_queue_compare_fn compare = queue->compare;
|
||||||
|
|
||||||
|
if (!queue->nr)
|
||||||
|
return NULL;
|
||||||
|
if (!compare)
|
||||||
|
return queue->array[--queue->nr]; /* LIFO */
|
||||||
|
|
||||||
|
result = queue->array[0];
|
||||||
|
if (!--queue->nr)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
queue->array[0] = queue->array[queue->nr];
|
||||||
|
|
||||||
|
/* Push down the one at the root */
|
||||||
|
for (ix = 0; ix * 2 + 1 < queue->nr; ix = child) {
|
||||||
|
child = ix * 2 + 1; /* left */
|
||||||
|
if ((child + 1 < queue->nr) &&
|
||||||
|
(compare(queue->array[child], queue->array[child + 1],
|
||||||
|
queue->cb_data) >= 0))
|
||||||
|
child++; /* use right child */
|
||||||
|
|
||||||
|
if (compare(queue->array[ix], queue->array[child],
|
||||||
|
queue->cb_data) <= 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
swap = queue->array[child];
|
||||||
|
queue->array[child] = queue->array[ix];
|
||||||
|
queue->array[ix] = swap;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
48
prio-queue.h
Normal file
48
prio-queue.h
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#ifndef PRIO_QUEUE_H
|
||||||
|
#define PRIO_QUEUE_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A priority queue implementation, primarily for keeping track of
|
||||||
|
* commits in the 'date-order' so that we process them from new to old
|
||||||
|
* as they are discovered, but can be used to hold any pointer to
|
||||||
|
* struct. The caller is responsible for supplying a function to
|
||||||
|
* compare two "things".
|
||||||
|
*
|
||||||
|
* Alternatively, this data structure can also be used as a LIFO stack
|
||||||
|
* by specifying NULL as the comparison function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compare two "things", one and two; the third parameter is cb_data
|
||||||
|
* in the prio_queue structure. The result is returned as a sign of
|
||||||
|
* the return value, being the same as the sign of the result of
|
||||||
|
* subtracting "two" from "one" (i.e. negative if "one" sorts earlier
|
||||||
|
* than "two").
|
||||||
|
*/
|
||||||
|
typedef int (*prio_queue_compare_fn)(const void *one, const void *two, void *cb_data);
|
||||||
|
|
||||||
|
struct prio_queue {
|
||||||
|
prio_queue_compare_fn compare;
|
||||||
|
void *cb_data;
|
||||||
|
int alloc, nr;
|
||||||
|
void **array;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the "thing" to the queue.
|
||||||
|
*/
|
||||||
|
extern void prio_queue_put(struct prio_queue *, void *thing);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract the "thing" that compares the smallest out of the queue,
|
||||||
|
* or NULL. If compare function is NULL, the queue acts as a LIFO
|
||||||
|
* stack.
|
||||||
|
*/
|
||||||
|
extern void *prio_queue_get(struct prio_queue *);
|
||||||
|
|
||||||
|
extern void clear_prio_queue(struct prio_queue *);
|
||||||
|
|
||||||
|
/* Reverse the LIFO elements */
|
||||||
|
extern void prio_queue_reverse(struct prio_queue *);
|
||||||
|
|
||||||
|
#endif /* PRIO_QUEUE_H */
|
13
revision.c
13
revision.c
|
@ -1296,7 +1296,7 @@ void init_revisions(struct rev_info *revs, const char *prefix)
|
||||||
DIFF_OPT_SET(&revs->pruning, QUICK);
|
DIFF_OPT_SET(&revs->pruning, QUICK);
|
||||||
revs->pruning.add_remove = file_add_remove;
|
revs->pruning.add_remove = file_add_remove;
|
||||||
revs->pruning.change = file_change;
|
revs->pruning.change = file_change;
|
||||||
revs->lifo = 1;
|
revs->sort_order = REV_SORT_IN_GRAPH_ORDER;
|
||||||
revs->dense = 1;
|
revs->dense = 1;
|
||||||
revs->prefix = prefix;
|
revs->prefix = prefix;
|
||||||
revs->max_age = -1;
|
revs->max_age = -1;
|
||||||
|
@ -1638,7 +1638,7 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
||||||
} else if (!strcmp(arg, "--merge")) {
|
} else if (!strcmp(arg, "--merge")) {
|
||||||
revs->show_merge = 1;
|
revs->show_merge = 1;
|
||||||
} else if (!strcmp(arg, "--topo-order")) {
|
} else if (!strcmp(arg, "--topo-order")) {
|
||||||
revs->lifo = 1;
|
revs->sort_order = REV_SORT_IN_GRAPH_ORDER;
|
||||||
revs->topo_order = 1;
|
revs->topo_order = 1;
|
||||||
} else if (!strcmp(arg, "--simplify-merges")) {
|
} else if (!strcmp(arg, "--simplify-merges")) {
|
||||||
revs->simplify_merges = 1;
|
revs->simplify_merges = 1;
|
||||||
|
@ -1656,7 +1656,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
|
||||||
revs->prune = 1;
|
revs->prune = 1;
|
||||||
load_ref_decorations(DECORATE_SHORT_REFS);
|
load_ref_decorations(DECORATE_SHORT_REFS);
|
||||||
} else if (!strcmp(arg, "--date-order")) {
|
} else if (!strcmp(arg, "--date-order")) {
|
||||||
revs->lifo = 0;
|
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;
|
revs->topo_order = 1;
|
||||||
} else if (!prefixcmp(arg, "--early-output")) {
|
} else if (!prefixcmp(arg, "--early-output")) {
|
||||||
int count = 100;
|
int count = 100;
|
||||||
|
@ -2606,7 +2609,7 @@ int prepare_revision_walk(struct rev_info *revs)
|
||||||
if (limit_list(revs) < 0)
|
if (limit_list(revs) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (revs->topo_order)
|
if (revs->topo_order)
|
||||||
sort_in_topological_order(&revs->commits, revs->lifo);
|
sort_in_topological_order(&revs->commits, revs->sort_order);
|
||||||
if (revs->line_level_traverse)
|
if (revs->line_level_traverse)
|
||||||
line_log_filter(revs);
|
line_log_filter(revs);
|
||||||
if (revs->simplify_merges)
|
if (revs->simplify_merges)
|
||||||
|
@ -2924,7 +2927,7 @@ static void create_boundary_commit_list(struct rev_info *revs)
|
||||||
* If revs->topo_order is set, sort the boundary commits
|
* If revs->topo_order is set, sort the boundary commits
|
||||||
* in topological order
|
* in topological order
|
||||||
*/
|
*/
|
||||||
sort_in_topological_order(&revs->commits, revs->lifo);
|
sort_in_topological_order(&revs->commits, revs->sort_order);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct commit *get_revision_internal(struct rev_info *revs)
|
static struct commit *get_revision_internal(struct rev_info *revs)
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include "parse-options.h"
|
#include "parse-options.h"
|
||||||
#include "grep.h"
|
#include "grep.h"
|
||||||
#include "notes.h"
|
#include "notes.h"
|
||||||
|
#include "commit.h"
|
||||||
|
|
||||||
#define SEEN (1u<<0)
|
#define SEEN (1u<<0)
|
||||||
#define UNINTERESTING (1u<<1)
|
#define UNINTERESTING (1u<<1)
|
||||||
|
@ -62,6 +63,10 @@ struct rev_info {
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
const char *def;
|
const char *def;
|
||||||
struct pathspec prune_data;
|
struct pathspec prune_data;
|
||||||
|
|
||||||
|
/* topo-sort */
|
||||||
|
enum rev_sort_order sort_order;
|
||||||
|
|
||||||
unsigned int early_output:1,
|
unsigned int early_output:1,
|
||||||
ignore_missing:1;
|
ignore_missing:1;
|
||||||
|
|
||||||
|
@ -72,7 +77,6 @@ struct rev_info {
|
||||||
show_all:1,
|
show_all:1,
|
||||||
remove_empty_trees:1,
|
remove_empty_trees:1,
|
||||||
simplify_history:1,
|
simplify_history:1,
|
||||||
lifo:1,
|
|
||||||
topo_order:1,
|
topo_order:1,
|
||||||
simplify_merges:1,
|
simplify_merges:1,
|
||||||
simplify_by_decoration:1,
|
simplify_by_decoration:1,
|
||||||
|
|
104
t/lib-t6000.sh
104
t/lib-t6000.sh
|
@ -1,55 +1,50 @@
|
||||||
: included from 6002 and others
|
: included from 6002 and others
|
||||||
|
|
||||||
[ -d .git/refs/tags ] || mkdir -p .git/refs/tags
|
mkdir -p .git/refs/tags
|
||||||
|
|
||||||
:> sed.script
|
>sed.script
|
||||||
|
|
||||||
# Answer the sha1 has associated with the tag. The tag must exist in .git or .git/refs/tags
|
# Answer the sha1 has associated with the tag. The tag must exist in .git/refs/tags
|
||||||
tag()
|
tag () {
|
||||||
{
|
|
||||||
_tag=$1
|
_tag=$1
|
||||||
[ -f .git/refs/tags/$_tag ] || error "tag: \"$_tag\" does not exist"
|
test -f ".git/refs/tags/$_tag" || error "tag: \"$_tag\" does not exist"
|
||||||
cat .git/refs/tags/$_tag
|
cat ".git/refs/tags/$_tag"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Generate a commit using the text specified to make it unique and the tree
|
# Generate a commit using the text specified to make it unique and the tree
|
||||||
# named by the tag specified.
|
# named by the tag specified.
|
||||||
unique_commit()
|
unique_commit () {
|
||||||
{
|
|
||||||
_text=$1
|
_text=$1
|
||||||
_tree=$2
|
_tree=$2
|
||||||
shift 2
|
shift 2
|
||||||
echo $_text | git commit-tree $(tag $_tree) "$@"
|
echo "$_text" | git commit-tree $(tag "$_tree") "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Save the output of a command into the tag specified. Prepend
|
# Save the output of a command into the tag specified. Prepend
|
||||||
# a substitution script for the tag onto the front of sed.script
|
# a substitution script for the tag onto the front of sed.script
|
||||||
save_tag()
|
save_tag () {
|
||||||
{
|
|
||||||
_tag=$1
|
_tag=$1
|
||||||
[ -n "$_tag" ] || error "usage: save_tag tag commit-args ..."
|
test -n "$_tag" || error "usage: save_tag tag commit-args ..."
|
||||||
shift 1
|
shift 1
|
||||||
"$@" >.git/refs/tags/$_tag
|
"$@" >".git/refs/tags/$_tag"
|
||||||
|
|
||||||
echo "s/$(tag $_tag)/$_tag/g" > sed.script.tmp
|
echo "s/$(tag $_tag)/$_tag/g" >sed.script.tmp
|
||||||
cat sed.script >> sed.script.tmp
|
cat sed.script >>sed.script.tmp
|
||||||
rm sed.script
|
rm sed.script
|
||||||
mv sed.script.tmp sed.script
|
mv sed.script.tmp sed.script
|
||||||
}
|
}
|
||||||
|
|
||||||
# Replace unhelpful sha1 hashses with their symbolic equivalents
|
# Replace unhelpful sha1 hashses with their symbolic equivalents
|
||||||
entag()
|
entag () {
|
||||||
{
|
|
||||||
sed -f sed.script
|
sed -f sed.script
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
|
# Execute a command after first saving, then setting the GIT_AUTHOR_EMAIL
|
||||||
# tag to a specified value. Restore the original value on return.
|
# tag to a specified value. Restore the original value on return.
|
||||||
as_author()
|
as_author () {
|
||||||
{
|
|
||||||
_author=$1
|
_author=$1
|
||||||
shift 1
|
shift 1
|
||||||
_save=$GIT_AUTHOR_EMAIL
|
_save=$GIT_AUTHOR_EMAIL
|
||||||
|
|
||||||
GIT_AUTHOR_EMAIL="$_author"
|
GIT_AUTHOR_EMAIL="$_author"
|
||||||
export GIT_AUTHOR_EMAIL
|
export GIT_AUTHOR_EMAIL
|
||||||
|
@ -63,45 +58,58 @@ as_author()
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
commit_date()
|
commit_date () {
|
||||||
{
|
_commit=$1
|
||||||
_commit=$1
|
git cat-file commit $_commit |
|
||||||
git cat-file commit $_commit | sed -n "s/^committer .*> \([0-9]*\) .*/\1/p"
|
sed -n "s/^committer .*> \([0-9]*\) .*/\1/p"
|
||||||
}
|
}
|
||||||
|
|
||||||
on_committer_date()
|
# Assign the value of fake date to a variable, but
|
||||||
{
|
# allow fairly common "1971-08-16 00:00" to be omittd
|
||||||
_date=$1
|
assign_fake_date () {
|
||||||
shift 1
|
case "$2" in
|
||||||
GIT_COMMITTER_DATE="$_date"
|
??:??:??) eval "$1='1971-08-16 $2'" ;;
|
||||||
export GIT_COMMITTER_DATE
|
??:??) eval "$1='1971-08-16 00:$2'" ;;
|
||||||
"$@"
|
??) eval "$1='1971-08-16 00:00:$2'" ;;
|
||||||
unset GIT_COMMITTER_DATE
|
*) eval "$1='$2'" ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
on_committer_date () {
|
||||||
|
assign_fake_date GIT_COMMITTER_DATE "$1"
|
||||||
|
export GIT_COMMITTER_DATE
|
||||||
|
shift 1
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
on_dates () {
|
||||||
|
assign_fake_date GIT_COMMITTER_DATE "$1"
|
||||||
|
assign_fake_date GIT_AUTHOR_DATE "$2"
|
||||||
|
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
|
||||||
|
shift 2
|
||||||
|
"$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Execute a command and suppress any error output.
|
# Execute a command and suppress any error output.
|
||||||
hide_error()
|
hide_error () {
|
||||||
{
|
|
||||||
"$@" 2>/dev/null
|
"$@" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
check_output()
|
check_output () {
|
||||||
{
|
|
||||||
_name=$1
|
_name=$1
|
||||||
shift 1
|
shift 1
|
||||||
if eval "$*" | entag > $_name.actual
|
if eval "$*" | entag >"$_name.actual"
|
||||||
then
|
then
|
||||||
test_cmp $_name.expected $_name.actual
|
test_cmp "$_name.expected" "$_name.actual"
|
||||||
else
|
else
|
||||||
return 1;
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Turn a reasonable test description into a reasonable test name.
|
# Turn a reasonable test description into a reasonable test name.
|
||||||
# All alphanums translated into -'s which are then compressed and stripped
|
# All alphanums translated into -'s which are then compressed and stripped
|
||||||
# from front and back.
|
# from front and back.
|
||||||
name_from_description()
|
name_from_description () {
|
||||||
{
|
|
||||||
perl -pe '
|
perl -pe '
|
||||||
s/[^A-Za-z0-9.]/-/g;
|
s/[^A-Za-z0-9.]/-/g;
|
||||||
s/-+/-/g;
|
s/-+/-/g;
|
||||||
|
@ -119,9 +127,11 @@ name_from_description()
|
||||||
test_output_expect_success()
|
test_output_expect_success()
|
||||||
{
|
{
|
||||||
_description=$1
|
_description=$1
|
||||||
_test=$2
|
_test=$2
|
||||||
[ $# -eq 2 ] || error "usage: test_output_expect_success description test <<EOF ... EOF"
|
test $# -eq 2 ||
|
||||||
_name=$(echo $_description | name_from_description)
|
error "usage: test_output_expect_success description test <<EOF ... EOF"
|
||||||
cat > $_name.expected
|
|
||||||
|
_name=$(echo $_description | name_from_description)
|
||||||
|
cat >"$_name.expected"
|
||||||
test_expect_success "$_description" "check_output $_name \"$_test\""
|
test_expect_success "$_description" "check_output $_name \"$_test\""
|
||||||
}
|
}
|
||||||
|
|
50
t/t0009-prio-queue.sh
Executable file
50
t/t0009-prio-queue.sh
Executable file
|
@ -0,0 +1,50 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
test_description='basic tests for priority queue implementation'
|
||||||
|
. ./test-lib.sh
|
||||||
|
|
||||||
|
cat >expect <<'EOF'
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
10
|
||||||
|
EOF
|
||||||
|
test_expect_success 'basic ordering' '
|
||||||
|
test-prio-queue 2 6 3 10 9 5 7 4 5 8 1 dump >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >expect <<'EOF'
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
1
|
||||||
|
5
|
||||||
|
6
|
||||||
|
EOF
|
||||||
|
test_expect_success 'mixed put and get' '
|
||||||
|
test-prio-queue 6 2 4 get 5 3 get get 1 dump >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
cat >expect <<'EOF'
|
||||||
|
1
|
||||||
|
2
|
||||||
|
NULL
|
||||||
|
1
|
||||||
|
2
|
||||||
|
NULL
|
||||||
|
EOF
|
||||||
|
test_expect_success 'notice empty queue' '
|
||||||
|
test-prio-queue 1 2 get get get 1 2 get get get >actual &&
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
|
test_done
|
|
@ -39,25 +39,25 @@ test_bisection_diff()
|
||||||
date >path0
|
date >path0
|
||||||
git update-index --add path0
|
git update-index --add path0
|
||||||
save_tag tree git write-tree
|
save_tag tree git write-tree
|
||||||
on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
|
on_committer_date "00:00" hide_error save_tag root unique_commit root tree
|
||||||
on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
|
on_committer_date "00:01" save_tag l0 unique_commit l0 tree -p root
|
||||||
on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
|
on_committer_date "00:02" save_tag l1 unique_commit l1 tree -p l0
|
||||||
on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
|
on_committer_date "00:03" save_tag l2 unique_commit l2 tree -p l1
|
||||||
on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
|
on_committer_date "00:04" save_tag a0 unique_commit a0 tree -p l2
|
||||||
on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
|
on_committer_date "00:05" save_tag a1 unique_commit a1 tree -p a0
|
||||||
on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
|
on_committer_date "00:06" save_tag b1 unique_commit b1 tree -p a0
|
||||||
on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
|
on_committer_date "00:07" save_tag c1 unique_commit c1 tree -p b1
|
||||||
on_committer_date "1971-08-16 00:00:08" save_tag b2 unique_commit b2 tree -p b1
|
on_committer_date "00:08" save_tag b2 unique_commit b2 tree -p b1
|
||||||
on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b2 tree -p b2
|
on_committer_date "00:09" save_tag b3 unique_commit b2 tree -p b2
|
||||||
on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
|
on_committer_date "00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
|
||||||
on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
|
on_committer_date "00:11" save_tag c3 unique_commit c3 tree -p c2
|
||||||
on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
|
on_committer_date "00:12" save_tag a2 unique_commit a2 tree -p a1
|
||||||
on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
|
on_committer_date "00:13" save_tag a3 unique_commit a3 tree -p a2
|
||||||
on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
|
on_committer_date "00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
|
||||||
on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
|
on_committer_date "00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
|
||||||
on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
|
on_committer_date "00:16" save_tag l3 unique_commit l3 tree -p a4
|
||||||
on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
|
on_committer_date "00:17" save_tag l4 unique_commit l4 tree -p l3
|
||||||
on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
|
on_committer_date "00:18" save_tag l5 unique_commit l5 tree -p l4
|
||||||
git update-ref HEAD $(tag l5)
|
git update-ref HEAD $(tag l5)
|
||||||
|
|
||||||
|
|
||||||
|
@ -90,29 +90,29 @@ git update-ref HEAD $(tag l5)
|
||||||
# F
|
# F
|
||||||
|
|
||||||
|
|
||||||
on_committer_date "1971-08-16 00:00:00" hide_error save_tag F unique_commit F tree
|
on_committer_date "00:00" hide_error save_tag F unique_commit F tree
|
||||||
on_committer_date "1971-08-16 00:00:01" save_tag e8 unique_commit e8 tree -p F
|
on_committer_date "00:01" save_tag e8 unique_commit e8 tree -p F
|
||||||
on_committer_date "1971-08-16 00:00:02" save_tag e7 unique_commit e7 tree -p e8
|
on_committer_date "00:02" save_tag e7 unique_commit e7 tree -p e8
|
||||||
on_committer_date "1971-08-16 00:00:03" save_tag e6 unique_commit e6 tree -p e7
|
on_committer_date "00:03" save_tag e6 unique_commit e6 tree -p e7
|
||||||
on_committer_date "1971-08-16 00:00:04" save_tag e5 unique_commit e5 tree -p e6
|
on_committer_date "00:04" save_tag e5 unique_commit e5 tree -p e6
|
||||||
on_committer_date "1971-08-16 00:00:05" save_tag f4 unique_commit f4 tree -p F
|
on_committer_date "00:05" save_tag f4 unique_commit f4 tree -p F
|
||||||
on_committer_date "1971-08-16 00:00:06" save_tag f3 unique_commit f3 tree -p f4
|
on_committer_date "00:06" save_tag f3 unique_commit f3 tree -p f4
|
||||||
on_committer_date "1971-08-16 00:00:07" save_tag f2 unique_commit f2 tree -p f3
|
on_committer_date "00:07" save_tag f2 unique_commit f2 tree -p f3
|
||||||
on_committer_date "1971-08-16 00:00:08" save_tag f1 unique_commit f1 tree -p f2
|
on_committer_date "00:08" save_tag f1 unique_commit f1 tree -p f2
|
||||||
on_committer_date "1971-08-16 00:00:09" save_tag e4 unique_commit e4 tree -p e5
|
on_committer_date "00:09" save_tag e4 unique_commit e4 tree -p e5
|
||||||
on_committer_date "1971-08-16 00:00:10" save_tag e3 unique_commit e3 tree -p e4
|
on_committer_date "00:10" save_tag e3 unique_commit e3 tree -p e4
|
||||||
on_committer_date "1971-08-16 00:00:11" save_tag e2 unique_commit e2 tree -p e3
|
on_committer_date "00:11" save_tag e2 unique_commit e2 tree -p e3
|
||||||
on_committer_date "1971-08-16 00:00:12" save_tag e1 unique_commit e1 tree -p e2
|
on_committer_date "00:12" save_tag e1 unique_commit e1 tree -p e2
|
||||||
on_committer_date "1971-08-16 00:00:13" save_tag E unique_commit E tree -p e1 -p f1
|
on_committer_date "00:13" save_tag E unique_commit E tree -p e1 -p f1
|
||||||
|
|
||||||
on_committer_date "1971-08-16 00:00:00" hide_error save_tag U unique_commit U tree
|
on_committer_date "00:00" hide_error save_tag U unique_commit U tree
|
||||||
on_committer_date "1971-08-16 00:00:01" save_tag u0 unique_commit u0 tree -p U
|
on_committer_date "00:01" save_tag u0 unique_commit u0 tree -p U
|
||||||
on_committer_date "1971-08-16 00:00:01" save_tag u1 unique_commit u1 tree -p u0
|
on_committer_date "00:01" save_tag u1 unique_commit u1 tree -p u0
|
||||||
on_committer_date "1971-08-16 00:00:02" save_tag u2 unique_commit u2 tree -p u0
|
on_committer_date "00:02" save_tag u2 unique_commit u2 tree -p u0
|
||||||
on_committer_date "1971-08-16 00:00:03" save_tag u3 unique_commit u3 tree -p u0
|
on_committer_date "00:03" save_tag u3 unique_commit u3 tree -p u0
|
||||||
on_committer_date "1971-08-16 00:00:04" save_tag u4 unique_commit u4 tree -p u0
|
on_committer_date "00:04" save_tag u4 unique_commit u4 tree -p u0
|
||||||
on_committer_date "1971-08-16 00:00:05" save_tag u5 unique_commit u5 tree -p u0
|
on_committer_date "00:05" save_tag u5 unique_commit u5 tree -p u0
|
||||||
on_committer_date "1971-08-16 00:00:06" save_tag V unique_commit V tree -p u1 -p u2 -p u3 -p u4 -p u5
|
on_committer_date "00:06" save_tag V unique_commit V tree -p u1 -p u2 -p u3 -p u4 -p u5
|
||||||
|
|
||||||
test_sequence()
|
test_sequence()
|
||||||
{
|
{
|
||||||
|
|
|
@ -16,39 +16,34 @@ list_duplicates()
|
||||||
date >path0
|
date >path0
|
||||||
git update-index --add path0
|
git update-index --add path0
|
||||||
save_tag tree git write-tree
|
save_tag tree git write-tree
|
||||||
on_committer_date "1971-08-16 00:00:00" hide_error save_tag root unique_commit root tree
|
on_dates "00:00" "00:00" hide_error save_tag root unique_commit root tree
|
||||||
on_committer_date "1971-08-16 00:00:01" save_tag l0 unique_commit l0 tree -p root
|
on_dates "00:01" "00:01" save_tag l0 unique_commit l0 tree -p root
|
||||||
on_committer_date "1971-08-16 00:00:02" save_tag l1 unique_commit l1 tree -p l0
|
on_dates "00:02" "00:02" save_tag l1 unique_commit l1 tree -p l0
|
||||||
on_committer_date "1971-08-16 00:00:03" save_tag l2 unique_commit l2 tree -p l1
|
on_dates "00:03" "00:03" save_tag l2 unique_commit l2 tree -p l1
|
||||||
on_committer_date "1971-08-16 00:00:04" save_tag a0 unique_commit a0 tree -p l2
|
on_dates "00:04" "00:04" save_tag a0 unique_commit a0 tree -p l2
|
||||||
on_committer_date "1971-08-16 00:00:05" save_tag a1 unique_commit a1 tree -p a0
|
on_dates "00:05" "00:05" save_tag a1 unique_commit a1 tree -p a0
|
||||||
on_committer_date "1971-08-16 00:00:06" save_tag b1 unique_commit b1 tree -p a0
|
on_dates "00:06" "00:06" save_tag b1 unique_commit b1 tree -p a0
|
||||||
on_committer_date "1971-08-16 00:00:07" save_tag c1 unique_commit c1 tree -p b1
|
on_dates "00:07" "00:07" save_tag c1 unique_commit c1 tree -p b1
|
||||||
on_committer_date "1971-08-16 00:00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
|
on_dates "00:08" "00:08" as_author foobar@example.com save_tag b2 unique_commit b2 tree -p b1
|
||||||
on_committer_date "1971-08-16 00:00:09" save_tag b3 unique_commit b3 tree -p b2
|
on_dates "00:09" "00:09" save_tag b3 unique_commit b3 tree -p b2
|
||||||
on_committer_date "1971-08-16 00:00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
|
on_dates "00:10" "00:10" save_tag c2 unique_commit c2 tree -p c1 -p b2
|
||||||
on_committer_date "1971-08-16 00:00:11" save_tag c3 unique_commit c3 tree -p c2
|
on_dates "00:11" "00:11" save_tag c3 unique_commit c3 tree -p c2
|
||||||
on_committer_date "1971-08-16 00:00:12" save_tag a2 unique_commit a2 tree -p a1
|
on_dates "00:12" "00:00" save_tag a2 unique_commit a2 tree -p a1
|
||||||
on_committer_date "1971-08-16 00:00:13" save_tag a3 unique_commit a3 tree -p a2
|
on_dates "00:13" "00:01" save_tag a3 unique_commit a3 tree -p a2
|
||||||
on_committer_date "1971-08-16 00:00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
|
on_dates "00:14" "00:14" save_tag b4 unique_commit b4 tree -p b3 -p a3
|
||||||
on_committer_date "1971-08-16 00:00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
|
on_dates "00:15" "00:15" save_tag a4 unique_commit a4 tree -p a3 -p b4 -p c3
|
||||||
on_committer_date "1971-08-16 00:00:16" save_tag l3 unique_commit l3 tree -p a4
|
on_dates "00:16" "00:16" save_tag l3 unique_commit l3 tree -p a4
|
||||||
on_committer_date "1971-08-16 00:00:17" save_tag l4 unique_commit l4 tree -p l3
|
on_dates "00:17" "00:17" save_tag l4 unique_commit l4 tree -p l3
|
||||||
on_committer_date "1971-08-16 00:00:18" save_tag l5 unique_commit l5 tree -p l4
|
on_dates "00:18" "00:18" save_tag l5 unique_commit l5 tree -p l4
|
||||||
on_committer_date "1971-08-16 00:00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
|
on_dates "00:19" "00:19" save_tag m1 unique_commit m1 tree -p a4 -p c3
|
||||||
on_committer_date "1971-08-16 00:00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
|
on_dates "00:20" "00:20" save_tag m2 unique_commit m2 tree -p c3 -p a4
|
||||||
on_committer_date "1971-08-16 00:00:21" hide_error save_tag alt_root unique_commit alt_root tree
|
on_dates "00:21" "00:21" hide_error save_tag alt_root unique_commit alt_root tree
|
||||||
on_committer_date "1971-08-16 00:00:22" save_tag r0 unique_commit r0 tree -p alt_root
|
on_dates "00:22" "00:22" save_tag r0 unique_commit r0 tree -p alt_root
|
||||||
on_committer_date "1971-08-16 00:00:23" save_tag r1 unique_commit r1 tree -p r0
|
on_dates "00:23" "00:23" save_tag r1 unique_commit r1 tree -p r0
|
||||||
on_committer_date "1971-08-16 00:00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1
|
on_dates "00:24" "00:24" save_tag l5r1 unique_commit l5r1 tree -p l5 -p r1
|
||||||
on_committer_date "1971-08-16 00:00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5
|
on_dates "00:25" "00:25" save_tag r1l5 unique_commit r1l5 tree -p r1 -p l5
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# note: as of 20/6, it isn't possible to create duplicate parents, so this
|
|
||||||
# can't be tested.
|
|
||||||
#
|
|
||||||
#on_committer_date "1971-08-16 00:00:20" save_tag m3 unique_commit m3 tree -p c3 -p a4 -p c3
|
|
||||||
hide_error save_tag e1 as_author e@example.com unique_commit e1 tree
|
hide_error save_tag e1 as_author e@example.com unique_commit e1 tree
|
||||||
save_tag e2 as_author e@example.com unique_commit e2 tree -p e1
|
save_tag e2 as_author e@example.com unique_commit e2 tree -p e1
|
||||||
save_tag f1 as_author f@example.com unique_commit f1 tree -p e1
|
save_tag f1 as_author f@example.com unique_commit f1 tree -p e1
|
||||||
|
@ -105,6 +100,50 @@ l0
|
||||||
root
|
root
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
test_output_expect_success 'simple date order' 'git rev-list --date-order HEAD' <<EOF
|
||||||
|
l5
|
||||||
|
l4
|
||||||
|
l3
|
||||||
|
a4
|
||||||
|
b4
|
||||||
|
a3
|
||||||
|
a2
|
||||||
|
c3
|
||||||
|
c2
|
||||||
|
b3
|
||||||
|
b2
|
||||||
|
c1
|
||||||
|
b1
|
||||||
|
a1
|
||||||
|
a0
|
||||||
|
l2
|
||||||
|
l1
|
||||||
|
l0
|
||||||
|
root
|
||||||
|
EOF
|
||||||
|
|
||||||
|
test_output_expect_success 'simple author-date order' 'git rev-list --author-date-order HEAD' <<EOF
|
||||||
|
l5
|
||||||
|
l4
|
||||||
|
l3
|
||||||
|
a4
|
||||||
|
b4
|
||||||
|
c3
|
||||||
|
c2
|
||||||
|
b3
|
||||||
|
b2
|
||||||
|
c1
|
||||||
|
b1
|
||||||
|
a3
|
||||||
|
a2
|
||||||
|
a1
|
||||||
|
a0
|
||||||
|
l2
|
||||||
|
l1
|
||||||
|
l0
|
||||||
|
root
|
||||||
|
EOF
|
||||||
|
|
||||||
test_output_expect_success 'two diamonds topo order (g6)' 'git rev-list --topo-order g4' <<EOF
|
test_output_expect_success 'two diamonds topo order (g6)' 'git rev-list --topo-order g4' <<EOF
|
||||||
g4
|
g4
|
||||||
h2
|
h2
|
||||||
|
|
39
test-prio-queue.c
Normal file
39
test-prio-queue.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
#include "cache.h"
|
||||||
|
#include "prio-queue.h"
|
||||||
|
|
||||||
|
static int intcmp(const void *va, const void *vb, void *data)
|
||||||
|
{
|
||||||
|
const int *a = va, *b = vb;
|
||||||
|
return *a - *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void show(int *v)
|
||||||
|
{
|
||||||
|
if (!v)
|
||||||
|
printf("NULL\n");
|
||||||
|
else
|
||||||
|
printf("%d\n", *v);
|
||||||
|
free(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct prio_queue pq = { intcmp };
|
||||||
|
|
||||||
|
while (*++argv) {
|
||||||
|
if (!strcmp(*argv, "get"))
|
||||||
|
show(prio_queue_get(&pq));
|
||||||
|
else if (!strcmp(*argv, "dump")) {
|
||||||
|
int *v;
|
||||||
|
while ((v = prio_queue_get(&pq)))
|
||||||
|
show(v);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int *v = malloc(sizeof(*v));
|
||||||
|
*v = atoi(*argv);
|
||||||
|
prio_queue_put(&pq, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue