summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2008-04-03 02:12:06 -0700
committerJunio C Hamano <gitster@pobox.com>2008-04-12 19:41:29 -0700
commitf35f5603f4f07c939754743b2a6cf61bb3a4694e (patch)
tree6b7390153bdfe003803e89410d3a4c9d6cbc059e
parentf43e2fd43b50d5a82a34bb3e4f848cb38bf93b7f (diff)
downloadgit-f35f5603f4f07c939754743b2a6cf61bb3a4694e.tar.gz
revision traversal: --children option
This adds a new --children option to the revision machinery. In addition to the list of parents, child commits of each commit are computed and stored as a decoration to each commit. Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r--revision.c40
-rw-r--r--revision.h1
2 files changed, 38 insertions, 3 deletions
diff --git a/revision.c b/revision.c
index ffbed3fbf2..979241eb0d 100644
--- a/revision.c
+++ b/revision.c
@@ -9,6 +9,7 @@
#include "grep.h"
#include "reflog-walk.h"
#include "patch-ids.h"
+#include "decorate.h"
volatile show_early_output_fn_t show_early_output;
@@ -1310,6 +1311,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
revs->no_walk = 0;
continue;
}
+ if (!strcmp(arg, "--children")) {
+ revs->children.name = "children";
+ revs->limited = 1;
+ continue;
+ }
opts = diff_opt_parse(&revs->diffopt, argv+i, argc-i);
if (opts > 0) {
@@ -1395,10 +1401,31 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, const ch
if (revs->reverse && revs->reflog_info)
die("cannot combine --reverse with --walk-reflogs");
-
+ if (revs->parents && revs->children.name)
+ die("cannot combine --parents and --children");
return left;
}
+static void add_child(struct rev_info *revs, struct commit *parent, struct commit *child)
+{
+ struct commit_list *l = xcalloc(1, sizeof(*l));
+
+ l->item = child;
+ l->next = add_decoration(&revs->children, &parent->object, l);
+}
+
+static void set_children(struct rev_info *revs)
+{
+ struct commit_list *l;
+ for (l = revs->commits; l; l = l->next) {
+ struct commit *commit = l->item;
+ struct commit_list *p;
+
+ for (p = commit->parents; p; p = p->next)
+ add_child(revs, p->item, commit);
+ }
+}
+
int prepare_revision_walk(struct rev_info *revs)
{
int nr = revs->pending.nr;
@@ -1427,6 +1454,8 @@ int prepare_revision_walk(struct rev_info *revs)
return -1;
if (revs->topo_order)
sort_in_topological_order(&revs->commits, revs->lifo);
+ if (revs->children.name)
+ set_children(revs);
return 0;
}
@@ -1504,6 +1533,11 @@ static int commit_match(struct commit *commit, struct rev_info *opt)
commit->buffer, strlen(commit->buffer));
}
+static inline int want_ancestry(struct rev_info *revs)
+{
+ return (revs->parents || revs->children.name);
+}
+
enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
{
if (commit->object.flags & SHOWN)
@@ -1524,13 +1558,13 @@ enum commit_action simplify_commit(struct rev_info *revs, struct commit *commit)
/* Commit without changes? */
if (commit->object.flags & TREESAME) {
/* drop merges unless we want parenthood */
- if (!revs->parents)
+ if (!want_ancestry(revs))
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)
+ if (want_ancestry(revs) && rewrite_parents(revs, commit) < 0)
return commit_error;
}
return commit_show;
diff --git a/revision.h b/revision.h
index c8b3b948ec..966116cd5b 100644
--- a/revision.h
+++ b/revision.h
@@ -98,6 +98,7 @@ struct rev_info {
struct diff_options pruning;
struct reflog_walk_info *reflog_info;
+ struct decoration children;
};
#define REV_TREE_SAME 0