From 23c17d4a4a0e1fc9a5fa347f1fc6be3cf477e543 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 2 Nov 2007 13:32:58 -0700 Subject: Simplify topo-sort logic .. by not using quite so much indirection. This currently grows the "struct commit" a bit, which could be avoided by using a union for "util" and "indegree" (the topo-sort used to use "util" anyway, so you cannot use them together), but for now the goal of this was to simplify, not optimize. Signed-off-by: Linus Torvalds --- revision.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) (limited to 'revision.c') diff --git a/revision.c b/revision.c index e76da0d448..e85b4af392 100644 --- a/revision.c +++ b/revision.c @@ -677,9 +677,6 @@ void init_revisions(struct rev_info *revs, const char *prefix) 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; diff_setup(&revs->diffopt); @@ -1303,9 +1300,7 @@ int prepare_revision_walk(struct rev_info *revs) if (limit_list(revs) < 0) return -1; if (revs->topo_order) - sort_in_topological_order_fn(&revs->commits, revs->lifo, - revs->topo_setter, - revs->topo_getter); + sort_in_topological_order(&revs->commits, revs->lifo); return 0; } -- cgit v1.2.3 From cdcefbc971d8fcdd293750af7571d4c715f86964 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 3 Nov 2007 11:11:10 -0700 Subject: Add "--early-output" log flag for interactive GUI use 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 Signed-off-by: Junio C Hamano --- revision.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'revision.c') diff --git a/revision.c b/revision.c index e85b4af392..26610bb42d 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; -- cgit v1.2.3 From 252a7c02354a3e2825cfde3c5053a04acc07be9c Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 4 Nov 2007 12:12:05 -0800 Subject: Enhance --early-output format This makes --early-output a bit more advanced, and actually makes it generate multiple "Final output:" headers as it updates things asynchronously. I realize that the "Final output:" line is now illogical, since it's not really final until it also says "done", but It now _always_ generates a "Final output:" header in front of any commit list, and that output header gives you a *guess* at the maximum number of commits available. However, it should be noted that the guess can be completely off: I do a reasonable job estimating it, but it is not meant to be exact. So what happens is that you may get output like this: - at 0.1 seconds: Final output: 2 incomplete .. 2 commits listed .. - half a second later: Final output: 33 incomplete .. 33 commits listed .. - another half a second after that: Final output: 71 incomplete .. 71 commits listed .. - another half second later: Final output: 136 incomplete .. 100 commits listed: we hit the --early-output limit, and .. will only output 100 commits, and after this you'll not .. see an "incomplete" report any more since you got as much .. early output as you asked for! - .. and then finally: Final output: 73106 done .. all the commits .. The above is a real-life scenario on my current kernel tree after having flushed all the caches. Tested with the experimental gitk patch that Paul sent out, and by looking at the actual log output (and verifying that my commit count guesses actually match real life fairly well). Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- revision.c | 63 +++++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 36 insertions(+), 27 deletions(-) (limited to 'revision.c') 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; } -- cgit v1.2.3 From 53b2c823f6e862e0c83a4a25bab43e8c32e9c289 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 5 Nov 2007 13:22:34 -0800 Subject: revision walker: mini clean-up This removes the unnecessary indirection of "revs->prune_fn", since that function is always the same one (or NULL), and there is in fact not even an abstraction reason to make it a function (i.e. its not called from some other file and doesn't allow us to keep the function itself static or anything like that). It then just replaces it with a bit that says "prune or not", and if not pruning, every commit gets TREECHANGE. That in turn means that - if (!revs->prune_fn || (flags & TREECHANGE)) - if (revs->prune_fn && !(flags & TREECHANGE)) just become - if (flags & TREECHANGE) - if (!(flags & TREECHANGE)) respectively. Together with adding the "single_parent()" helper function, the "complex" conditional now becomes if (!(flags & TREECHANGE) && rev->dense && single_parent(commit)) continue; Also indirection of "revs->dense" checking is thrown away the same way, because TREECHANGE bit is set appropriately now. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- revision.c | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'revision.c') diff --git a/revision.c b/revision.c index 2e6121fa1b..931f978af9 100644 --- a/revision.c +++ b/revision.c @@ -308,6 +308,14 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) struct commit_list **pp, *parent; int tree_changed = 0, tree_same = 0; + /* + * If we don't do pruning, everything is interesting + */ + if (!revs->prune) { + commit->object.flags |= TREECHANGE; + return; + } + if (!commit->tree) return; @@ -317,6 +325,15 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) 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) { + commit->object.flags |= TREECHANGE; + return; + } + pp = &commit->parents; while ((parent = *pp) != NULL) { struct commit *p = parent->item; @@ -415,8 +432,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str * simplify the commit history and find the parent * that has no differences in the path set if one exists. */ - if (revs->prune_fn) - revs->prune_fn(revs, commit); + try_to_simplify_commit(revs, commit); if (revs->no_walk) return 0; @@ -684,9 +700,6 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->skip_count = -1; revs->max_count = -1; - revs->prune_fn = NULL; - revs->prune_data = NULL; - revs->commit_format = CMIT_FMT_DEFAULT; diff_setup(&revs->diffopt); @@ -1271,7 +1284,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch diff_tree_setup_paths(revs->prune_data, &revs->pruning); /* Can't prune commits with rename following: the paths change.. */ if (!revs->diffopt.follow_renames) - revs->prune_fn = try_to_simplify_commit; + revs->prune = 1; if (!revs->full_diff) diff_tree_setup_paths(revs->prune_data, &revs->diffopt); } @@ -1412,7 +1425,7 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) return commit_ignore; if (!commit_match(commit, revs)) return commit_ignore; - if (revs->prune_fn && revs->dense) { + if (revs->prune && revs->dense) { /* Commit without changes? */ if (!(commit->object.flags & TREECHANGE)) { /* drop merges unless we want parenthood */ -- cgit v1.2.3 From 8f67f8aefb1b751073f8b36fae8be8f72eb93f4a Mon Sep 17 00:00:00 2001 From: Pierre Habouzit Date: Sat, 10 Nov 2007 20:05:14 +0100 Subject: Make the diff_options bitfields be an unsigned with explicit masks. reverse_diff was a bit-value in disguise, it's merged in the flags now. Signed-off-by: Pierre Habouzit Signed-off-by: Junio C Hamano --- revision.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'revision.c') diff --git a/revision.c b/revision.c index e76da0d448..f5b0e83ee3 100644 --- a/revision.c +++ b/revision.c @@ -250,7 +250,7 @@ static void file_add_remove(struct diff_options *options, } tree_difference = diff; if (tree_difference == REV_TREE_DIFFERENT) - options->has_changes = 1; + DIFF_OPT_SET(options, HAS_CHANGES); } static void file_change(struct diff_options *options, @@ -260,7 +260,7 @@ static void file_change(struct diff_options *options, const char *base, const char *path) { tree_difference = REV_TREE_DIFFERENT; - options->has_changes = 1; + DIFF_OPT_SET(options, HAS_CHANGES); } static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree *t2) @@ -270,7 +270,7 @@ static int rev_compare_tree(struct rev_info *revs, struct tree *t1, struct tree if (!t2) return REV_TREE_DIFFERENT; tree_difference = REV_TREE_SAME; - revs->pruning.has_changes = 0; + DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES); if (diff_tree_sha1(t1->object.sha1, t2->object.sha1, "", &revs->pruning) < 0) return REV_TREE_DIFFERENT; @@ -294,7 +294,7 @@ static int rev_same_tree_as_empty(struct rev_info *revs, struct tree *t1) init_tree_desc(&empty, "", 0); tree_difference = REV_TREE_SAME; - revs->pruning.has_changes = 0; + DIFF_OPT_CLR(&revs->pruning, HAS_CHANGES); retval = diff_tree(&empty, &real, "", &revs->pruning); free(tree); @@ -662,8 +662,8 @@ void init_revisions(struct rev_info *revs, const char *prefix) revs->abbrev = DEFAULT_ABBREV; revs->ignore_merges = 1; revs->simplify_history = 1; - revs->pruning.recursive = 1; - revs->pruning.quiet = 1; + DIFF_OPT_SET(&revs->pruning, RECURSIVE); + DIFF_OPT_SET(&revs->pruning, QUIET); revs->pruning.add_remove = file_add_remove; revs->pruning.change = file_change; revs->lifo = 1; @@ -1054,13 +1054,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch } if (!strcmp(arg, "-r")) { revs->diff = 1; - revs->diffopt.recursive = 1; + DIFF_OPT_SET(&revs->diffopt, RECURSIVE); continue; } if (!strcmp(arg, "-t")) { revs->diff = 1; - revs->diffopt.recursive = 1; - revs->diffopt.tree_in_recursive = 1; + DIFF_OPT_SET(&revs->diffopt, RECURSIVE); + DIFF_OPT_SET(&revs->diffopt, TREE_IN_RECURSIVE); continue; } if (!strcmp(arg, "-m")) { @@ -1242,7 +1242,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch revs->diff = 1; /* Pickaxe and rename following needs diffs */ - if (revs->diffopt.pickaxe || revs->diffopt.follow_renames) + if (revs->diffopt.pickaxe || DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) revs->diff = 1; if (revs->topo_order) @@ -1251,7 +1251,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (revs->prune_data) { diff_tree_setup_paths(revs->prune_data, &revs->pruning); /* Can't prune commits with rename following: the paths change.. */ - if (!revs->diffopt.follow_renames) + if (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) revs->prune_fn = try_to_simplify_commit; if (!revs->full_diff) diff_tree_setup_paths(revs->prune_data, &revs->diffopt); -- cgit v1.2.3 From 4d1012c3709e356107d0fb0e3bf5a39e0d5c209d Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sun, 11 Nov 2007 23:35:23 +0000 Subject: Fix rev-list when showing objects involving submodules The function mark_tree_uninteresting() assumed that the tree entries are blob when they are not trees. This is not so. Since we do not traverse into submodules (yet), the gitlinks should be ignored. In general, we should try to start moving away from using the "S_ISLNK()" like things for internal git state. It was a mistake to just assume the numbers all were same across all systems in the first place. This implementation converts to the "object_type", and then uses a case statement. Noticed by Ilari on IRC. Test script taken from an earlier version by Dscho. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- revision.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'revision.c') diff --git a/revision.c b/revision.c index e76da0d448..e8650c35a7 100644 --- a/revision.c +++ b/revision.c @@ -65,10 +65,17 @@ void mark_tree_uninteresting(struct tree *tree) init_tree_desc(&desc, tree->buffer, tree->size); while (tree_entry(&desc, &entry)) { - if (S_ISDIR(entry.mode)) + switch (object_type(entry.mode)) { + case OBJ_TREE: mark_tree_uninteresting(lookup_tree(entry.sha1)); - else + break; + case OBJ_BLOB: mark_blob_uninteresting(lookup_blob(entry.sha1)); + break; + default: + /* Subproject commit - not in this repository */ + break; + } } /* -- cgit v1.2.3 From 7dc0fe3be5c949e83e96a1b829be0e72eafffb47 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Mon, 12 Nov 2007 23:16:08 -0800 Subject: Fix parent rewriting in --early-output We cannot tell a node that has been checked and found not to be interesting (which does not have the TREECHANGE flag) from a node that hasn't been checked if it is interesting or not, without relying on something else, such as object->parsed. But an object can get the "parsed" flag for other reasons. Which means that "TREECHANGE" has the wrong polarity. This changes the way how the path pruning logic marks an uninteresting commits. From now on, we consider a commit interesting by default, and explicitly mark the ones we decided to prune. The flag is renamed to "TREESAME". Then, this fixes the logic to show the early output with incomplete pruning. It basically says "a commit that has TREESAME set is kind-of-UNINTERESTING", but obviously in a different way than an outright UNINTERESTING commit. Until we parse and examine enough parents to determine if a commit becomes surely "kind-of-UNINTERESTING", we avoid rewriting the ancestry so that later rounds can fix things up. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- revision.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'revision.c') diff --git a/revision.c b/revision.c index 931f978af9..5796153bbd 100644 --- a/revision.c +++ b/revision.c @@ -311,17 +311,15 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) /* * If we don't do pruning, everything is interesting */ - if (!revs->prune) { - commit->object.flags |= TREECHANGE; + if (!revs->prune) return; - } if (!commit->tree) return; if (!commit->parents) { - if (!rev_same_tree_as_empty(revs, commit->tree)) - commit->object.flags |= TREECHANGE; + if (rev_same_tree_as_empty(revs, commit->tree)) + commit->object.flags |= TREESAME; return; } @@ -329,10 +327,8 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) * 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) { - commit->object.flags |= TREECHANGE; + if (!revs->dense && !commit->parents->next) return; - } pp = &commit->parents; while ((parent = *pp) != NULL) { @@ -357,6 +353,7 @@ static void try_to_simplify_commit(struct rev_info *revs, struct commit *commit) } parent->next = NULL; commit->parents = parent; + commit->object.flags |= TREESAME; return; case REV_TREE_NEW: @@ -385,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)); } 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) @@ -1354,7 +1352,9 @@ static enum rewrite_result rewrite_one(struct rev_info *revs, struct commit **pp return rewrite_one_error; if (p->parents && p->parents->next) 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; if (!p->parents) return rewrite_one_noparents; @@ -1427,7 +1427,7 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) return commit_ignore; if (revs->prune && revs->dense) { /* Commit without changes? */ - if (!(commit->object.flags & TREECHANGE)) { + if (commit->object.flags & TREESAME) { /* drop merges unless we want parenthood */ if (!revs->parents) return commit_ignore; -- cgit v1.2.3 From 3384a2dfc12f0fecd25ecfd6bfa9ee0d82517bf2 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Tue, 11 Dec 2007 10:09:04 -0800 Subject: shortlog: default to HEAD when the standard input is a tty Instead of warning the user that it is expecting git log output from the standard input (and waiting for the user to type the log from the keyboard, which is a silly thing to do), default to traverse from HEAD when there is no rev parameter given and the standard input is a tty. This factors out a useful helper "add_head()" from builtin-diff.c to a more appropriate place revision.c while renaming it to more descriptive name add_head_to_pending(), as that is what the function is about. Signed-off-by: Junio C Hamano --- revision.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'revision.c') diff --git a/revision.c b/revision.c index 2a59035192..7e2f4f1eb5 100644 --- a/revision.c +++ b/revision.c @@ -139,6 +139,18 @@ void add_pending_object(struct rev_info *revs, struct object *obj, const char *n add_pending_object_with_mode(revs, obj, name, S_IFINVALID); } +void add_head_to_pending(struct rev_info *revs) +{ + unsigned char sha1[20]; + struct object *obj; + if (get_sha1("HEAD", sha1)) + return; + obj = parse_object(sha1); + if (!obj) + return; + add_pending_object(revs, obj, "HEAD"); +} + static struct object *get_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags) { struct object *object; -- cgit v1.2.3 From 0faf2da7e5ee5c2f472d8a7afaf8616101f34e80 Mon Sep 17 00:00:00 2001 From: Arjen Laarhoven Date: Tue, 25 Dec 2007 12:06:47 +0100 Subject: Fix "git log --diff-filter" bug In commit b7bb760d5ed4881422673d32f869d140221d3564 (Fix revision log diff setup, avoid unnecessary diff generation) an optimization was made to avoid unnecessary diff generation. This was partly fixed in 99516e35d096f41e7133cacde8fbed8ee9a3ecd0 (Fix embarrassing "git log --follow" bug). The '--diff-filter' option also needs the diff machinery in action. Signed-off-by: Arjen Laarhoven Signed-off-by: Junio C Hamano --- revision.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'revision.c') diff --git a/revision.c b/revision.c index 7e2f4f1eb5..6e85aaa3fb 100644 --- a/revision.c +++ b/revision.c @@ -1290,8 +1290,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch if (revs->diffopt.output_format & ~DIFF_FORMAT_NO_OUTPUT) revs->diff = 1; - /* Pickaxe and rename following needs diffs */ - if (revs->diffopt.pickaxe || DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) + /* Pickaxe, diff-filter and rename following need diffs */ + if (revs->diffopt.pickaxe || + revs->diffopt.filter || + DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES)) revs->diff = 1; if (revs->topo_order) -- cgit v1.2.3 From 3131b713013f06285cad3ffdcc61f417ac4ba158 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 9 Feb 2008 14:02:07 -0800 Subject: Add "--show-all" revision walker flag for debugging It's really not very easy to visualize the commit walker, because - on purpose - it obvously doesn't show the uninteresting commits! This adds a "--show-all" flag to the revision walker, which will make it show uninteresting commits too, and they'll have a '^' in front of them (it also fixes a logic error for !verbose_header for boundary commits - we should show the '-' even if left_right isn't shown). A separate patch to gitk to teach it the new '^' was sent to paulus. With the change in place, it actually is interesting even for the cases that git doesn't have any problems with, ie for the kernel you can do: gitk -d --show-all v2.6.24.. and you see just how far down it has to parse things to see it all. The use of "-d" is a good idea, since the date-ordered toposort is much better at showing why it goes deep down (ie the date of some of those commits after 2.6.24 is much older, because they were merged from trees that weren't rebased). So I think this is a useful feature even for non-debugging - just to visualize what git does internally more. When it actually breaks out due to the "everybody_uninteresting()" case, it adds the uninteresting commits (both the one it's looking at now, and the list of pending ones) to the list This way, we really list *all* the commits we've looked at. Because we now end up listing commits we may not even have been parsed at all "show_log" and "show_commit" need to protect against commits that don't have a commit buffer entry. That second part is debatable just how it should work. Maybe we shouldn't show such entries at all (with this patch those entries do get shown, they just don't get any message shown with them). But I think this is a useful case. Signed-off-by: Linus Torvalds Signed-off-by: Junio C Hamano --- revision.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) (limited to 'revision.c') diff --git a/revision.c b/revision.c index 6e85aaa3fb..76faf4b009 100644 --- a/revision.c +++ b/revision.c @@ -558,6 +558,12 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs) free_patch_ids(&ids); } +static void add_to_list(struct commit_list **p, struct commit *commit, struct commit_list *n) +{ + p = &commit_list_insert(commit, p)->next; + *p = n; +} + static int limit_list(struct rev_info *revs) { struct commit_list *list = revs->commits; @@ -579,9 +585,13 @@ static int limit_list(struct rev_info *revs) return -1; if (obj->flags & UNINTERESTING) { mark_parents_uninteresting(commit); - if (everybody_uninteresting(list)) + if (everybody_uninteresting(list)) { + if (revs->show_all) + add_to_list(p, commit, list); break; - continue; + } + if (!revs->show_all) + continue; } if (revs->min_age != -1 && (commit->date > revs->min_age)) continue; @@ -1055,6 +1065,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch revs->dense = 0; continue; } + if (!strcmp(arg, "--show-all")) { + revs->show_all = 1; + continue; + } if (!strcmp(arg, "--remove-empty")) { revs->remove_empty_trees = 1; continue; @@ -1438,6 +1452,8 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit) return commit_ignore; if (revs->unpacked && has_sha1_pack(commit->object.sha1, revs->ignore_packed)) return commit_ignore; + if (revs->show_all) + return commit_show; if (commit->object.flags & UNINTERESTING) return commit_ignore; if (revs->min_age != -1 && (commit->date > revs->min_age)) -- cgit v1.2.3 From c1ee9013ad5acfff47a36899af7d485f6d60fa83 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 18 Feb 2008 21:47:54 +0100 Subject: mark_blob/tree_uninteresting: check for NULL As these functions are directly called with the result from lookup_tree/blob, they must handle NULL. Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- revision.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'revision.c') diff --git a/revision.c b/revision.c index 6e85aaa3fb..484e5e7959 100644 --- a/revision.c +++ b/revision.c @@ -46,6 +46,8 @@ void add_object(struct object *obj, static void mark_blob_uninteresting(struct blob *blob) { + if (!blob) + return; if (blob->object.flags & UNINTERESTING) return; blob->object.flags |= UNINTERESTING; @@ -57,6 +59,8 @@ void mark_tree_uninteresting(struct tree *tree) struct name_entry entry; struct object *obj = &tree->object; + if (!tree) + return; if (obj->flags & UNINTERESTING) return; obj->flags |= UNINTERESTING; -- cgit v1.2.3 From 9684afd967f61047bbf1b3a8039adf7d41916b31 Mon Sep 17 00:00:00 2001 From: Martin Koegler Date: Mon, 18 Feb 2008 21:48:01 +0100 Subject: revision.c: handle tag->tagged == NULL Signed-off-by: Martin Koegler Signed-off-by: Junio C Hamano --- revision.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'revision.c') diff --git a/revision.c b/revision.c index 484e5e7959..b1aebf8999 100644 --- a/revision.c +++ b/revision.c @@ -177,6 +177,8 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object struct tag *tag = (struct tag *) object; if (revs->tag_objects && !(flags & UNINTERESTING)) add_pending_object(revs, object, tag->tag); + if (!tag->tagged) + die("bad tag"); object = parse_object(tag->tagged->sha1); if (!object) die("bad object %s", sha1_to_hex(tag->tagged->sha1)); @@ -689,6 +691,8 @@ static int add_parents_only(struct rev_info *revs, const char *arg, int flags) it = get_reference(revs, arg, sha1, 0); if (it->type != OBJ_TAG) break; + if (!((struct tag*)it)->tagged) + return 0; hashcpy(sha1, ((struct tag*)it)->tagged->sha1); } if (it->type != OBJ_COMMIT) -- cgit v1.2.3