6 #define INTERESTING (1u << 1)
7 #define COUNTED (1u << 2)
8 #define SHOWN (LAST_EPOCH_FLAG << 2)
10 static const char rev_list_usage[] =
11 "usage: git-rev-list [OPTION] commit-id <commit-id>\n"
17 " --merge-order [ --show-breaks ]";
19 static int bisect_list = 0;
20 static int verbose_header = 0;
21 static int show_parents = 0;
22 static int hdr_termination = 0;
23 static const char *prefix = "";
24 static unsigned long max_age = -1;
25 static unsigned long min_age = -1;
26 static int max_count = -1;
27 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
28 static int merge_order = 0;
29 static int show_breaks = 0;
30 static int stop_traversal = 0;
32 static void show_commit(struct commit *commit)
34 commit->object.flags |= SHOWN;
37 if (commit->object.flags & DISCONTINUITY) {
39 } else if (commit->object.flags & BOUNDARY) {
43 printf("%s%s", prefix, sha1_to_hex(commit->object.sha1));
45 struct commit_list *parents = commit->parents;
47 printf(" %s", sha1_to_hex(parents->item->object.sha1));
48 parents = parents->next;
53 static char pretty_header[16384];
54 pretty_print_commit(commit_format, commit->buffer, ~0, pretty_header, sizeof(pretty_header));
55 printf("%s%c", pretty_header, hdr_termination);
59 static int filter_commit(struct commit * commit)
61 if (merge_order && stop_traversal && commit->object.flags & BOUNDARY)
63 if (commit->object.flags & (UNINTERESTING|SHOWN))
65 if (min_age != -1 && (commit->date > min_age))
67 if (max_age != -1 && (commit->date < max_age)) {
75 if (max_count != -1 && !max_count--)
80 static int process_commit(struct commit * commit)
82 int action=filter_commit(commit);
88 if (action == CONTINUE) {
97 static void show_commit_list(struct commit_list *list)
100 struct commit *commit = pop_most_recent_commit(&list, SEEN);
102 if (process_commit(commit) == STOP)
107 static void mark_parents_uninteresting(struct commit *commit)
109 struct commit_list *parents = commit->parents;
112 struct commit *commit = parents->item;
113 commit->object.flags |= UNINTERESTING;
114 parents = parents->next;
118 static int everybody_uninteresting(struct commit_list *list)
121 struct commit *commit = list->item;
123 if (commit->object.flags & UNINTERESTING)
131 * This is a truly stupid algorithm, but it's only
132 * used for bisection, and we just don't care enough.
134 * We care just barely enough to avoid recursing for
137 static int count_distance(struct commit_list *entry)
142 struct commit *commit = entry->item;
143 struct commit_list *p;
145 if (commit->object.flags & (UNINTERESTING | COUNTED))
148 commit->object.flags |= COUNTED;
154 nr += count_distance(p);
162 static void clear_distance(struct commit_list *list)
165 struct commit *commit = list->item;
166 commit->object.flags &= ~COUNTED;
171 static struct commit_list *find_bisection(struct commit_list *list)
174 struct commit_list *p, *best;
187 int distance = count_distance(p);
188 clear_distance(list);
189 if (nr - distance < distance)
190 distance = nr - distance;
191 if (distance > closest) {
202 struct commit_list *limit_list(struct commit_list *list)
204 struct commit_list *newlist = NULL;
205 struct commit_list **p = &newlist;
207 struct commit *commit = pop_most_recent_commit(&list, SEEN);
208 struct object *obj = &commit->object;
210 if (obj->flags & UNINTERESTING) {
211 mark_parents_uninteresting(commit);
212 if (everybody_uninteresting(list))
216 p = &commit_list_insert(commit, p)->next;
219 newlist = find_bisection(newlist);
223 static enum cmit_fmt get_commit_format(const char *arg)
226 return CMIT_FMT_DEFAULT;
227 if (!strcmp(arg, "=raw"))
229 if (!strcmp(arg, "=medium"))
230 return CMIT_FMT_MEDIUM;
231 if (!strcmp(arg, "=short"))
232 return CMIT_FMT_SHORT;
233 usage(rev_list_usage);
237 int main(int argc, char **argv)
239 struct commit_list *list = NULL;
242 for (i = 1 ; i < argc; i++) {
245 unsigned char sha1[20];
246 struct commit *commit;
248 if (!strncmp(arg, "--max-count=", 12)) {
249 max_count = atoi(arg + 12);
252 if (!strncmp(arg, "--max-age=", 10)) {
253 max_age = atoi(arg + 10);
256 if (!strncmp(arg, "--min-age=", 10)) {
257 min_age = atoi(arg + 10);
260 if (!strcmp(arg, "--header")) {
264 if (!strncmp(arg, "--pretty", 8)) {
265 commit_format = get_commit_format(arg+8);
267 hdr_termination = '\n';
271 if (!strcmp(arg, "--parents")) {
275 if (!strcmp(arg, "--bisect")) {
279 if (!strncmp(arg, "--merge-order", 13)) {
283 if (!strncmp(arg, "--show-breaks", 13)) {
290 flags = UNINTERESTING;
294 if (get_sha1(arg, sha1) || (show_breaks && !merge_order))
295 usage(rev_list_usage);
296 commit = lookup_commit_reference(sha1);
297 if (!commit || parse_commit(commit) < 0)
298 die("bad commit object %s", arg);
299 commit->object.flags |= flags;
300 commit_list_insert(commit, &list);
304 usage(rev_list_usage);
308 list = limit_list(list);
309 show_commit_list(list);
311 if (sort_list_in_merge_order(list, &process_commit)) {
312 die("merge order sort failed\n");