This notices if we aren't in topological order, and replays the history.
Thus avoiding the need to sort history up front.
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
---
See the code and the more complete explanations in [PATCH 0/2]. In
particular, see the last section there about the downsides of this: the
50x expansion of output on the kernel is unacceptable, but if somebody can
make a graphical viewer that can react correctly to the "Replay" thing,
I'm sure I can make the replays themselves happen much more rarely.
builtin-blame.c | 2 +-
builtin-log.c | 35 +++++++++++++++++++++++++++++++++++
log-tree.c | 10 +++++++---
revision.c | 29 ++++++++++++++++++++++-------
revision.h | 6 +++++-
5 files changed, 70 insertions(+), 12 deletions(-)
diff --git a/builtin-blame.c b/builtin-blame.c
index 8432b82..7b6af8c 100644
--- a/builtin-blame.c
+++ b/builtin-blame.c
@@ -1502,7 +1502,7 @@ static void assign_blame(struct scoreboard *sb, struct rev_info *revs, int opt)
else {
commit->object.flags |= UNINTERESTING;
if (commit->object.parsed)
- mark_parents_uninteresting(commit);
+ mark_parents_uninteresting(revs, commit);
}
/* treat root commit as boundary */
if (!commit->parents && !show_root)
diff --git a/builtin-log.c b/builtin-log.c
index e8b982d..10e0821 100644
--- a/builtin-log.c
+++ b/builtin-log.c
@@ -77,6 +77,35 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,
}
}
+static void replay_history(struct rev_info *revs)
+{
+ struct commit_list *entry;
+
+ revs->trigger_replay = 0;
+ while ((entry = revs->shown) != NULL) {
+ struct commit *commit = entry->item;
+ unsigned flags = commit->object.flags;
+
+ /* Undo the SHOWN and FORCE_REPLAY bits */
+ commit->object.flags = flags & ~(SHOWN | FORCE_REPLAY);
+ commit->indegree = 0;
+
+ /* Remove it from the shown list, put it on the commit list */
+ revs->shown = entry->next;
+ entry->next = revs->commits;
+ revs->commits = entry;
+
+ printf("Replay %s\n", sha1_to_hex(commit->object.sha1));
+
+ /* Was this the one that caused us to replay? */
+ if (flags & FORCE_REPLAY)
+ break;
+ }
+
+ /* Ok, sort the list to be replayed properly now.. */
+ sort_in_topological_order(&revs->commits, revs->lifo);
+}
+
static int cmd_log_walk(struct rev_info *rev)
{
struct commit *commit;
@@ -84,6 +113,12 @@ static int cmd_log_walk(struct rev_info *rev)
prepare_revision_walk(rev);
while ((commit = get_revision(rev)) != NULL) {
log_tree_commit(rev, commit);
+
+ if (rev->replay_history) {
+ if (rev->trigger_replay)
+ replay_history(rev);
+ continue;
+ }
if (!rev->reflog_info) {
/* we allow cycles in reflog ancestry */
free(commit->buffer);
diff --git a/log-tree.c b/log-tree.c
index 3763ce9..ce9b887 100644
--- a/log-tree.c
+++ b/log-tree.c
@@ -6,12 +6,16 @@
struct decoration name_decoration = { "object names" };
-static void show_parents(struct commit *commit, int abbrev)
+static void show_parents(struct rev_info *opt, struct commit *commit, int abbrev)
{
struct commit_list *p;
for (p = commit->parents; p ; p = p->next) {
struct commit *parent = p->item;
printf(" %s", diff_unique_abbrev(parent->object.sha1, abbrev));
+ if (parent->object.flags & SHOWN) {
+ opt->trigger_replay = 1;
+ parent->object.flags |= FORCE_REPLAY;
+ }
}
}
@@ -147,7 +151,7 @@ void show_log(struct rev_info *opt, const char *sep)
}
fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit), stdout);
if (opt->parents)
- show_parents(commit, abbrev_commit);
+ show_parents(opt, commit, abbrev_commit);
show_decorations(commit);
putchar(opt->diffopt.line_termination);
return;
@@ -248,7 +252,7 @@ void show_log(struct rev_info *opt, const char *sep)
fputs(diff_unique_abbrev(commit->object.sha1, abbrev_commit),
stdout);
if (opt->parents)
- show_parents(commit, abbrev_commit);
+ show_parents(opt, commit, abbrev_commit);
if (parent)
printf(" (from %s)",
diff_unique_abbrev(parent->object.sha1,
diff --git a/revision.c b/revision.c
index e85b4af..e40bc1c 100644
--- a/revision.c
+++ b/revision.c
@@ -79,7 +79,7 @@ void mark_tree_uninteresting(struct tree *tree)
tree->buffer = NULL;
}
-void mark_parents_uninteresting(struct commit *commit)
+void mark_parents_uninteresting(struct rev_info *revs, struct commit *commit)
{
struct commit_list *parents = commit->parents;
@@ -87,6 +87,10 @@ void mark_parents_uninteresting(struct commit *commit)
struct commit *commit = parents->item;
if (!(commit->object.flags & UNINTERESTING)) {
commit->object.flags |= UNINTERESTING;
+ if (commit->object.flags & SHOWN) {
+ revs->trigger_replay = 1;
+ commit->object.flags |= FORCE_REPLAY;
+ }
/*
* Normally we haven't parsed the parent
@@ -97,7 +101,7 @@ void mark_parents_uninteresting(struct commit *commit)
* to mark its parents recursively too..
*/
if (commit->parents)
- mark_parents_uninteresting(commit);
+ mark_parents_uninteresting(revs, commit);
}
/*
@@ -167,8 +171,9 @@ static struct commit *handle_commit(struct rev_info *revs, struct object *object
die("unable to parse commit %s", name);
if (flags & UNINTERESTING) {
commit->object.flags |= UNINTERESTING;
- mark_parents_uninteresting(commit);
- revs->limited = 1;
+ mark_parents_uninteresting(revs, commit);
+ if (!revs->replay_history)
+ revs->limited = 1;
}
return commit;
}
@@ -399,7 +404,7 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit, str
return -1;
p->object.flags |= UNINTERESTING;
if (p->parents)
- mark_parents_uninteresting(p);
+ mark_parents_uninteresting(revs, p);
if (p->object.flags & SEEN)
continue;
p->object.flags |= SEEN;
@@ -542,7 +547,7 @@ static int limit_list(struct rev_info *revs)
if (add_parents_to_list(revs, commit, &list) < 0)
return -1;
if (obj->flags & UNINTERESTING) {
- mark_parents_uninteresting(commit);
+ mark_parents_uninteresting(revs, commit);
if (everybody_uninteresting(list))
break;
continue;
@@ -995,6 +1000,10 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->parents = 1;
continue;
}
+ if (!strcmp(arg, "--replay")) {
+ revs->replay_history = 1;
+ continue;
+ }
if (!strcmp(arg, "--dense")) {
revs->dense = 1;
continue;
@@ -1386,7 +1395,13 @@ static struct commit *get_revision_1(struct rev_info *revs)
struct commit *commit = entry->item;
revs->commits = entry->next;
- free(entry);
+
+ /* Are we going to potentially replay? */
+ if (revs->replay_history) {
+ entry->next = revs->shown;
+ revs->shown = entry;
+ } else
+ free(entry);
if (revs->reflog_info)
fake_reflog_parent(revs->reflog_info, commit);
diff --git a/revision.h b/revision.h
index 1f64576..75b320d 100644
--- a/revision.h
+++ b/revision.h
@@ -11,6 +11,7 @@
#define ADDED (1u<<7) /* Parents already parsed and added? */
#define SYMMETRIC_LEFT (1u<<8)
#define TOPOSORT (1u<<9) /* In the active toposort list.. */
+#define FORCE_REPLAY (1u<<10) /* This commit was wrong somehow */
struct rev_info;
struct log_info;
@@ -20,6 +21,7 @@ typedef void (prune_fn_t)(struct rev_info *revs, struct commit *commit);
struct rev_info {
/* Starting list */
struct commit_list *commits;
+ struct commit_list *shown;
struct object_array pending;
/* Parents of shown commits */
@@ -36,6 +38,8 @@ struct rev_info {
no_walk:1,
remove_empty_trees:1,
simplify_history:1,
+ replay_history:1,
+ trigger_replay:1,
lifo:1,
topo_order:1,
tag_objects:1,
@@ -113,7 +117,7 @@ extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,
extern int prepare_revision_walk(struct rev_info *revs);
extern struct commit *get_revision(struct rev_info *revs);
-extern void mark_parents_uninteresting(struct commit *commit);
+extern void mark_parents_uninteresting(struct rev_info *revs, struct commit *commit);
extern void mark_tree_uninteresting(struct tree *tree);
struct name_path {
-
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html