git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[REPLACEMENT PATCH 2/2] Add "--early-output" log flag for interactive GUI use

From
Linus Torvalds <torvalds@linux-foundation.org>
Date
Nov 3, 2007, 18:11 UTC
Message-ID
<alpine.LFD.0.999.0711031103340.3342@woody.linux-foundation.org>
In-Reply-To
<alpine.LFD.0.999.0711021809060.3342@woody.linux-foundation.org>

This adds support for "--early-output[=n]" as a flag to the "git log" family of commands. This allows GUI programs to state that they want to get some output early, in order to be able to show at least something quickly, even if the full output may take longer to generate.

If no count is specified, a default count of a hundred commits will be used, although the actual numbr of commits output may be smaller depending on how many commits were actually found in the first tenth of a second (or if *everything* was found before that, in which case no early output will be provided, and only the final list is made available).

When the full list is generated, there will be a "Final output:" string prepended to it, regardless of whether any early commits were shown or not, so that the consumer can always know the difference between early output and the final list.

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---

This replaces my 2/2 patch from yesterday, but still relies on the topo-sorting cleanups in 1/2 (which are really totally independent, and probably could go in regardless of any of this series).

Instead of having a generic replay mechanism, this one just does *one* replay, and discards even that if it can generate all the commits really quickly.

The timeout right now is set to a pretty aggressive one-tenth-of-a- second, and realistically that could/should probably be longer, but making it short makes sure that we actually trigger this in normal use, so I think this is the right approach for the initial implementation.

Try it out, with
	git log --early-output=2

and look at what happens: if it cannot generate all the commits in the first 0.1 seconds, it will take what it *could* generate, sort it topologically (you can add "--date-order" if you want), and show the first two commits.

When it then generates the rest, it will add a "Final output:" line, and then re-generate it all.

The intent is for a GUI front-end to be able to use the first one-hundred or so commits to populate the commit log, and show the window, and not have to worry about the fact that the rest of the data (how-ever many hundred thousand commits there are) may take much more time to arrive.

So not only is this patch pretty straightforward in itself, I think usage should be pretty straightforward too.

 builtin-log.c |   67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 revision.c    |   22 ++++++++++++++++++
 revision.h    |    4 +++
 3 files changed, 93 insertions(+), 0 deletions(-)
diff --git a/builtin-log.c b/builtin-log.c
index e8b982d..707add2 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -77,11 +77,78 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
 	}
 }
 
