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 11static int show_edges = 0; 12static int basemask = 0; 13 14static 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 */ 28static 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 49void 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 */ 73int 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}