Git fork

revision: drop early output option

We added the --early-output feature long ago in cdcefbc971 (Add
"--early-output" log flag for interactive GUI use, 2007-11-03). The idea
was that GUIs could use it to progressively render a history view,
showing something quick-and-inaccurate at first and then enhancing it
later.

But we never documented it, and it appears never to have been used, even
by the projects which initially expressed interest. There was an RFC
patch for gitk to use it:

http://public-inbox.org/git/18221.2285.259487.655684@cargo.ozlabs.ibm.com/

but it was never merged. Likewise QGit had a patch in:

https://lore.kernel.org/git/e5bfff550711040225ne67c907r2023b1354c35f35@mail.gmail.com/

but it was never fully merged (to this day, QGit has a commented-out line to
add "--early-output" to the "log" invocation). Searching for other
mentions on the web or forges like github.com turns up nothing.

Meanwhile, the feature has been broken off and on over the years without
anybody noticing (and naturally, there are no tests, either). From 2011
to 2017 the option didn't even turn on via "--early-output"; this was
fixed in e35b6ac56f (revision.h: turn rev_info.early_output back into an
unsigned int, 2017-06-10).

It worked for a while then, but it does not interact well at all with
commit-graphs (which are turned on by default these days). The main
logic to count early commits is triggered by limit_list(), which we
traditionally invoked when showing output in topo-order (and
--early-output always enables --topo-order). But that changed in
f0d9cc4196 (revision.c: begin refactoring --topo-order logic,
2018-11-01). Now when we have generation numbers, we skip limit_list()
entirely, and the early-output code shows no commits, and just the final
header "Final output: 1 done". Which is syntactically OK, but
semantically wrong: that message should give the total number of commits
we're about to show.

So let's drop the feature. It is extra code that is untested and
undocumented, and makes working on the revision machinery more brittle.

Given the history above, it seems unlikely that anybody is using it (or
has used it), and we can drop it without the usual deprecation period.

A gentler option might be to "soft" drop it: keep accepting the option,
have it imply --topo-order as it does now, print "Final output: 1 done",
and then do our regular traversal. That would keep any hypothetical
caller working. But it doesn't seem worth the hassle to me.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Jeff King and committed by
Junio C Hamano
54b18261 16bd9f20

