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 voidread_cache_file(const char*path) 15{ 16die("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 intinteresting(struct commit *rev) 29{ 30unsigned mask = rev->object.flags; 31 32if(!mask) 33return0; 34if(show_edges) { 35struct commit_list *p = rev->parents; 36while(p) { 37if(mask != p->item->object.flags) 38return1; 39 p = p->next; 40} 41return0; 42} 43if(mask & basemask) 44return0; 45 46return1; 47} 48 49voidprocess_commit(unsigned char*sha1) 50{ 51struct commit_list *parents; 52struct commit *obj =lookup_commit(sha1); 53 54if(obj && obj->object.parsed) 55return; 56if(!obj ||parse_commit(obj)) 57die("unable to parse commit (%s)",sha1_to_hex(sha1)); 58 59 parents = obj->parents; 60while(parents) { 61process_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 */ 73intmain(int argc,char**argv) 74{ 75int i; 76int nr =0; 77unsigned 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 */ 83for(i =1; i < argc ; i++) { 84char*arg = argv[i]; 85 86if(!strcmp(arg,"--cache")) { 87read_cache_file(argv[++i]); 88continue; 89} 90 91if(!strcmp(arg,"--edges")) { 92 show_edges =1; 93continue; 94} 95 96if(arg[0] =='^') { 97 arg++; 98 basemask |=1<<nr; 99} 100if(nr >= MAX_COMMITS ||get_sha1(arg, sha1[nr])) 101usage("rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id>]"); 102process_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 */ 109for(i =0; i < nr; i++) 110mark_reachable(&lookup_commit(sha1[i])->object,1<< i); 111 112/* 113 * Now print out the results.. 114 */ 115for(i =0; i < nr_objs; i++) { 116struct object *obj = objs[i]; 117struct commit *commit; 118struct commit_list *p; 119 120if(obj->type != commit_type) 121continue; 122 123 commit = (struct commit *) obj; 124 125if(!interesting(commit)) 126continue; 127 128printf("%lu%s:%d", commit->date,sha1_to_hex(obj->sha1), 129 obj->flags); 130 p = commit->parents; 131while(p) { 132printf("%s:%d",sha1_to_hex(p->item->object.sha1), 133 p->item->object.flags); 134 p = p->next; 135} 136printf("\n"); 137} 138return0; 139}