revision traversal: --children option
authorJunio C Hamano <gitster@pobox.com>
Thu, 3 Apr 2008 09:12:06 +0000 (02:12 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 13 Apr 2008 02:41:29 +0000 (19:41 -0700)
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>
revision.c
revision.h

index ffbed3fbf22c22b8862c49bdddd10cab201f86a2..979241eb0dd7a3fe0123c2c9af9c06ad77d3ac52 100644 (file)
@@ -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;
index c8b3b948ecc1cc8b45859a6e1ea11763addfb8b5..966116cd5b107959995b758f120269f579190578 100644 (file)
@@ -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