[PATCH] clone-pack.c:write_one_ref() - Create leading directories.
[git.git] / rev-list.c
1 #include "cache.h"
2 #include "tag.h"
3 #include "commit.h"
4 #include "tree.h"
5 #include "blob.h"
6 #include "epoch.h"
7
8 #define SEEN            (1u << 0)
9 #define INTERESTING     (1u << 1)
10 #define COUNTED         (1u << 2)
11 #define SHOWN           (1u << 3)
12 #define DUPCHECK        (1u << 4)
13
14 static const char rev_list_usage[] =
15         "usage: git-rev-list [OPTION] commit-id <commit-id>\n"
16                       "  --max-count=nr\n"
17                       "  --max-age=epoch\n"
18                       "  --min-age=epoch\n"
19                       "  --bisect\n"
20                       "  --objects\n"
21                       "  --unpacked\n"
22                       "  --header\n"
23                       "  --pretty\n"
24                       "  --merge-order [ --show-breaks ]";
25
26 static int unpacked = 0;
27 static int bisect_list = 0;
28 static int tag_objects = 0;
29 static int tree_objects = 0;
30 static int blob_objects = 0;
31 static int verbose_header = 0;
32 static int show_parents = 0;
33 static int hdr_termination = 0;
34 static const char *prefix = "";
35 static unsigned long max_age = -1;
36 static unsigned long min_age = -1;
37 static int max_count = -1;
38 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
39 static int merge_order = 0;
40 static int show_breaks = 0;
41 static int stop_traversal = 0;
42 static int topo_order = 0;
43
44 static void show_commit(struct commit *commit)
45 {
46         commit->object.flags |= SHOWN;
47         if (show_breaks) {
48                 prefix = "| ";
49                 if (commit->object.flags & DISCONTINUITY) {
50                         prefix = "^ ";     
51                 } else if (commit->object.flags & BOUNDARY) {
52                         prefix = "= ";
53                 } 
54         }                       
55         printf("%s%s", prefix, sha1_to_hex(commit->object.sha1));
56         if (show_parents) {
57                 struct commit_list *parents = commit->parents;
58                 while (parents) {
59                         printf(" %s", sha1_to_hex(parents->item->object.sha1));
60                         parents = parents->next;
61                 }
62         }
63         putchar('\n');
64         if (verbose_header) {
65                 static char pretty_header[16384];
66                 pretty_print_commit(commit_format, commit->buffer, ~0, pretty_header, sizeof(pretty_header));
67                 printf("%s%c", pretty_header, hdr_termination);
68         }
69         fflush(stdout);
70 }
71
72 static int filter_commit(struct commit * commit)
73 {
74         if (stop_traversal && (commit->object.flags & BOUNDARY))
75                 return STOP;
76         if (commit->object.flags & (UNINTERESTING|SHOWN))
77                 return CONTINUE;
78         if (min_age != -1 && (commit->date > min_age))
79                 return CONTINUE;
80         if (max_age != -1 && (commit->date < max_age)) {
81                 stop_traversal=1;
82                 return merge_order?CONTINUE:STOP;
83         }
84         if (max_count != -1 && !max_count--)
85                 return STOP;
86         return DO;
87 }
88
89 static int process_commit(struct commit * commit)
90 {
91         int action=filter_commit(commit);
92
93         if (action == STOP) {
94                 return STOP;
95         }
96
97         if (action == CONTINUE) {
98                 return CONTINUE;
99         }
100
101         show_commit(commit);
102
103         return CONTINUE;
104 }
105
106 static struct object_list **add_object(struct object *obj, struct object_list **p, const char *name)
107 {
108         struct object_list *entry = xmalloc(sizeof(*entry));
109         entry->item = obj;
110         entry->next = *p;
111         entry->name = name;
112         *p = entry;
113         return &entry->next;
114 }
115
116 static struct object_list **process_blob(struct blob *blob, struct object_list **p, const char *name)
117 {
118         struct object *obj = &blob->object;
119
120         if (!blob_objects)
121                 return p;
122         if (obj->flags & (UNINTERESTING | SEEN))
123                 return p;
124         obj->flags |= SEEN;
125         return add_object(obj, p, name);
126 }
127
128 static struct object_list **process_tree(struct tree *tree, struct object_list **p, const char *name)
129 {
130         struct object *obj = &tree->object;
131         struct tree_entry_list *entry;
132
133         if (!tree_objects)
134                 return p;
135         if (obj->flags & (UNINTERESTING | SEEN))
136                 return p;
137         if (parse_tree(tree) < 0)
138                 die("bad tree object %s", sha1_to_hex(obj->sha1));
139         obj->flags |= SEEN;
140         p = add_object(obj, p, name);
141         for (entry = tree->entries ; entry ; entry = entry->next) {
142                 if (entry->directory)
143                         p = process_tree(entry->item.tree, p, entry->name);
144                 else
145                         p = process_blob(entry->item.blob, p, entry->name);
146         }
147         return p;
148 }
149
150 static struct object_list *pending_objects = NULL;
151
152 static void show_commit_list(struct commit_list *list)
153 {
154         struct object_list *objects = NULL, **p = &objects, *pending;
155         while (list) {
156                 struct commit *commit = pop_most_recent_commit(&list, SEEN);
157
158                 p = process_tree(commit->tree, p, "");
159                 if (process_commit(commit) == STOP)
160                         break;
161         }
162         for (pending = pending_objects; pending; pending = pending->next) {
163                 struct object *obj = pending->item;
164                 const char *name = pending->name;
165                 if (obj->flags & (UNINTERESTING | SEEN))
166                         continue;
167                 if (obj->type == tag_type) {
168                         obj->flags |= SEEN;
169                         p = add_object(obj, p, name);
170                         continue;
171                 }
172                 if (obj->type == tree_type) {
173                         p = process_tree((struct tree *)obj, p, name);
174                         continue;
175                 }
176                 if (obj->type == blob_type) {
177                         p = process_blob((struct blob *)obj, p, name);
178                         continue;
179                 }
180                 die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
181         }
182         while (objects) {
183                 printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name);
184                 objects = objects->next;
185         }
186 }
187
188 static void mark_blob_uninteresting(struct blob *blob)
189 {
190         if (!blob_objects)
191                 return;
192         if (blob->object.flags & UNINTERESTING)
193                 return;
194         blob->object.flags |= UNINTERESTING;
195 }
196
197 static void mark_tree_uninteresting(struct tree *tree)
198 {
199         struct object *obj = &tree->object;
200         struct tree_entry_list *entry;
201
202         if (!tree_objects)
203                 return;
204         if (obj->flags & UNINTERESTING)
205                 return;
206         obj->flags |= UNINTERESTING;
207         if (parse_tree(tree) < 0)
208                 die("bad tree %s", sha1_to_hex(obj->sha1));
209         entry = tree->entries;
210         while (entry) {
211                 if (entry->directory)
212                         mark_tree_uninteresting(entry->item.tree);
213                 else
214                         mark_blob_uninteresting(entry->item.blob);
215                 entry = entry->next;
216         }
217 }
218
219 static void mark_parents_uninteresting(struct commit *commit)
220 {
221         struct commit_list *parents = commit->parents;
222
223         if (tree_objects)
224                 mark_tree_uninteresting(commit->tree);
225         while (parents) {
226                 struct commit *commit = parents->item;
227                 commit->object.flags |= UNINTERESTING;
228                 parents = parents->next;
229         }
230 }
231
232 static int everybody_uninteresting(struct commit_list *list)
233 {
234         while (list) {
235                 struct commit *commit = list->item;
236                 list = list->next;
237                 if (commit->object.flags & UNINTERESTING)
238                         continue;
239                 return 0;
240         }
241         return 1;
242 }
243
244 /*
245  * This is a truly stupid algorithm, but it's only
246  * used for bisection, and we just don't care enough.
247  *
248  * We care just barely enough to avoid recursing for
249  * non-merge entries.
250  */
251 static int count_distance(struct commit_list *entry)
252 {
253         int nr = 0;
254
255         while (entry) {
256                 struct commit *commit = entry->item;
257                 struct commit_list *p;
258
259                 if (commit->object.flags & (UNINTERESTING | COUNTED))
260                         break;
261                 nr++;
262                 commit->object.flags |= COUNTED;
263                 p = commit->parents;
264                 entry = p;
265                 if (p) {
266                         p = p->next;
267                         while (p) {
268                                 nr += count_distance(p);
269                                 p = p->next;
270                         }
271                 }
272         }
273         return nr;
274 }
275
276 static void clear_distance(struct commit_list *list)
277 {
278         while (list) {
279                 struct commit *commit = list->item;
280                 commit->object.flags &= ~COUNTED;
281                 list = list->next;
282         }
283 }
284
285 static struct commit_list *find_bisection(struct commit_list *list)
286 {
287         int nr, closest;
288         struct commit_list *p, *best;
289
290         nr = 0;
291         p = list;
292         while (p) {
293                 nr++;
294                 p = p->next;
295         }
296         closest = 0;
297         best = list;
298
299         p = list;
300         while (p) {
301                 int distance = count_distance(p);
302                 clear_distance(list);
303                 if (nr - distance < distance)
304                         distance = nr - distance;
305                 if (distance > closest) {
306                         best = p;
307                         closest = distance;
308                 }
309                 p = p->next;
310         }
311         if (best)
312                 best->next = NULL;
313         return best;
314 }
315
316 static struct commit_list *limit_list(struct commit_list *list)
317 {
318         struct commit_list *newlist = NULL;
319         struct commit_list **p = &newlist;
320         while (list) {
321                 struct commit *commit = pop_most_recent_commit(&list, SEEN);
322                 struct object *obj = &commit->object;
323
324                 if (unpacked && has_sha1_pack(obj->sha1))
325                         obj->flags |= UNINTERESTING;
326                 if (obj->flags & UNINTERESTING) {
327                         mark_parents_uninteresting(commit);
328                         if (everybody_uninteresting(list))
329                                 break;
330                         continue;
331                 }
332                 p = &commit_list_insert(commit, p)->next;
333         }
334         if (bisect_list)
335                 newlist = find_bisection(newlist);
336         return newlist;
337 }
338
339 static void add_pending_object(struct object *obj, const char *name)
340 {
341         add_object(obj, &pending_objects, name);
342 }
343
344 static struct commit *get_commit_reference(const char *name, unsigned int flags)
345 {
346         unsigned char sha1[20];
347         struct object *object;
348
349         if (get_sha1(name, sha1))
350                 usage(rev_list_usage);
351         object = parse_object(sha1);
352         if (!object)
353                 die("bad object %s", name);
354
355         /*
356          * Tag object? Look what it points to..
357          */
358         if (object->type == tag_type) {
359                 struct tag *tag = (struct tag *) object;
360                 object->flags |= flags;
361                 if (tag_objects && !(object->flags & UNINTERESTING))
362                         add_pending_object(object, tag->tag);
363                 object = tag->tagged;
364         }
365
366         /*
367          * Commit object? Just return it, we'll do all the complex
368          * reachability crud.
369          */
370         if (object->type == commit_type) {
371                 struct commit *commit = (struct commit *)object;
372                 object->flags |= flags;
373                 if (parse_commit(commit) < 0)
374                         die("unable to parse commit %s", name);
375                 return commit;
376         }
377
378         /*
379          * Tree object? Either mark it uniniteresting, or add it
380          * to the list of objects to look at later..
381          */
382         if (object->type == tree_type) {
383                 struct tree *tree = (struct tree *)object;
384                 if (!tree_objects)
385                         return NULL;
386                 if (flags & UNINTERESTING) {
387                         mark_tree_uninteresting(tree);
388                         return NULL;
389                 }
390                 add_pending_object(object, "");
391                 return NULL;
392         }
393
394         /*
395          * Blob object? You know the drill by now..
396          */
397         if (object->type == blob_type) {
398                 struct blob *blob = (struct blob *)object;
399                 if (!blob_objects)
400                         return NULL;
401                 if (flags & UNINTERESTING) {
402                         mark_blob_uninteresting(blob);
403                         return NULL;
404                 }
405                 add_pending_object(object, "");
406                 return NULL;
407         }
408         die("%s is unknown object", name);
409 }
410
411 int main(int argc, char **argv)
412 {
413         struct commit_list *list = NULL;
414         struct commit_list *(*insert)(struct commit *, struct commit_list **);
415         int i, limited = 0;
416
417         insert = insert_by_date;
418         for (i = 1 ; i < argc; i++) {
419                 int flags;
420                 char *arg = argv[i];
421                 struct commit *commit;
422
423                 if (!strncmp(arg, "--max-count=", 12)) {
424                         max_count = atoi(arg + 12);
425                         continue;
426                 }
427                 if (!strncmp(arg, "--max-age=", 10)) {
428                         max_age = atoi(arg + 10);
429                         continue;
430                 }
431                 if (!strncmp(arg, "--min-age=", 10)) {
432                         min_age = atoi(arg + 10);
433                         continue;
434                 }
435                 if (!strcmp(arg, "--header")) {
436                         verbose_header = 1;
437                         continue;
438                 }
439                 if (!strncmp(arg, "--pretty", 8)) {
440                         commit_format = get_commit_format(arg+8);
441                         verbose_header = 1;
442                         hdr_termination = '\n';
443                         prefix = "commit ";
444                         continue;
445                 }
446                 if (!strcmp(arg, "--parents")) {
447                         show_parents = 1;
448                         continue;
449                 }
450                 if (!strcmp(arg, "--bisect")) {
451                         bisect_list = 1;
452                         continue;
453                 }
454                 if (!strcmp(arg, "--objects")) {
455                         tag_objects = 1;
456                         tree_objects = 1;
457                         blob_objects = 1;
458                         continue;
459                 }
460                 if (!strcmp(arg, "--unpacked")) {
461                         unpacked = 1;
462                         limited = 1;
463                         continue;
464                 }
465                 if (!strcmp(arg, "--merge-order")) {
466                         merge_order = 1;
467                         insert = commit_list_insert;
468                         continue;
469                 }
470                 if (!strcmp(arg, "--show-breaks")) {
471                         show_breaks = 1;
472                         continue;
473                 }
474                 if (!strcmp(arg, "--topo-order")) {
475                         topo_order = 1;
476                         continue;
477                 }
478
479                 flags = 0;
480                 if (*arg == '^') {
481                         flags = UNINTERESTING;
482                         arg++;
483                         limited = 1;
484                 }
485                 if (show_breaks && !merge_order)
486                         usage(rev_list_usage);
487                 commit = get_commit_reference(arg, flags);
488                 if (!commit)
489                         continue;
490                 if (commit->object.flags & DUPCHECK)
491                         continue;
492                 commit->object.flags |= DUPCHECK;
493                 insert(commit, &list);
494         }
495
496         if (!merge_order) {             
497                 if (limited)
498                         list = limit_list(list);
499                 if (topo_order)
500                         sort_in_topological_order(&list);
501                 show_commit_list(list);
502         } else {
503                 if (sort_list_in_merge_order(list, &process_commit)) {
504                           die("merge order sort failed\n");
505                 }
506         }
507
508         return 0;
509 }