+static void log_show_early(struct rev_info *revs, struct commit_list *list)
+{
+	int i = revs->early_output;
+
+	sort_in_topological_order(&list, revs->lifo);
+	while (list && i) {
+		struct commit *commit = list->item;
+		log_tree_commit(revs, commit);
+		list = list->next;
+		i--;
+	}
+}
+
+static void early_output(int signal)
+{
+	show_early_output = log_show_early;
+}
+
+static void setup_early_output(struct rev_info *rev)
+{
+	struct sigaction sa;
+	struct itimerval v;
+
+	/*
+	 * 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.
+	 */
+	memset(&v, 0, sizeof(v));
+	v.it_value.tv_sec = 0;
+	v.it_value.tv_usec = 100000;
+	setitimer(ITIMER_REAL, &v, NULL);
+}
+
+static void finish_early_output(struct rev_info *rev)
+{
+	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");
+}
+
 static int cmd_log_walk(struct rev_info *rev)
 {
 	struct commit *commit;
 
+	if (rev->early_output)
+		setup_early_output(rev);
+
 	prepare_revision_walk(rev);
+
+	if (rev->early_output)
+		finish_early_output(rev);
+
 	while ((commit = get_revision(rev)) != NULL) {
 		log_tree_commit(rev, commit);
 		if (!rev->reflog_info) {
diff --git a/revision.c b/revision.c
index e85b4af..26610bb 100644
--- a/revision.c
+++ b/revision.c
@@ -10,6 +10,8 @@
 #include "reflog-walk.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)
 {
 	struct name_path *p;
@@ -533,6 +535,7 @@ static int limit_list(struct rev_info *revs)
 		struct commit_list *entry = list;
 		struct commit *commit = list->item;
 		struct object *obj = &commit->object;
+		show_early_output_fn_t show;
 
 		list = list->next;
 		free(entry);
@@ -550,6 +553,13 @@ static int limit_list(struct rev_info *revs)
 		if (revs->min_age != -1 && (commit->date > revs->min_age))
 			continue;
 		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)
 		cherry_pick_list(newlist, revs);
@@ -991,6 +1001,18 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
 				revs->topo_order = 1;
 				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")) {
 				revs->parents = 1;
 				continue;
diff --git a/revision.h b/revision.h
index 1f64576..d8a5a50 100644
--- a/revision.h
+++ b/revision.h
@@ -30,6 +30,8 @@ struct rev_info {
 	void *prune_data;
 	prune_fn_t *prune_fn;
 
+	unsigned int early_output;
+
 	/* Traversal flags */
 	unsigned int	dense:1,
 			no_merges:1,
@@ -105,6 +107,8 @@ struct rev_info {
 #define REV_TREE_DIFFERENT	2
 
 /* 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 int setup_revisions(int argc, const char **argv, struct rev_info *revs, const char *def);
Previous: Marco CostalbaNext: Marco Costalba
Message 20 of 57 in “New features in gitk”
  1. Paul MackerrasOct 28, 2007
  2. Linus TorvaldsOct 28, 2007
  3. Paul MackerrasOct 28, 2007
  4. Steffen ProhaskaOct 28, 2007
  5. Linus TorvaldsOct 28, 2007
  6. Paul MackerrasNov 1, 2007
  7. Linus TorvaldsNov 1, 2007
  8. Paul MackerrasNov 2, 2007
  9. Marco CostalbaNov 2, 2007
  10. Linus TorvaldsNov 2, 2007
  11. Marco CostalbaNov 2, 2007
  12. Linus TorvaldsNov 2, 2007
  13. 0/2 History replay supportLinus Torvalds, Nov 2, 2007
  14. 1/2 Simplify topo-sort logicLinus Torvalds, Nov 2, 2007
  15. 2/2 Support "history replay" for git log commandsLinus Torvalds, Nov 2, 2007
  16. Junio C HamanoNov 2, 2007
  17. Linus TorvaldsNov 2, 2007
  18. Linus TorvaldsNov 3, 2007
  19. Marco CostalbaNov 3, 2007
  20. 2/2 Add "--early-output" log flag for interactive GUI useLinus Torvalds, Nov 3, 2007
  21. Marco CostalbaNov 3, 2007
  22. Paul MackerrasNov 4, 2007
  23. Linus TorvaldsNov 4, 2007
  24. Paul MackerrasNov 4, 2007
  25. Marco CostalbaNov 4, 2007
  26. Linus TorvaldsNov 4, 2007
  27. 3/2 Enhance --early-output formatLinus Torvalds, Nov 4, 2007
  28. Junio C HamanoNov 5, 2007
  29. Linus TorvaldsNov 5, 2007
  30. Linus TorvaldsNov 5, 2007
  31. Linus TorvaldsNov 5, 2007
  32. 4/2 Fix parent rewriting in --early-outputLinus Torvalds, Nov 13, 2007
  33. Junio C HamanoNov 13, 2007
  34. Linus TorvaldsNov 13, 2007
  35. Linus TorvaldsNov 13, 2007
  36. Sven VerdoolaegeNov 13, 2007
  37. Junio C HamanoNov 13, 2007
  38. Shawn O. PearceNov 13, 2007
  39. Junio C HamanoNov 13, 2007
  40. Paul MackerrasNov 13, 2007
  41. Junio C HamanoNov 13, 2007
  42. Paul MackerrasNov 13, 2007
  43. Marco CostalbaNov 16, 2007
  44. Paul MackerrasNov 4, 2007
  45. Johannes SchindelinNov 2, 2007
  46. Linus TorvaldsNov 2, 2007
  47. Paul MackerrasNov 1, 2007
  48. Linus TorvaldsNov 1, 2007
  49. Linus TorvaldsNov 1, 2007
  50. Pierre HabouzitOct 28, 2007
  51. Mike HommeyOct 28, 2007
  52. Paul MackerrasOct 28, 2007
  53. Pierre HabouzitOct 29, 2007
  54. Jonathan del StrotherOct 29, 2007
  55. Pierre HabouzitOct 29, 2007
  56. Han-Wen NienhuysOct 29, 2007
  57. Michele BallabioOct 29, 2007

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.