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 voidread_cache_file(const char*path) 18{ 19die("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 intinteresting(struct commit *rev) 32{ 33unsigned mask =cmit_flags(rev); 34 35if(!mask) 36return0; 37if(show_edges) { 38struct commit_list *p = rev->parents; 39while(p) { 40if(mask !=cmit_flags(p->item)) 41return1; 42 p = p->next; 43} 44return0; 45} 46if(mask & basemask) 47return0; 48 49return1; 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 */ 59intmain(int argc,char**argv) 60{ 61int i; 62int nr =0; 63unsigned char sha1[MAX_COMMITS][20]; 64struct 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 */ 70for(i =1; i < argc ; i++) { 71char*arg = argv[i]; 72struct commit *commit; 73 74if(!strcmp(arg,"--cache")) { 75read_cache_file(argv[++i]); 76continue; 77} 78 79if(!strcmp(arg,"--edges")) { 80 show_edges =1; 81continue; 82} 83 84if(arg[0] =='^') { 85 arg++; 86 basemask |=1<<nr; 87} 88if(nr >= MAX_COMMITS ||get_sha1(arg, sha1[nr])) 89usage("git-rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id>]"); 90 91 commit =lookup_commit_reference(sha1[nr]); 92if(!commit ||parse_commit(commit) <0) 93die("bad commit object"); 94commit_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 */ 104while(list) 105pop_most_recent_commit(&list, REACHABLE); 106 107/* 108 * Now we have the maximal tree. Walk the different sha files back to the root. 109 */ 110for(i =0; i < nr; i++) 111mark_reachable(&lookup_commit_reference(sha1[i])->object,1<< i); 112 113/* 114 * Now print out the results.. 115 */ 116for(i =0; i < nr_objs; i++) { 117struct object *obj = objs[i]; 118struct commit *commit; 119struct commit_list *p; 120 121if(obj->type != commit_type) 122continue; 123 124 commit = (struct commit *) obj; 125 126if(!interesting(commit)) 127continue; 128 129printf("%lu%s:%d", commit->date,sha1_to_hex(obj->sha1), 130cmit_flags(commit)); 131 p = commit->parents; 132while(p) { 133printf("%s:%d",sha1_to_hex(p->item->object.sha1), 134cmit_flags(p->item)); 135 p = p->next; 136} 137printf("\n"); 138} 139return0; 140}