Merge branch 'lt/rev-list-interactive'

* lt/rev-list-interactive:
  Fix parent rewriting in --early-output
  revision walker: mini clean-up
  Enhance --early-output format
  Add "--early-output" log flag for interactive GUI use
  Simplify topo-sort logic
This commit is contained in:
Junio C Hamano
2007-11-18 16:03:24 -08:00
7 changed files with 285 additions and 175 deletions

View File

@ -176,7 +176,7 @@ static void shortlog(const char *name, unsigned char *sha1,
struct commit *commit; struct commit *commit;
struct object *branch; struct object *branch;
struct list subjects = { NULL, NULL, 0, 0 }; struct list subjects = { NULL, NULL, 0, 0 };
int flags = UNINTERESTING | TREECHANGE | SEEN | SHOWN | ADDED; int flags = UNINTERESTING | TREESAME | SEEN | SHOWN | ADDED;
branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40); branch = deref_tag(parse_object(sha1), sha1_to_hex(sha1), 40);
if (!branch || branch->type != OBJ_COMMIT) if (!branch || branch->type != OBJ_COMMIT)

View File

@ -77,11 +77,134 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
} }
} }
/*
* This gives a rough estimate for how many commits we
* will print out in the list.
*/
static int estimate_commit_count(struct rev_info *rev, struct commit_list *list)
{
int n = 0;
while (list) {
struct commit *commit = list->item;
unsigned int flags = commit->object.flags;
list = list->next;
if (!(flags & (TREESAME | UNINTERESTING)))
n++;
}
return n;
}
static void show_early_header(struct rev_info *rev, const char *stage, int nr)
{
if (rev->shown_one) {
rev->shown_one = 0;
if (rev->commit_format != CMIT_FMT_ONELINE)
putchar(rev->diffopt.line_termination);
}
printf("Final output: %d %s\n", nr, stage);
}
struct itimerval early_output_timer;
static void log_show_early(struct rev_info *revs, struct commit_list *list)
{
int i = revs->early_output;
int show_header = 1;
sort_in_topological_order(&list, revs->lifo);
while (list && i) {
struct commit *commit = list->item;
switch (simplify_commit(revs, commit)) {
case commit_show:
if (show_header) {
int n = estimate_commit_count(revs, list);
show_early_header(revs, "incomplete", n);
show_header = 0;
}
log_tree_commit(revs, commit);
i--;
break;
case commit_ignore:
break;
case commit_error:
return;
}
list = list->next;
}
/* Did we already get enough commits for the early output? */
if (!i)
return;
/*
* ..if no, then repeat it twice a second until we
* do.
*
* NOTE! We don't use "it_interval", because if the
* reader isn't listening, we want our output to be
* throttled by the writing, and not have the timer
* trigger every second even if we're blocked on a
* reader!
*/
early_output_timer.it_value.tv_sec = 0;
early_output_timer.it_value.tv_usec = 500000;
setitimer(ITIMER_REAL, &early_output_timer, NULL);
}
static void early_output(int signal)
{
show_early_output = log_show_early;
}
static void setup_early_output(struct rev_info *rev)
{
struct sigaction sa;
/*
* Set up the signal handler, minimally intrusively:
* we only set a single volatile integer word (not
* using sigatomic_t - trying to avoid unnecessary
* system dependencies and headers), and using
* SA_RESTART.
*/
memset(&sa, 0, sizeof(sa));
sa.sa_handler = early_output;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
sigaction(SIGALRM, &sa, NULL);
/*
* If we can get the whole output in less than a
* tenth of a second, don't even bother doing the
* early-output thing..
*
* This is a one-time-only trigger.
*/
early_output_timer.it_value.tv_sec = 0;
early_output_timer.it_value.tv_usec = 100000;
setitimer(ITIMER_REAL, &early_output_timer, NULL);
}
static void finish_early_output(struct rev_info *rev)
{
int n = estimate_commit_count(rev, rev->commits);
signal(SIGALRM, SIG_IGN);
show_early_header(rev, "done", n);
}
static int cmd_log_walk(struct rev_info *rev) static int cmd_log_walk(struct rev_info *rev)
{ {
struct commit *commit; struct commit *commit;
if (rev->early_output)
setup_early_output(rev);
prepare_revision_walk(rev); prepare_revision_walk(rev);
if (rev->early_output)
finish_early_output(rev);
while ((commit = get_revision(rev)) != NULL) { while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit); log_tree_commit(rev, commit);
if (!rev->reflog_info) { if (!rev->reflog_info) {

View File

@ -153,7 +153,7 @@ static int count_distance(struct commit_list *entry)
if (commit->object.flags & (UNINTERESTING | COUNTED)) if (commit->object.flags & (UNINTERESTING | COUNTED))
break; break;
if (!revs.prune_fn || (commit->object.flags & TREECHANGE)) if (!(commit->object.flags & TREESAME))
nr++; nr++;
commit->object.flags |= COUNTED; commit->object.flags |= COUNTED;
p = commit->parents; p = commit->parents;
@ -209,7 +209,7 @@ static inline int halfway(struct commit_list *p, int nr)
/* /*
* Don't short-cut something we are not going to return! * Don't short-cut something we are not going to return!
*/ */
if (revs.prune_fn && !(p->item->object.flags & TREECHANGE)) if (p->item->object.flags & TREESAME)
return 0; return 0;
if (DEBUG_BISECT) if (DEBUG_BISECT)
return 0; return 0;
@ -245,7 +245,7 @@ static void show_list(const char *debug, int counted, int nr,
char *ep, *sp; char *ep, *sp;
fprintf(stderr, "%c%c%c ", fprintf(stderr, "%c%c%c ",
(flags & TREECHANGE) ? 'T' : ' ', (flags & TREESAME) ? ' ' : 'T',
(flags & UNINTERESTING) ? 'U' : ' ', (flags & UNINTERESTING) ? 'U' : ' ',
(flags & COUNTED) ? 'C' : ' '); (flags & COUNTED) ? 'C' : ' ');
if (commit->util) if (commit->util)
@ -279,7 +279,7 @@ static struct commit_list *best_bisection(struct commit_list *list, int nr)
int distance; int distance;
unsigned flags = p->item->object.flags; unsigned flags = p->item->object.flags;
if (revs.prune_fn && !(flags & TREECHANGE)) if (flags & TREESAME)
continue; continue;
distance = weight(p); distance = weight(p);
if (nr - distance < distance) if (nr - distance < distance)
@ -319,7 +319,7 @@ static struct commit_list *best_bisection_sorted(struct commit_list *list, int n
int distance; int distance;
unsigned flags = p->item->object.flags; unsigned flags = p->item->object.flags;
if (revs.prune_fn && !(flags & TREECHANGE)) if (flags & TREESAME)
continue; continue;
distance = weight(p); distance = weight(p);
if (nr - distance < distance) if (nr - distance < distance)
@ -373,7 +373,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
p->item->util = &weights[n++]; p->item->util = &weights[n++];
switch (count_interesting_parents(commit)) { switch (count_interesting_parents(commit)) {
case 0: case 0:
if (!revs.prune_fn || (flags & TREECHANGE)) { if (!(flags & TREESAME)) {
weight_set(p, 1); weight_set(p, 1);
counted++; counted++;
show_list("bisection 2 count one", show_list("bisection 2 count one",
@ -446,7 +446,7 @@ static struct commit_list *do_find_bisection(struct commit_list *list,
* add one for p itself if p is to be counted, * add one for p itself if p is to be counted,
* otherwise inherit it from q directly. * otherwise inherit it from q directly.
*/ */
if (!revs.prune_fn || (flags & TREECHANGE)) { if (!(flags & TREESAME)) {
weight_set(p, weight(q)+1); weight_set(p, weight(q)+1);
counted++; counted++;
show_list("bisection 2 count one", show_list("bisection 2 count one",
@ -493,7 +493,7 @@ static struct commit_list *find_bisection(struct commit_list *list,
continue; continue;
p->next = last; p->next = last;
last = p; last = p;
if (!revs.prune_fn || (flags & TREECHANGE)) if (!(flags & TREESAME))
nr++; nr++;
on_list++; on_list++;
} }

148
commit.c
View File

@ -8,22 +8,6 @@
int save_commit_buffer = 1; int save_commit_buffer = 1;
struct sort_node
{
/*
* the number of children of the associated commit
* that also occur in the list being sorted.
*/
unsigned int indegree;
/*
* reference to original list item that we will re-use
* on output.
*/
struct commit_list * list_item;
};
const char *commit_type = "commit"; const char *commit_type = "commit";
static struct commit *check_commit(struct object *obj, static struct commit *check_commit(struct object *obj,
@ -431,69 +415,38 @@ struct commit *pop_commit(struct commit_list **stack)
return item; return item;
} }
void topo_sort_default_setter(struct commit *c, void *data)
{
c->util = data;
}
void *topo_sort_default_getter(struct commit *c)
{
return c->util;
}
/* /*
* 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, int lifo)
{ {
sort_in_topological_order_fn(list, lifo, topo_sort_default_setter, struct commit_list *next, *orig = *list;
topo_sort_default_getter); struct commit_list *work, **insert;
} struct commit_list **pptr;
void sort_in_topological_order_fn(struct commit_list ** list, int lifo, if (!orig)
topo_sort_set_fn_t setter,
topo_sort_get_fn_t getter)
{
struct commit_list * next = *list;
struct commit_list * work = NULL, **insert;
struct commit_list ** pptr = list;
struct sort_node * nodes;
struct sort_node * next_nodes;
int count = 0;
/* determine the size of the list */
while (next) {
next = next->next;
count++;
}
if (!count)
return; return;
/* allocate an array to help sort the list */ *list = NULL;
nodes = xcalloc(count, sizeof(*nodes));
/* link the list to the array */ /* Mark them and clear the indegree */
next_nodes = nodes; for (next = orig; next; next = next->next) {
next=*list; struct commit *commit = next->item;
while (next) { commit->object.flags |= TOPOSORT;
next_nodes->list_item = next; commit->indegree = 0;
setter(next->item, next_nodes);
next_nodes++;
next = next->next;
} }
/* update the indegree */ /* update the indegree */
next=*list; for (next = orig; next; next = next->next) {
while (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;
struct sort_node * pn = (struct sort_node *) getter(parent);
if (pn) if (parent->object.flags & TOPOSORT)
pn->indegree++; parent->indegree++;
parents=parents->next; parents = parents->next;
} }
next=next->next;
} }
/* /*
* find the tips * find the tips
* *
@ -501,55 +454,56 @@ void sort_in_topological_order_fn(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.
*/ */
next=*list; work = NULL;
insert = &work; insert = &work;
while (next) { for (next = orig; next; next = next->next) {
struct sort_node * node = (struct sort_node *) getter(next->item); struct commit *commit = next->item;
if (node->indegree == 0) { if (!commit->indegree)
insert = &commit_list_insert(next->item, insert)->next; insert = &commit_list_insert(commit, insert)->next;
}
next=next->next;
} }
/* process the list in topological order */ /* process the list in topological order */
if (!lifo) if (!lifo)
sort_by_date(&work); sort_by_date(&work);
pptr = list;
*list = NULL;
while (work) { while (work) {
struct commit * work_item = pop_commit(&work); struct commit *commit;
struct sort_node * work_node = (struct sort_node *) getter(work_item); struct commit_list *parents, *work_item;
struct commit_list * parents = work_item->parents;
while (parents) { work_item = work;
struct commit * parent=parents->item; work = work_item->next;
struct sort_node * pn = (struct sort_node *) getter(parent); work_item->next = NULL;
if (pn) { commit = work_item->item;
/* for (parents = commit->parents; parents ; parents = parents->next) {
* parents are only enqueued for emission struct commit *parent=parents->item;
* when all their children have been emitted thereby
* guaranteeing topological order. if (!(parent->object.flags & TOPOSORT))
*/ continue;
pn->indegree--;
if (!pn->indegree) { /*
if (!lifo) * parents are only enqueued for emission
insert_by_date(parent, &work); * when all their children have been emitted thereby
else * guaranteeing topological order.
commit_list_insert(parent, &work); */
} if (!--parent->indegree) {
if (!lifo)
insert_by_date(parent, &work);
else
commit_list_insert(parent, &work);
} }
parents=parents->next;
} }
/* /*
* work_item is a commit all of whose children * work_item is a commit all of whose children
* have already been emitted. we can emit it now. * have already been emitted. we can emit it now.
*/ */
*pptr = work_node->list_item; commit->object.flags &= ~TOPOSORT;
pptr = &(*pptr)->next; *pptr = work_item;
*pptr = NULL; pptr = &work_item->next;
setter(work_item, NULL);
} }
free(nodes);
} }
/* merge-base stuff */ /* merge-base stuff */

View File

@ -14,6 +14,7 @@ struct commit_list {
struct commit { struct commit {
struct object object; struct object object;
void *util; void *util;
unsigned int indegree;
unsigned long date; unsigned long date;
struct commit_list *parents; struct commit_list *parents;
struct tree *tree; struct tree *tree;
@ -84,31 +85,12 @@ void clear_commit_marks(struct commit *commit, unsigned int mark);
/* /*
* Performs an in-place topological sort of list supplied. * Performs an in-place topological sort of list supplied.
* *
* Pre-conditions for sort_in_topological_order:
* all commits in input list and all parents of those
* commits must have object.util == NULL
*
* Pre-conditions for sort_in_topological_order_fn:
* all commits in input list and all parents of those
* commits must have getter(commit) == NULL
*
* Post-conditions:
* 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 * in addition, when lifo == 0, commits on parallel tracks are
* sorted in the dates order. * sorted in the dates order.
*/ */
typedef void (*topo_sort_set_fn_t)(struct commit*, void *data);
typedef void* (*topo_sort_get_fn_t)(struct commit*);
void topo_sort_default_setter(struct commit *c, void *data);
void *topo_sort_default_getter(struct commit *c);
void sort_in_topological_order(struct commit_list ** list, int lifo); void sort_in_topological_order(struct commit_list ** list, int lifo);
void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
topo_sort_set_fn_t setter,
topo_sort_get_fn_t getter);
struct commit_graft { struct commit_graft {
unsigned char sha1[20]; unsigned char sha1[20];
@ -135,4 +117,9 @@ extern int interactive_add(void);
extern void add_files_to_cache(int verbose, const char *prefix, const char **files); extern void add_files_to_cache(int verbose, const char *prefix, const char **files);
extern int rerere(void); extern int rerere(void);
static inline int single_parent(struct commit *commit)
{
return commit->parents && !commit->parents->next;
}
#endif /* COMMIT_H */ #endif /* COMMIT_H */

View File

@ -10,6 +10,8 @@
#include "reflog-walk.h" #include "reflog-walk.h"
#include "patch-ids.h" #include "patch-ids.h"
volatile show_early_output_fn_t show_early_output;
static char *path_name(struct name_path *path, const char *name) static char *path_name(struct name_path *path, const char *name)
{ {
struct name_path *p; struct name_path *p;
@ -306,15 +308,28 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
struct commit_list **pp, *parent; struct commit_list **pp, *parent;
int tree_changed = 0, tree_same = 0; int tree_changed = 0, tree_same = 0;
/*
* If we don't do pruning, everything is interesting
*/
if (!revs->prune)
return;
if (!commit->tree) if (!commit->tree)
return; return;
if (!commit->parents) { if (!commit->parents) {
if (!rev_same_tree_as_empty(revs, commit->tree)) if (rev_same_tree_as_empty(revs, commit->tree))
commit->object.flags |= TREECHANGE; commit->object.flags |= TREESAME;
return; return;
} }
/*
* Normal non-merge commit? If we don't want to make the
* history dense, we consider it always to be a change..
*/
if (!revs->dense && !commit->parents->next)
return;
pp = &commit->parents; pp = &commit->parents;
while ((parent = *pp) != NULL) { while ((parent = *pp) != NULL) {
struct commit *p = parent->item; struct commit *p = parent->item;
@ -338,6 +353,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
} }
parent->next = NULL; parent->next = NULL;
commit->parents = parent; commit->parents = parent;
commit->object.flags |= TREESAME;
return; return;
case REV_TREE_NEW: case REV_TREE_NEW:
@ -366,7 +382,8 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit)
die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1)); die("bad tree compare for commit %s", sha1_to_hex(commit->object.sha1));
} }
if (tree_changed && !tree_same) if (tree_changed && !tree_same)
commit->object.flags |= TREECHANGE; return;
commit->object.flags |= TREESAME;
} }
static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list) static int add_parents_to_list(struct rev_info *revs, struct commit *commit, struct commit_list **list)
@ -413,8 +430,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
* simplify the commit history and find the parent * simplify the commit history and find the parent
* that has no differences in the path set if one exists. * that has no differences in the path set if one exists.
*/ */
if (revs->prune_fn) try_to_simplify_commit(revs, commit);
revs->prune_fn(revs, commit);
if (revs->no_walk) if (revs->no_walk)
return 0; return 0;
@ -533,6 +549,7 @@ static int limit_list(struct rev_info *revs)
struct commit_list *entry = list; struct commit_list *entry = list;
struct commit *commit = list->item; struct commit *commit = list->item;
struct object *obj = &commit->object; struct object *obj = &commit->object;
show_early_output_fn_t show;
list = list->next; list = list->next;
free(entry); free(entry);
@ -550,6 +567,13 @@ static int limit_list(struct rev_info *revs)
if (revs->min_age != -1 && (commit->date > revs->min_age)) if (revs->min_age != -1 && (commit->date > revs->min_age))
continue; continue;
p = &commit_list_insert(commit, p)->next; p = &commit_list_insert(commit, p)->next;
show = show_early_output;
if (!show)
continue;
show(revs, newlist);
show_early_output = NULL;
} }
if (revs->cherry_pick) if (revs->cherry_pick)
cherry_pick_list(newlist, revs); cherry_pick_list(newlist, revs);
@ -674,12 +698,6 @@ void init_revisions(struct rev_info *revs, const char *prefix)
revs->skip_count = -1; revs->skip_count = -1;
revs->max_count = -1; revs->max_count = -1;
revs->prune_fn = NULL;
revs->prune_data = NULL;
revs->topo_setter = topo_sort_default_setter;
revs->topo_getter = topo_sort_default_getter;
revs->commit_format = CMIT_FMT_DEFAULT; revs->commit_format = CMIT_FMT_DEFAULT;
diff_setup(&revs->diffopt); diff_setup(&revs->diffopt);
@ -994,6 +1012,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->topo_order = 1; revs->topo_order = 1;
continue; continue;
} }
if (!prefixcmp(arg, "--early-output")) {
int count = 100;
switch (arg[14]) {
case '=':
count = atoi(arg+15);
/* Fallthrough */
case 0:
revs->topo_order = 1;
revs->early_output = count;
continue;
}
}
if (!strcmp(arg, "--parents")) { if (!strcmp(arg, "--parents")) {
revs->parents = 1; revs->parents = 1;
continue; continue;
@ -1252,7 +1282,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
diff_tree_setup_paths(revs->prune_data, &revs->pruning); diff_tree_setup_paths(revs->prune_data, &revs->pruning);
/* Can't prune commits with rename following: the paths change.. */ /* Can't prune commits with rename following: the paths change.. */
if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))
revs->prune_fn = try_to_simplify_commit; revs->prune = 1;
if (!revs->full_diff) if (!revs->full_diff)
diff_tree_setup_paths(revs->prune_data, &revs->diffopt); diff_tree_setup_paths(revs->prune_data, &revs->diffopt);
} }
@ -1303,9 +1333,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_fn(&revs->commits, revs->lifo, sort_in_topological_order(&revs->commits, revs->lifo);
revs->topo_setter,
revs->topo_getter);
return 0; return 0;
} }
@ -1324,7 +1352,9 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp
return rewrite_one_error; return rewrite_one_error;
if (p->parents && p->parents->next) if (p->parents && p->parents->next)
return rewrite_one_ok; return rewrite_one_ok;
if (p->object.flags & (TREECHANGE | UNINTERESTING)) if (p->object.flags & UNINTERESTING)
return rewrite_one_ok;
if (!(p->object.flags & TREESAME))
return rewrite_one_ok; return rewrite_one_ok;
if (!p->parents) if (!p->parents)
return rewrite_one_noparents; return rewrite_one_noparents;
@ -1381,6 +1411,36 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
commit->buffer, strlen(commit->buffer)); commit->buffer, strlen(commit->buffer));
} }
enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
{
if (commit->object.flags & SHOWN)
return commit_ignore;
if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed))
return commit_ignore;
if (commit->object.flags & UNINTERESTING)
return commit_ignore;
if (revs->min_age != -1 && (commit->date > revs->min_age))
return commit_ignore;
if (revs->no_merges && commit->parents && commit->parents->next)
return commit_ignore;
if (!commit_match(commit, revs))
return commit_ignore;
if (revs->prune && revs->dense) {
/* Commit without changes? */
if (commit->object.flags & TREESAME) {
/* drop merges unless we want parenthood */
if (!revs->parents)
return commit_ignore;
/* non-merge - always ignore it */
if (!commit->parents || !commit->parents->next)
return commit_ignore;
}
if (revs->parents && rewrite_parents(revs, commit) < 0)
return commit_error;
}
return commit_show;
}
static struct commit *get_revision_1(struct rev_info *revs) static struct commit *get_revision_1(struct rev_info *revs)
{ {
if (!revs->commits) if (!revs->commits)
@ -1408,36 +1468,15 @@ static struct commit *get_revision_1(struct rev_info *revs)
if (add_parents_to_list(revs, commit, &revs->commits) < 0) if (add_parents_to_list(revs, commit, &revs->commits) < 0)
return NULL; return NULL;
} }
if (commit->object.flags & SHOWN)
continue;
if (revs->unpacked && has_sha1_pack(commit->object.sha1, switch (simplify_commit(revs, commit)) {
revs->ignore_packed)) case commit_ignore:
continue;
if (commit->object.flags & UNINTERESTING)
continue; continue;
if (revs->min_age != -1 && (commit->date > revs->min_age)) case commit_error:
continue; return NULL;
if (revs->no_merges && default:
commit->parents && commit->parents->next) return commit;
continue;
if (!commit_match(commit, revs))
continue;
if (revs->prune_fn && revs->dense) {
/* Commit without changes? */
if (!(commit->object.flags & TREECHANGE)) {
/* drop merges unless we want parenthood */
if (!revs->parents)
continue;
/* non-merge - always ignore it */
if (!commit->parents || !commit->parents->next)
continue;
}
if (revs->parents && rewrite_parents(revs, commit) < 0)
return NULL;
} }
return commit;
} while (revs->commits); } while (revs->commits);
return NULL; return NULL;
} }

