rev-tree.con commit git-rev-tree: teach it about tag references (ea84480)
   1#include "cache.h"
   2#include "commit.h"
   3
   4/*
   5 * revision.h leaves the low 16 bits of the "flags" field of the
   6 * revision data structure unused. We use it for a "reachable from
   7 * this commit <N>" bitmask.
   8 */
   9#define MAX_COMMITS 16
  10#define REACHABLE (1U << 16)
  11
  12#define cmit_flags(cmit) ((cmit)->object.flags & ~REACHABLE)
  13
  14static int show_edges = 0;
  15static int basemask = 0;
  16
  17static void read_cache_file(const char *path)
  18{
  19        die("no revtree cache file yet");
  20}
  21
  22/*
  23 * Some revisions are less interesting than others.
  24 *
  25 * For example, if we use a cache-file, that one may contain
  26 * revisions that were never used. They are never interesting.
  27 *
  28 * And sometimes we're only interested in "edge" commits, ie
  29 * places where the marking changes between parent and child.
  30 */
  31static int interesting(struct commit *rev)
  32{
  33        unsigned mask = cmit_flags(rev);
  34
  35        if (!mask)
  36                return 0;
  37        if (show_edges) {
  38                struct commit_list *p = rev->parents;
  39                while (p) {
  40                        if (mask != cmit_flags(p->item))
  41                                return 1;
  42                        p = p->next;
  43                }
  44                return 0;
  45        }
  46        if (mask & basemask)
  47                return 0;
  48
  49        return 1;
  50}
  51
  52/*
  53 * Usage: git-rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id2>]
  54 *
  55 * The cache-file can be quite important for big trees. This is an
  56 * expensive operation if you have to walk the whole chain of
  57 * parents in a tree with a long revision history.
  58 */
  59int main(int argc, char **argv)
  60{
  61        int i;
  62        int nr = 0;
  63        unsigned char sha1[MAX_COMMITS][20];
  64        struct commit_list *list = NULL;
  65
  66        /*
  67         * First - pick up all the revisions we can (both from
  68         * caches and from commit file chains).
  69         */
  70        for (i = 1; i < argc ; i++) {
  71                char *arg = argv[i];
  72                struct commit *commit;
  73
  74                if (!strcmp(arg, "--cache")) {
  75                        read_cache_file(argv[++i]);
  76                        continue;
  77                }
  78
  79                if (!strcmp(arg, "--edges")) {
  80                        show_edges = 1;
  81                        continue;
  82                }
  83
  84                if (arg[0] == '^') {
  85                        arg++;
  86                        basemask |= 1<<nr;
  87                }
  88                if (nr >= MAX_COMMITS || get_sha1(arg, sha1[nr]))
  89                        usage("git-rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id>]");
  90
  91                commit = lookup_commit_reference(sha1[nr]);
  92                if (!commit || parse_commit(commit) < 0)
  93                        die("bad commit object");
  94                commit_list_insert(commit, &list);
  95                nr++;
  96        }
  97
  98        /*
  99         * Parse all the commits in date order.
 100         *
 101         * We really should stop once we know enough, but that's a
 102         * decision that isn't trivial to make.
 103         */
 104        while (list)
 105                pop_most_recent_commit(&list, REACHABLE);
 106
 107        /*
 108         * Now we have the maximal tree. Walk the different sha files back to the root.
 109         */
 110        for (i = 0; i < nr; i++)
 111                mark_reachable(&lookup_commit_reference(sha1[i])->object, 1 << i);
 112
 113        /*
 114         * Now print out the results..
 115         */
 116        for (i = 0; i < nr_objs; i++) {
 117                struct object *obj = objs[i];
 118                struct commit *commit;
 119                struct commit_list *p;
 120
 121                if (obj->type != commit_type)
 122                        continue;
 123
 124                commit = (struct commit *) obj;
 125
 126                if (!interesting(commit))
 127                        continue;
 128
 129                printf("%lu %s:%d", commit->date, sha1_to_hex(obj->sha1),
 130                                    cmit_flags(commit));
 131                p = commit->parents;
 132                while (p) {
 133                        printf(" %s:%d", sha1_to_hex(p->item->object.sha1), 
 134                               cmit_flags(p->item));
 135                        p = p->next;
 136                }
 137                printf("\n");
 138        }
 139        return 0;
 140}