diff options
-rw-r--r-- | builtin-log.c | 88 | ||||
-rw-r--r-- | revision.c | 63 | ||||
-rw-r--r-- | revision.h | 8 |
3 files changed, 119 insertions, 40 deletions
diff --git a/builtin-log.c b/builtin-log.c index 4e9d0cb69c..981f38872c 100644 --- a/builtin-log.c +++ b/builtin-log.c @@ -77,17 +77,85 @@ 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 & UNINTERESTING) + continue; + if (rev->prune_fn && rev->dense && !(flags & TREECHANGE)) { + if (commit->parents && !commit->parents->next) + continue; + } + 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; - log_tree_commit(revs, commit); + 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; - i--; } + + /* 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) @@ -98,7 +166,6 @@ static void early_output(int signal) static void setup_early_output(struct rev_info *rev) { struct sigaction sa; - struct itimerval v; /* * Set up the signal handler, minimally intrusively: @@ -120,21 +187,16 @@ static void setup_early_output(struct rev_info *rev) * * This is a one-time-only trigger. */ - memset(&v, 0, sizeof(v)); - v.it_value.tv_sec = 0; - v.it_value.tv_usec = 100000; - setitimer(ITIMER_REAL, &v, NULL); + 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); - if (rev->shown_one) { - rev->shown_one = 0; - if (rev->commit_format != CMIT_FMT_ONELINE) - putchar(rev->diffopt.line_termination); - } - printf("Final output:\n"); + show_early_header(rev, "done", n); } static int cmd_log_walk(struct rev_info *rev) diff --git a/revision.c b/revision.c index 26610bb42d..2e6121fa1b 100644 --- a/revision.c +++ b/revision.c @@ -1398,6 +1398,36 @@ static int commit_match(struct commit *commit, struct rev_info *opt) 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_fn && revs->dense) { + /* Commit without changes? */ + if (!(commit->object.flags & TREECHANGE)) { + /* 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) { if (!revs->commits) @@ -1425,36 +1455,15 @@ static struct commit *get_revision_1(struct rev_info *revs) if (add_parents_to_list(revs, commit, &revs->commits) < 0) return NULL; } - if (commit->object.flags & SHOWN) - continue; - - if (revs->unpacked && has_sha1_pack(commit->object.sha1, - revs->ignore_packed)) - continue; - if (commit->object.flags & UNINTERESTING) - continue; - if (revs->min_age != -1 && (commit->date > revs->min_age)) - continue; - if (revs->no_merges && - commit->parents && commit->parents->next) - continue; - if (!commit_match(commit, revs)) + switch (simplify_commit(revs, commit)) { + case commit_ignore: 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; + case commit_error: + return NULL; + default: + return commit; } - return commit; } while (revs->commits); return NULL; } diff --git a/revision.h b/revision.h index d8a5a5021f..2232247be4 100644 --- a/revision.h +++ b/revision.h @@ -133,4 +133,12 @@ extern void add_object(struct object *obj, 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 |