-154
-129
builtin/log.c
··· 378 378 cmd_log_init_finish(argc, argv, prefix, rev, opt, cfg); 379 379 } 380 380 381 - /* 382 - * This gives a rough estimate for how many commits we 383 - * will print out in the list. 384 - */ 385 - static int estimate_commit_count(struct commit_list *list) 386 - { 387 - int n = 0; 388 - 389 - while (list) { 390 - struct commit *commit = list->item; 391 - unsigned int flags = commit->object.flags; 392 - list = list->next; 393 - if (!(flags & (TREESAME | UNINTERESTING))) 394 - n++; 395 - } 396 - return n; 397 - } 398 - 399 - static void show_early_header(struct rev_info *rev, const char *stage, int nr) 400 - { 401 - if (rev->shown_one) { 402 - rev->shown_one = 0; 403 - if (rev->commit_format != CMIT_FMT_ONELINE) 404 - putchar(rev->diffopt.line_termination); 405 - } 406 - fprintf(rev->diffopt.file, _("Final output: %d %s\n"), nr, stage); 407 - } 408 - 409 - static struct itimerval early_output_timer; 410 - 411 - static void log_show_early(struct rev_info *revs, struct commit_list *list) 412 - { 413 - int i = revs->early_output; 414 - int show_header = 1; 415 - int no_free = revs->diffopt.no_free; 416 - 417 - revs->diffopt.no_free = 0; 418 - sort_in_topological_order(&list, revs->sort_order); 419 - while (list && i) { 420 - struct commit *commit = list->item; 421 - switch (simplify_commit(revs, commit)) { 422 - case commit_show: 423 - if (show_header) { 424 - int n = estimate_commit_count(list); 425 - show_early_header(revs, "incomplete", n); 426 - show_header = 0; 427 - } 428 - log_tree_commit(revs, commit); 429 - i--; 430 - break; 431 - case commit_ignore: 432 - break; 433 - case commit_error: 434 - revs->diffopt.no_free = no_free; 435 - diff_free(&revs->diffopt); 436 - return; 437 - } 438 - list = list->next; 439 - } 440 - 441 - /* Did we already get enough commits for the early output? */ 442 - if (!i) { 443 - revs->diffopt.no_free = 0; 444 - diff_free(&revs->diffopt); 445 - return; 446 - } 447 - 448 - /* 449 - * ..if no, then repeat it twice a second until we 450 - * do. 451 - * 452 - * NOTE! We don't use "it_interval", because if the 453 - * reader isn't listening, we want our output to be 454 - * throttled by the writing, and not have the timer 455 - * trigger every second even if we're blocked on a 456 - * reader! 457 - */ 458 - early_output_timer.it_value.tv_sec = 0; 459 - early_output_timer.it_value.tv_usec = 500000; 460 - setitimer(ITIMER_REAL, &early_output_timer, NULL); 461 - } 462 - 463 - static void early_output(int signal UNUSED) 464 - { 465 - show_early_output = log_show_early; 466 - } 467 - 468 - static void setup_early_output(void) 469 - { 470 - struct sigaction sa; 471 - 472 - /* 473 - * Set up the signal handler, minimally intrusively: 474 - * we only set a single volatile integer word (not 475 - * using sigatomic_t - trying to avoid unnecessary 476 - * system dependencies and headers), and using 477 - * SA_RESTART. 478 - */ 479 - memset(&sa, 0, sizeof(sa)); 480 - sa.sa_handler = early_output; 481 - sigemptyset(&sa.sa_mask); 482 - sa.sa_flags = SA_RESTART; 483 - sigaction(SIGALRM, &sa, NULL); 484 - 485 - /* 486 - * If we can get the whole output in less than a 487 - * tenth of a second, don't even bother doing the 488 - * early-output thing.. 489 - * 490 - * This is a one-time-only trigger. 491 - */ 492 - early_output_timer.it_value.tv_sec = 0; 493 - early_output_timer.it_value.tv_usec = 100000; 494 - setitimer(ITIMER_REAL, &early_output_timer, NULL); 495 - } 496 - 497 - static void finish_early_output(struct rev_info *rev) 498 - { 499 - int n = estimate_commit_count(rev->commits); 500 - signal(SIGALRM, SIG_IGN); 501 - show_early_header(rev, "done", n); 502 - } 503 - 504 381 static int cmd_log_walk_no_free(struct rev_info *rev) 505 382 { 506 383 struct commit *commit; ··· 508 385 int saved_dcctc = 0; 509 386 int result; 510 387 511 - if (rev->early_output) 512 - setup_early_output(); 513 - 514 388 if (prepare_revision_walk(rev)) 515 389 die(_("revision walk setup failed")); 516 - 517 - if (rev->early_output) 518 - finish_early_output(rev); 519 390 520 391 /* 521 392 * For --check and --exit-code, the exit code is based on CHECK_FAILED
-17
revision.c
··· 50 50 #include "parse-options.h" 51 51 #include "wildmatch.h" 52 52 53 - volatile show_early_output_fn_t show_early_output; 54 - 55 53 static char *term_bad; 56 54 static char *term_good; 57 55 ··· 1479 1477 while (original_list) { 1480 1478 struct commit *commit = pop_commit(&original_list); 1481 1479 struct object *obj = &commit->object; 1482 - show_early_output_fn_t show; 1483 1480 1484 1481 if (commit == interesting_cache) 1485 1482 interesting_cache = NULL; ··· 1503 1500 continue; 1504 1501 date = commit->date; 1505 1502 p = &commit_list_insert(commit, p)->next; 1506 - 1507 - show = show_early_output; 1508 - if (!show) 1509 - continue; 1510 - 1511 - show(revs, newlist); 1512 - show_early_output = NULL; 1513 1503 } 1514 1504 if (revs->cherry_pick || revs->cherry_mark) 1515 1505 cherry_pick_list(newlist, revs); ··· 2440 2430 revs->topo_order = 1; 2441 2431 } else if (!strcmp(arg, "--author-date-order")) { 2442 2432 revs->sort_order = REV_SORT_BY_AUTHOR_DATE; 2443 - revs->topo_order = 1; 2444 - } else if (!strcmp(arg, "--early-output")) { 2445 - revs->early_output = 100; 2446 - revs->topo_order = 1; 2447 - } else if (skip_prefix(arg, "--early-output=", &optarg)) { 2448 - if (strtoul_ui(optarg, 10, &revs->early_output) < 0) 2449 - die("'%s': not a non-negative integer", optarg); 2450 2433 revs->topo_order = 1; 2451 2434 } else if (!strcmp(arg, "--parents")) { 2452 2435 revs->rewrite_parents = 1;
-8
revision.h
··· 160 160 /* topo-sort */ 161 161 enum rev_sort_order sort_order; 162 162 163 - unsigned int early_output; 164 - 165 163 unsigned int ignore_missing:1, 166 164 ignore_missing_links:1; 167 165 ··· 552 550 * history simplification is off. 553 551 */ 554 552 struct commit_list *get_saved_parents(struct rev_info *revs, const struct commit *commit); 555 - 556 - /** 557 - * Global for the (undocumented) "--early-output" flag for "git log". 558 - */ 559 - typedef void (*show_early_output_fn_t)(struct rev_info *, struct commit_list *); 560 - extern volatile show_early_output_fn_t show_early_output; 561 553 562 554 #endif