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