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}