]> asedeno.scripts.mit.edu Git - git.git/blob - builtin-rev-list.c
rev-list: make "bisect_list" variable local to "cmd_rev_list"
[git.git] / builtin-rev-list.c
1 #include "cache.h"
2 #include "refs.h"
3 #include "tag.h"
4 #include "commit.h"
5 #include "tree.h"
6 #include "blob.h"
7 #include "tree-walk.h"
8 #include "diff.h"
9 #include "revision.h"
10 #include "list-objects.h"
11 #include "builtin.h"
12 #include "log-tree.h"
13 #include "graph.h"
14
15 /* bits #0-15 in revision.h */
16
17 #define COUNTED         (1u<<16)
18
19 static const char rev_list_usage[] =
20 "git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
21 "  limiting output:\n"
22 "    --max-count=nr\n"
23 "    --max-age=epoch\n"
24 "    --min-age=epoch\n"
25 "    --sparse\n"
26 "    --no-merges\n"
27 "    --remove-empty\n"
28 "    --all\n"
29 "    --branches\n"
30 "    --tags\n"
31 "    --remotes\n"
32 "    --stdin\n"
33 "    --quiet\n"
34 "  ordering output:\n"
35 "    --topo-order\n"
36 "    --date-order\n"
37 "    --reverse\n"
38 "  formatting output:\n"
39 "    --parents\n"
40 "    --children\n"
41 "    --objects | --objects-edge\n"
42 "    --unpacked\n"
43 "    --header | --pretty\n"
44 "    --abbrev=nr | --no-abbrev\n"
45 "    --abbrev-commit\n"
46 "    --left-right\n"
47 "  special purpose:\n"
48 "    --bisect\n"
49 "    --bisect-vars\n"
50 "    --bisect-all"
51 ;
52
53 static struct rev_info revs;
54
55 static int show_timestamp;
56 static int hdr_termination;
57 static const char *header_prefix;
58
59 static void finish_commit(struct commit *commit);
60 static void show_commit(struct commit *commit)
61 {
62         graph_show_commit(revs.graph);
63
64         if (show_timestamp)
65                 printf("%lu ", commit->date);
66         if (header_prefix)
67                 fputs(header_prefix, stdout);
68
69         if (!revs.graph) {
70                 if (commit->object.flags & BOUNDARY)
71                         putchar('-');
72                 else if (commit->object.flags & UNINTERESTING)
73                         putchar('^');
74                 else if (revs.left_right) {
75                         if (commit->object.flags & SYMMETRIC_LEFT)
76                                 putchar('<');
77                         else
78                                 putchar('>');
79                 }
80         }
81         if (revs.abbrev_commit && revs.abbrev)
82                 fputs(find_unique_abbrev(commit->object.sha1, revs.abbrev),
83                       stdout);
84         else
85                 fputs(sha1_to_hex(commit->object.sha1), stdout);
86         if (revs.print_parents) {
87                 struct commit_list *parents = commit->parents;
88                 while (parents) {
89                         printf(" %s", sha1_to_hex(parents->item->object.sha1));
90                         parents = parents->next;
91                 }
92         }
93         if (revs.children.name) {
94                 struct commit_list *children;
95
96                 children = lookup_decoration(&revs.children, &commit->object);
97                 while (children) {
98                         printf(" %s", sha1_to_hex(children->item->object.sha1));
99                         children = children->next;
100                 }
101         }
102         show_decorations(&revs, commit);
103         if (revs.commit_format == CMIT_FMT_ONELINE)
104                 putchar(' ');
105         else
106                 putchar('\n');
107
108         if (revs.verbose_header && commit->buffer) {
109                 struct strbuf buf = STRBUF_INIT;
110                 pretty_print_commit(revs.commit_format, commit,
111                                     &buf, revs.abbrev, NULL, NULL,
112                                     revs.date_mode, 0);
113                 if (revs.graph) {
114                         if (buf.len) {
115                                 if (revs.commit_format != CMIT_FMT_ONELINE)
116                                         graph_show_oneline(revs.graph);
117
118                                 graph_show_commit_msg(revs.graph, &buf);
119
120                                 /*
121                                  * Add a newline after the commit message.
122                                  *
123                                  * Usually, this newline produces a blank
124                                  * padding line between entries, in which case
125                                  * we need to add graph padding on this line.
126                                  *
127                                  * However, the commit message may not end in a
128                                  * newline.  In this case the newline simply
129                                  * ends the last line of the commit message,
130                                  * and we don't need any graph output.  (This
131                                  * always happens with CMIT_FMT_ONELINE, and it
132                                  * happens with CMIT_FMT_USERFORMAT when the
133                                  * format doesn't explicitly end in a newline.)
134                                  */
135                                 if (buf.len && buf.buf[buf.len - 1] == '\n')
136                                         graph_show_padding(revs.graph);
137                                 putchar('\n');
138                         } else {
139                                 /*
140                                  * If the message buffer is empty, just show
141                                  * the rest of the graph output for this
142                                  * commit.
143                                  */
144                                 if (graph_show_remainder(revs.graph))
145                                         putchar('\n');
146                         }
147                 } else {
148                         if (buf.len)
149                                 printf("%s%c", buf.buf, hdr_termination);
150                 }
151                 strbuf_release(&buf);
152         } else {
153                 if (graph_show_remainder(revs.graph))
154                         putchar('\n');
155         }
156         maybe_flush_or_die(stdout, "stdout");
157         finish_commit(commit);
158 }
159
160 static void finish_commit(struct commit *commit)
161 {
162         if (commit->parents) {
163                 free_commit_list(commit->parents);
164                 commit->parents = NULL;
165         }
166         free(commit->buffer);
167         commit->buffer = NULL;
168 }
169
170 static void finish_object(struct object_array_entry *p)
171 {
172         if (p->item->type == OBJ_BLOB && !has_sha1_file(p->item->sha1))
173                 die("missing blob object '%s'", sha1_to_hex(p->item->sha1));
174 }
175
176 static void show_object(struct object_array_entry *p)
177 {
178         /* An object with name "foo\n0000000..." can be used to
179          * confuse downstream "git pack-objects" very badly.
180          */
181         const char *ep = strchr(p->name, '\n');
182
183         finish_object(p);
184         if (ep) {
185                 printf("%s %.*s\n", sha1_to_hex(p->item->sha1),
186                        (int) (ep - p->name),
187                        p->name);
188         }
189         else
190                 printf("%s %s\n", sha1_to_hex(p->item->sha1), p->name);
191 }
192
193 static void show_edge(struct commit *commit)
194 {
195         printf("-%s\n", sha1_to_hex(commit->object.sha1));
196 }
197
198 /*
199  * This is a truly stupid algorithm, but it's only
200  * used for bisection, and we just don't care enough.
201  *
202  * We care just barely enough to avoid recursing for
203  * non-merge entries.
204  */
205 static int count_distance(struct commit_list *entry)
206 {
207         int nr = 0;
208
209         while (entry) {
210                 struct commit *commit = entry->item;
211                 struct commit_list *p;
212
213                 if (commit->object.flags & (UNINTERESTING | COUNTED))
214                         break;
215                 if (!(commit->object.flags & TREESAME))
216                         nr++;
217                 commit->object.flags |= COUNTED;
218                 p = commit->parents;
219                 entry = p;
220                 if (p) {
221                         p = p->next;
222                         while (p) {
223                                 nr += count_distance(p);
224                                 p = p->next;
225                         }
226                 }
227         }
228
229         return nr;
230 }
231
232 static void clear_distance(struct commit_list *list)
233 {
234         while (list) {
235                 struct commit *commit = list->item;
236                 commit->object.flags &= ~COUNTED;
237                 list = list->next;
238         }
239 }
240
241 #define DEBUG_BISECT 0
242
243 static inline int weight(struct commit_list *elem)
244 {
245         return *((int*)(elem->item->util));
246 }
247
248 static inline void weight_set(struct commit_list *elem, int weight)
249 {
250         *((int*)(elem->item->util)) = weight;
251 }
252
253 static int count_interesting_parents(struct commit *commit)
254 {
255         struct commit_list *p;
256         int count;
257
258         for (count = 0, p = commit->parents; p; p = p->next) {
259                 if (p->item->object.flags & UNINTERESTING)
260                         continue;
261                 count++;
262         }
263         return count;
264 }
265
266 static inline int halfway(struct commit_list *p, int nr)
267 {
268         /*
269          * Don't short-cut something we are not going to return!
270          */
271         if (p->item->object.flags & TREESAME)
272                 return 0;
273         if (DEBUG_BISECT)
274                 return 0;
275         /*
276          * 2 and 3 are halfway of 5.
277          * 3 is halfway of 6 but 2 and 4 are not.
278          */
279         switch (2 * weight(p) - nr) {
280         case -1: case 0: case 1:
281                 return 1;
282         default:
283                 return 0;
284         }
285 }
286
287 #if !DEBUG_BISECT
288 #define show_list(a,b,c,d) do { ; } while (0)
289 #else
290 static void show_list(const char *debug, int counted, int nr,
291                       struct commit_list *list)
292 {
293         struct commit_list *p;
294
295         fprintf(stderr, "%s (%d/%d)\n", debug, counted, nr);
296
297         for (p = list; p; p = p->next) {
298                 struct commit_list *pp;
299                 struct commit *commit = p->item;
300                 unsigned flags = commit->object.flags;
301                 enum object_type type;
302                 unsigned long size;
303                 char *buf = read_sha1_file(commit->object.sha1, &type, &size);
304                 char *ep, *sp;
305
306                 fprintf(stderr, "%c%c%c ",
307                         (flags & TREESAME) ? ' ' : 'T',
308                         (flags & UNINTERESTING) ? 'U' : ' ',
309                         (flags & COUNTED) ? 'C' : ' ');
310                 if (commit->util)
311                         fprintf(stderr, "%3d", weight(p));
312                 else
313                         fprintf(stderr, "---");
314                 fprintf(stderr, " %.*s", 8, sha1_to_hex(commit->object.sha1));
315                 for (pp = commit->parents; pp; pp = pp->next)
316                         fprintf(stderr, " %.*s", 8,
317                                 sha1_to_hex(pp->item->object.sha1));
318
319                 sp = strstr(buf, "\n\n");
320                 if (sp) {
321                         sp += 2;
322                         for (ep = sp; *ep && *ep != '\n'; ep++)
323                                 ;
324                         fprintf(stderr, " %.*s", (int)(ep - sp), sp);
325                 }
326                 fprintf(stderr, "\n");
327         }
328 }
329 #endif /* DEBUG_BISECT */
330
331 static struct commit_list *best_bisection(struct commit_list *list, int nr)
332 {
333         struct commit_list *p, *best;
334         int best_distance = -1;
335
336         best = list;
337         for (p = list; p; p = p->next) {
338                 int distance;
339                 unsigned flags = p->item->object.flags;
340
341                 if (flags & TREESAME)
342                         continue;
343                 distance = weight(p);
344                 if (nr - distance < distance)
345                         distance = nr - distance;
346                 if (distance > best_distance) {
347                         best = p;
348                         best_distance = distance;
349                 }
350         }
351
352         return best;
353 }
354
355 struct commit_dist {
356         struct commit *commit;
357         int distance;
358 };
359
360 static int compare_commit_dist(const void *a_, const void *b_)
361 {
362         struct commit_dist *a, *b;
363
364         a = (struct commit_dist *)a_;
365         b = (struct commit_dist *)b_;
366         if (a->distance != b->distance)
367                 return b->distance - a->distance; /* desc sort */
368         return hashcmp(a->commit->object.sha1, b->commit->object.sha1);
369 }
370
371 static struct commit_list *best_bisection_sorted(struct commit_list *list, int nr)
372 {
373         struct commit_list *p;
374         struct commit_dist *array = xcalloc(nr, sizeof(*array));
375         int cnt, i;
376
377         for (p = list, cnt = 0; p; p = p->next) {
378                 int distance;
379                 unsigned flags = p->item->object.flags;
380
381                 if (flags & TREESAME)
382                         continue;
383                 distance = weight(p);
384                 if (nr - distance < distance)
385                         distance = nr - distance;
386                 array[cnt].commit = p->item;
387                 array[cnt].distance = distance;
388                 cnt++;
389         }
390         qsort(array, cnt, sizeof(*array), compare_commit_dist);
391         for (p = list, i = 0; i < cnt; i++) {
392                 struct name_decoration *r = xmalloc(sizeof(*r) + 100);
393                 struct object *obj = &(array[i].commit->object);
394
395                 sprintf(r->name, "dist=%d", array[i].distance);
396                 r->next = add_decoration(&name_decoration, obj, r);
397                 p->item = array[i].commit;
398                 p = p->next;
399         }
400         if (p)
401                 p->next = NULL;
402         free(array);
403         return list;
404 }
405
406 /*
407  * zero or positive weight is the number of interesting commits it can
408  * reach, including itself.  Especially, weight = 0 means it does not
409  * reach any tree-changing commits (e.g. just above uninteresting one
410  * but traversal is with pathspec).
411  *
412  * weight = -1 means it has one parent and its distance is yet to
413  * be computed.
414  *
415  * weight = -2 means it has more than one parent and its distance is
416  * unknown.  After running count_distance() first, they will get zero
417  * or positive distance.
418  */
419 static struct commit_list *do_find_bisection(struct commit_list *list,
420                                              int nr, int *weights,
421                                              int find_all)
422 {
423         int n, counted;
424         struct commit_list *p;
425
426         counted = 0;
427
428         for (n = 0, p = list; p; p = p->next) {
429                 struct commit *commit = p->item;
430                 unsigned flags = commit->object.flags;
431
432                 p->item->util = &weights[n++];
433                 switch (count_interesting_parents(commit)) {
434                 case 0:
435                         if (!(flags & TREESAME)) {
436                                 weight_set(p, 1);
437                                 counted++;
438                                 show_list("bisection 2 count one",
439                                           counted, nr, list);
440                         }
441                         /*
442                          * otherwise, it is known not to reach any
443                          * tree-changing commit and gets weight 0.
444                          */
445                         break;
446                 case 1:
447                         weight_set(p, -1);
448                         break;
449                 default:
450                         weight_set(p, -2);
451                         break;
452                 }
453         }
454
455         show_list("bisection 2 initialize", counted, nr, list);
456
457         /*
458          * If you have only one parent in the resulting set
459          * then you can reach one commit more than that parent
460          * can reach.  So we do not have to run the expensive
461          * count_distance() for single strand of pearls.
462          *
463          * However, if you have more than one parents, you cannot
464          * just add their distance and one for yourself, since
465          * they usually reach the same ancestor and you would
466          * end up counting them twice that way.
467          *
468          * So we will first count distance of merges the usual
469          * way, and then fill the blanks using cheaper algorithm.
470          */
471         for (p = list; p; p = p->next) {
472                 if (p->item->object.flags & UNINTERESTING)
473                         continue;
474                 if (weight(p) != -2)
475                         continue;
476                 weight_set(p, count_distance(p));
477                 clear_distance(list);
478
479                 /* Does it happen to be at exactly half-way? */
480                 if (!find_all && halfway(p, nr))
481                         return p;
482                 counted++;
483         }
484
485         show_list("bisection 2 count_distance", counted, nr, list);
486
487         while (counted < nr) {
488                 for (p = list; p; p = p->next) {
489                         struct commit_list *q;
490                         unsigned flags = p->item->object.flags;
491
492                         if (0 <= weight(p))
493                                 continue;
494                         for (q = p->item->parents; q; q = q->next) {
495                                 if (q->item->object.flags & UNINTERESTING)
496                                         continue;
497                                 if (0 <= weight(q))
498                                         break;
499                         }
500                         if (!q)
501                                 continue;
502
503                         /*
504                          * weight for p is unknown but q is known.
505                          * add one for p itself if p is to be counted,
506                          * otherwise inherit it from q directly.
507                          */
508                         if (!(flags & TREESAME)) {
509                                 weight_set(p, weight(q)+1);
510                                 counted++;
511                                 show_list("bisection 2 count one",
512                                           counted, nr, list);
513                         }
514                         else
515                                 weight_set(p, weight(q));
516
517                         /* Does it happen to be at exactly half-way? */
518                         if (!find_all && halfway(p, nr))
519                                 return p;
520                 }
521         }
522
523         show_list("bisection 2 counted all", counted, nr, list);
524
525         if (!find_all)
526                 return best_bisection(list, nr);
527         else
528                 return best_bisection_sorted(list, nr);
529 }
530
531 static struct commit_list *find_bisection(struct commit_list *list,
532                                           int *reaches, int *all,
533                                           int find_all)
534 {
535         int nr, on_list;
536         struct commit_list *p, *best, *next, *last;
537         int *weights;
538
539         show_list("bisection 2 entry", 0, 0, list);
540
541         /*
542          * Count the number of total and tree-changing items on the
543          * list, while reversing the list.
544          */
545         for (nr = on_list = 0, last = NULL, p = list;
546              p;
547              p = next) {
548                 unsigned flags = p->item->object.flags;
549
550                 next = p->next;
551                 if (flags & UNINTERESTING)
552                         continue;
553                 p->next = last;
554                 last = p;
555                 if (!(flags & TREESAME))
556                         nr++;
557                 on_list++;
558         }
559         list = last;
560         show_list("bisection 2 sorted", 0, nr, list);
561
562         *all = nr;
563         weights = xcalloc(on_list, sizeof(*weights));
564
565         /* Do the real work of finding bisection commit. */
566         best = do_find_bisection(list, nr, weights, find_all);
567         if (best) {
568                 if (!find_all)
569                         best->next = NULL;
570                 *reaches = weight(best);
571         }
572         free(weights);
573         return best;
574 }
575
576 static inline int log2i(int n)
577 {
578         int log2 = 0;
579
580         for (; n > 1; n >>= 1)
581                 log2++;
582
583         return log2;
584 }
585
586 static inline int exp2i(int n)
587 {
588         return 1 << n;
589 }
590
591 /*
592  * Estimate the number of bisect steps left (after the current step)
593  *
594  * For any x between 0 included and 2^n excluded, the probability for
595  * n - 1 steps left looks like:
596  *
597  * P(2^n + x) == (2^n - x) / (2^n + x)
598  *
599  * and P(2^n + x) < 0.5 means 2^n < 3x
600  */
601 static int estimate_bisect_steps(int all)
602 {
603         int n, x, e;
604
605         if (all < 3)
606                 return 0;
607
608         n = log2i(all);
609         e = exp2i(n);
610         x = all - e;
611
612         return (e < 3 * x) ? n : n - 1;
613 }
614
615 int cmd_rev_list(int argc, const char **argv, const char *prefix)
616 {
617         struct commit_list *list;
618         int i;
619         int read_from_stdin = 0;
620         int bisect_list = 0;
621         int bisect_show_vars = 0;
622         int bisect_find_all = 0;
623         int quiet = 0;
624
625         git_config(git_default_config, NULL);
626         init_revisions(&revs, prefix);
627         revs.abbrev = 0;
628         revs.commit_format = CMIT_FMT_UNSPECIFIED;
629         argc = setup_revisions(argc, argv, &revs, NULL);
630
631         quiet = DIFF_OPT_TST(&revs.diffopt, QUIET);
632         for (i = 1 ; i < argc; i++) {
633                 const char *arg = argv[i];
634
635                 if (!strcmp(arg, "--header")) {
636                         revs.verbose_header = 1;
637                         continue;
638                 }
639                 if (!strcmp(arg, "--timestamp")) {
640                         show_timestamp = 1;
641                         continue;
642                 }
643                 if (!strcmp(arg, "--bisect")) {
644                         bisect_list = 1;
645                         continue;
646                 }
647                 if (!strcmp(arg, "--bisect-all")) {
648                         bisect_list = 1;
649                         bisect_find_all = 1;
650                         revs.show_decorations = 1;
651                         continue;
652                 }
653                 if (!strcmp(arg, "--bisect-vars")) {
654                         bisect_list = 1;
655                         bisect_show_vars = 1;
656                         continue;
657                 }
658                 if (!strcmp(arg, "--stdin")) {
659                         if (read_from_stdin++)
660                                 die("--stdin given twice?");
661                         read_revisions_from_stdin(&revs);
662                         continue;
663                 }
664                 usage(rev_list_usage);
665
666         }
667         if (revs.commit_format != CMIT_FMT_UNSPECIFIED) {
668                 /* The command line has a --pretty  */
669                 hdr_termination = '\n';
670                 if (revs.commit_format == CMIT_FMT_ONELINE)
671                         header_prefix = "";
672                 else
673                         header_prefix = "commit ";
674         }
675         else if (revs.verbose_header)
676                 /* Only --header was specified */
677                 revs.commit_format = CMIT_FMT_RAW;
678
679         list = revs.commits;
680
681         if ((!list &&
682              (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) &&
683               !revs.pending.nr)) ||
684             revs.diff)
685                 usage(rev_list_usage);
686
687         save_commit_buffer = revs.verbose_header ||
688                 revs.grep_filter.pattern_list;
689         if (bisect_list)
690                 revs.limited = 1;
691
692         if (prepare_revision_walk(&revs))
693                 die("revision walk setup failed");
694         if (revs.tree_objects)
695                 mark_edges_uninteresting(revs.commits, &revs, show_edge);
696
697         if (bisect_list) {
698                 int reaches = reaches, all = all;
699
700                 revs.commits = find_bisection(revs.commits, &reaches, &all,
701                                               bisect_find_all);
702                 if (bisect_show_vars) {
703                         int cnt;
704                         char hex[41];
705                         if (!revs.commits)
706                                 return 1;
707                         /*
708                          * revs.commits can reach "reaches" commits among
709                          * "all" commits.  If it is good, then there are
710                          * (all-reaches) commits left to be bisected.
711                          * On the other hand, if it is bad, then the set
712                          * to bisect is "reaches".
713                          * A bisect set of size N has (N-1) commits further
714                          * to test, as we already know one bad one.
715                          */
716                         cnt = all - reaches;
717                         if (cnt < reaches)
718                                 cnt = reaches;
719                         strcpy(hex, sha1_to_hex(revs.commits->item->object.sha1));
720
721                         if (bisect_find_all) {
722                                 traverse_commit_list(&revs, show_commit, show_object);
723                                 printf("------\n");
724                         }
725
726                         printf("bisect_rev=%s\n"
727                                "bisect_nr=%d\n"
728                                "bisect_good=%d\n"
729                                "bisect_bad=%d\n"
730                                "bisect_all=%d\n"
731                                "bisect_steps=%d\n",
732                                hex,
733                                cnt - 1,
734                                all - reaches - 1,
735                                reaches - 1,
736                                all,
737                                estimate_bisect_steps(all));
738                         return 0;
739                 }
740         }
741
742         traverse_commit_list(&revs,
743                 quiet ? finish_commit : show_commit,
744                 quiet ? finish_object : show_object);
745
746         return 0;
747 }