]>
Commit | Line | Data |
---|---|---|
84fe9720 | 1 | #include "cache.h" |
5873b67e | 2 | #include "commit.h" |
84fe9720 | 3 | |
28258afe | 4 | /* |
458754a9 LT |
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. | |
28258afe | 8 | */ |
458754a9 | 9 | #define MAX_COMMITS 16 |
ea84480f LT |
10 | #define REACHABLE (1U << 16) |
11 | ||
12 | #define cmit_flags(cmit) ((cmit)->object.flags & ~REACHABLE) | |
28258afe LT |
13 | |
14 | static int show_edges = 0; | |
727ff277 | 15 | static int basemask = 0; |
97d9c3cd | 16 | |
84fe9720 LT |
17 | static void read_cache_file(const char *path) |
18 | { | |
5873b67e | 19 | die("no revtree cache file yet"); |
84fe9720 LT |
20 | } |
21 | ||
22 | /* | |
28258afe LT |
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 | */ | |
5873b67e | 31 | static int interesting(struct commit *rev) |
28258afe | 32 | { |
ea84480f | 33 | unsigned mask = cmit_flags(rev); |
28258afe LT |
34 | |
35 | if (!mask) | |
36 | return 0; | |
37 | if (show_edges) { | |
5873b67e | 38 | struct commit_list *p = rev->parents; |
28258afe | 39 | while (p) { |
ea84480f | 40 | if (mask != cmit_flags(p->item)) |
28258afe LT |
41 | return 1; |
42 | p = p->next; | |
43 | } | |
44 | return 0; | |
45 | } | |
727ff277 DW |
46 | if (mask & basemask) |
47 | return 0; | |
48 | ||
28258afe LT |
49 | return 1; |
50 | } | |
51 | ||
52 | /* | |
667bb59b | 53 | * Usage: git-rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id2>] |
84fe9720 LT |
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 | */ | |
59 | int main(int argc, char **argv) | |
60 | { | |
61 | int i; | |
28258afe LT |
62 | int nr = 0; |
63 | unsigned char sha1[MAX_COMMITS][20]; | |
ea84480f | 64 | struct commit_list *list = NULL; |
84fe9720 | 65 | |
28258afe LT |
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]; | |
ea84480f | 72 | struct commit *commit; |
28258afe LT |
73 | |
74 | if (!strcmp(arg, "--cache")) { | |
94dfb7f2 | 75 | read_cache_file(argv[++i]); |
28258afe LT |
76 | continue; |
77 | } | |
78 | ||
79 | if (!strcmp(arg, "--edges")) { | |
80 | show_edges = 1; | |
84fe9720 LT |
81 | continue; |
82 | } | |
28258afe | 83 | |
727ff277 DW |
84 | if (arg[0] == '^') { |
85 | arg++; | |
86 | basemask |= 1<<nr; | |
87 | } | |
3c249c95 | 88 | if (nr >= MAX_COMMITS || get_sha1(arg, sha1[nr])) |
667bb59b | 89 | usage("git-rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id>]"); |
ea84480f LT |
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); | |
28258afe | 95 | nr++; |
84fe9720 LT |
96 | } |
97 | ||
ea84480f LT |
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 | ||
28258afe LT |
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++) | |
ea84480f | 111 | mark_reachable(&lookup_commit_reference(sha1[i])->object, 1 << i); |
28258afe LT |
112 | |
113 | /* | |
114 | * Now print out the results.. | |
115 | */ | |
5873b67e DB |
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; | |
97d9c3cd | 125 | |
5873b67e | 126 | if (!interesting(commit)) |
28258afe LT |
127 | continue; |
128 | ||
ea84480f LT |
129 | printf("%lu %s:%d", commit->date, sha1_to_hex(obj->sha1), |
130 | cmit_flags(commit)); | |
5873b67e | 131 | p = commit->parents; |
97d9c3cd | 132 | while (p) { |
5873b67e | 133 | printf(" %s:%d", sha1_to_hex(p->item->object.sha1), |
ea84480f | 134 | cmit_flags(p->item)); |
97d9c3cd LT |
135 | p = p->next; |
136 | } | |
137 | printf("\n"); | |
84fe9720 LT |
138 | } |
139 | return 0; | |
140 | } |