View File

@ -3,19 +3,18 @@
#define SEEN (1u<<0) #define SEEN (1u<<0)
#define UNINTERESTING (1u<<1) #define UNINTERESTING (1u<<1)
#define TREECHANGE (1u<<2) #define TREESAME (1u<<2)
#define SHOWN (1u<<3) #define SHOWN (1u<<3)
#define TMP_MARK (1u<<4) /* for isolated cases; clean after use */ #define TMP_MARK (1u<<4) /* for isolated cases; clean after use */
#define BOUNDARY (1u<<5) #define BOUNDARY (1u<<5)
#define CHILD_SHOWN (1u<<6) #define CHILD_SHOWN (1u<<6)
#define ADDED (1u<<7) /* Parents already parsed and added? */ #define ADDED (1u<<7) /* Parents already parsed and added? */
#define SYMMETRIC_LEFT (1u<<8) #define SYMMETRIC_LEFT (1u<<8)
#define TOPOSORT (1u<<9) /* In the active toposort list.. */
struct rev_info; struct rev_info;
struct log_info; struct log_info;
typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
struct rev_info { struct rev_info {
/* Starting list */ /* Starting list */
struct commit_list *commits; struct commit_list *commits;
@ -27,10 +26,11 @@ struct rev_info {
/* Basic information */ /* Basic information */
const char *prefix; const char *prefix;
void *prune_data; void *prune_data;
prune_fn_t *prune_fn; unsigned int early_output;
/* Traversal flags */ /* Traversal flags */
unsigned int dense:1, unsigned int dense:1,
prune:1,
no_merges:1, no_merges:1,
no_walk:1, no_walk:1,
remove_empty_trees:1, remove_empty_trees:1,
@ -96,9 +96,6 @@ struct rev_info {
struct diff_options diffopt; struct diff_options diffopt;
struct diff_options pruning; struct diff_options pruning;
topo_sort_set_fn_t topo_setter;
topo_sort_get_fn_t topo_getter;
struct reflog_walk_info *reflog_info; struct reflog_walk_info *reflog_info;
}; };
@ -107,6 +104,8 @@ struct rev_info {
#define REV_TREE_DIFFERENT 2 #define REV_TREE_DIFFERENT 2
/* revision.c */ /* revision.c */
typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *);
volatile show_early_output_fn_t show_early_output;
extern void init_revisions(struct rev_info *revs, const char *prefix); extern void init_revisions(struct rev_info *revs, const char *prefix);
extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def); extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);
@ -131,4 +130,12 @@ extern void add_object(struct object *obj,
extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name); extern void add_pending_object(struct rev_info *revs, struct object *obj, const char *name);
enum commit_action {
commit_ignore,
commit_show,
commit_error
};
extern enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit);
#endif #endif