Rip out merge-order and make "git log <paths>..." work again.
[git.git] / 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 "diff.h"
8 #include "revision.h"
9
10 /* bits #0-3 in revision.h */
11
12 #define COUNTED         (1u << 4)
13 #define TMP_MARK        (1u << 5) /* for isolated cases; clean after use */
14
15 static const char rev_list_usage[] =
16 "git-rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
17 "  limiting output:\n"
18 "    --max-count=nr\n"
19 "    --max-age=epoch\n"
20 "    --min-age=epoch\n"
21 "    --sparse\n"
22 "    --no-merges\n"
23 "    --remove-empty\n"
24 "    --all\n"
25 "  ordering output:\n"
26 "    --topo-order\n"
27 "    --date-order\n"
28 "  formatting output:\n"
29 "    --parents\n"
30 "    --objects | --objects-edge\n"
31 "    --unpacked\n"
32 "    --header | --pretty\n"
33 "    --abbrev=nr | --no-abbrev\n"
34 "  special purpose:\n"
35 "    --bisect"
36 ;
37
38 struct rev_info revs;
39
40 static int bisect_list = 0;
41 static int verbose_header = 0;
42 static int abbrev = DEFAULT_ABBREV;
43 static int show_parents = 0;
44 static int hdr_termination = 0;
45 static const char *commit_prefix = "";
46 static enum cmit_fmt commit_format = CMIT_FMT_RAW;
47
48 static void show_commit(struct commit *commit)
49 {
50         printf("%s%s", commit_prefix, sha1_to_hex(commit->object.sha1));
51         if (show_parents) {
52                 struct commit_list *parents = commit->parents;
53                 while (parents) {
54                         struct object *o = &(parents->item->object);
55                         parents = parents->next;
56                         if (o->flags & TMP_MARK)
57                                 continue;
58                         printf(" %s", sha1_to_hex(o->sha1));
59                         o->flags |= TMP_MARK;
60                 }
61                 /* TMP_MARK is a general purpose flag that can
62                  * be used locally, but the user should clean
63                  * things up after it is done with them.
64                  */
65                 for (parents = commit->parents;
66                      parents;
67                      parents = parents->next)
68                         parents->item->object.flags &= ~TMP_MARK;
69         }
70         if (commit_format == CMIT_FMT_ONELINE)
71                 putchar(' ');
72         else
73                 putchar('\n');
74
75         if (verbose_header) {
76                 static char pretty_header[16384];
77                 pretty_print_commit(commit_format, commit, ~0, pretty_header, sizeof(pretty_header), abbrev);
78                 printf("%s%c", pretty_header, hdr_termination);
79         }
80         fflush(stdout);
81 }
82
83 static struct object_list **process_blob(struct blob *blob,
84                                          struct object_list **p,
85                                          struct name_path *path,
86                                          const char *name)
87 {
88         struct object *obj = &blob->object;
89
90         if (!revs.blob_objects)
91                 return p;
92         if (obj->flags & (UNINTERESTING | SEEN))
93                 return p;
94         obj->flags |= SEEN;
95         return add_object(obj, p, path, name);
96 }
97
98 static struct object_list **process_tree(struct tree *tree,
99                                          struct object_list **p,
100                                          struct name_path *path,
101                                          const char *name)
102 {
103         struct object *obj = &tree->object;
104         struct tree_entry_list *entry;
105         struct name_path me;
106
107         if (!revs.tree_objects)
108                 return p;
109         if (obj->flags & (UNINTERESTING | SEEN))
110                 return p;
111         if (parse_tree(tree) < 0)
112                 die("bad tree object %s", sha1_to_hex(obj->sha1));
113         obj->flags |= SEEN;
114         p = add_object(obj, p, path, name);
115         me.up = path;
116         me.elem = name;
117         me.elem_len = strlen(name);
118         entry = tree->entries;
119         tree->entries = NULL;
120         while (entry) {
121                 struct tree_entry_list *next = entry->next;
122                 if (entry->directory)
123                         p = process_tree(entry->item.tree, p, &me, entry->name);
124                 else
125                         p = process_blob(entry->item.blob, p, &me, entry->name);
126                 free(entry);
127                 entry = next;
128         }
129         return p;
130 }
131
132 static void show_commit_list(struct rev_info *revs)
133 {
134         struct commit *commit;
135         struct object_list *objects = NULL, **p = &objects, *pending;
136
137         while ((commit = get_revision(revs)) != NULL) {
138                 p = process_tree(commit->tree, p, NULL, "");
139                 show_commit(commit);
140         }
141         for (pending = revs->pending_objects; pending; pending = pending->next) {
142                 struct object *obj = pending->item;
143                 const char *name = pending->name;
144                 if (obj->flags & (UNINTERESTING | SEEN))
145                         continue;
146                 if (obj->type == tag_type) {
147                         obj->flags |= SEEN;
148                         p = add_object(obj, p, NULL, name);
149                         continue;
150                 }
151                 if (obj->type == tree_type) {
152                         p = process_tree((struct tree *)obj, p, NULL, name);
153                         continue;
154                 }
155                 if (obj->type == blob_type) {
156                         p = process_blob((struct blob *)obj, p, NULL, name);
157                         continue;
158                 }
159                 die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name);
160         }
161         while (objects) {
162                 /* An object with name "foo\n0000000..." can be used to
163                  * confuse downstream git-pack-objects very badly.
164                  */
165                 const char *ep = strchr(objects->name, '\n');
166                 if (ep) {
167                         printf("%s %.*s\n", sha1_to_hex(objects->item->sha1),
168                                (int) (ep - objects->name),
169                                objects->name);
170                 }
171                 else
172                         printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name);
173                 objects = objects->next;
174         }
175 }
176
177 /*
178  * This is a truly stupid algorithm, but it's only
179  * used for bisection, and we just don't care enough.
180  *
181  * We care just barely enough to avoid recursing for
182  * non-merge entries.
183  */
184 static int count_distance(struct commit_list *entry)
185 {
186         int nr = 0;
187
188         while (entry) {
189                 struct commit *commit = entry->item;
190                 struct commit_list *p;
191
192                 if (commit->object.flags & (UNINTERESTING | COUNTED))
193                         break;
194                 if (!revs.paths || (commit->object.flags & TREECHANGE))
195                         nr++;
196                 commit->object.flags |= COUNTED;
197                 p = commit->parents;
198                 entry = p;
199                 if (p) {
200                         p = p->next;
201                         while (p) {
202                                 nr += count_distance(p);
203                                 p = p->next;
204                         }
205                 }
206         }
207
208         return nr;
209 }
210
211 static void clear_distance(struct commit_list *list)
212 {
213         while (list) {
214                 struct commit *commit = list->item;
215                 commit->object.flags &= ~COUNTED;
216                 list = list->next;
217         }
218 }
219
220 static struct commit_list *find_bisection(struct commit_list *list)
221 {
222         int nr, closest;
223         struct commit_list *p, *best;
224
225         nr = 0;
226         p = list;
227         while (p) {
228                 if (!revs.paths || (p->item->object.flags & TREECHANGE))
229                         nr++;
230                 p = p->next;
231         }
232         closest = 0;
233         best = list;
234
235         for (p = list; p; p = p->next) {
236                 int distance;
237
238                 if (revs.paths && !(p->item->object.flags & TREECHANGE))
239                         continue;
240
241                 distance = count_distance(p);
242                 clear_distance(list);
243                 if (nr - distance < distance)
244                         distance = nr - distance;
245                 if (distance > closest) {
246                         best = p;
247                         closest = distance;
248                 }
249         }
250         if (best)
251                 best->next = NULL;
252         return best;
253 }
254
255 static void mark_edge_parents_uninteresting(struct commit *commit)
256 {
257         struct commit_list *parents;
258
259         for (parents = commit->parents; parents; parents = parents->next) {
260                 struct commit *parent = parents->item;
261                 if (!(parent->object.flags & UNINTERESTING))
262                         continue;
263                 mark_tree_uninteresting(parent->tree);
264                 if (revs.edge_hint && !(parent->object.flags & SHOWN)) {
265                         parent->object.flags |= SHOWN;
266                         printf("-%s\n", sha1_to_hex(parent->object.sha1));
267                 }
268         }
269 }
270
271 static void mark_edges_uninteresting(struct commit_list *list)
272 {
273         for ( ; list; list = list->next) {
274                 struct commit *commit = list->item;
275
276                 if (commit->object.flags & UNINTERESTING) {
277                         mark_tree_uninteresting(commit->tree);
278                         continue;
279                 }
280                 mark_edge_parents_uninteresting(commit);
281         }
282 }
283
284 int main(int argc, const char **argv)
285 {
286         struct commit_list *list;
287         int i;
288
289         argc = setup_revisions(argc, argv, &revs, NULL);
290
291         for (i = 1 ; i < argc; i++) {
292                 const char *arg = argv[i];
293
294                 /* accept -<digit>, like traditilnal "head" */
295                 if ((*arg == '-') && isdigit(arg[1])) {
296                         revs.max_count = atoi(arg + 1);
297                         continue;
298                 }
299                 if (!strcmp(arg, "-n")) {
300                         if (++i >= argc)
301                                 die("-n requires an argument");
302                         revs.max_count = atoi(argv[i]);
303                         continue;
304                 }
305                 if (!strncmp(arg,"-n",2)) {
306                         revs.max_count = atoi(arg + 2);
307                         continue;
308                 }
309                 if (!strcmp(arg, "--header")) {
310                         verbose_header = 1;
311                         continue;
312                 }
313                 if (!strcmp(arg, "--no-abbrev")) {
314                         abbrev = 0;
315                         continue;
316                 }
317                 if (!strncmp(arg, "--abbrev=", 9)) {
318                         abbrev = strtoul(arg + 9, NULL, 10);
319                         if (abbrev && abbrev < MINIMUM_ABBREV)
320                                 abbrev = MINIMUM_ABBREV;
321                         else if (40 < abbrev)
322                                 abbrev = 40;
323                         continue;
324                 }
325                 if (!strncmp(arg, "--pretty", 8)) {
326                         commit_format = get_commit_format(arg+8);
327                         verbose_header = 1;
328                         hdr_termination = '\n';
329                         if (commit_format == CMIT_FMT_ONELINE)
330                                 commit_prefix = "";
331                         else
332                                 commit_prefix = "commit ";
333                         continue;
334                 }
335                 if (!strcmp(arg, "--parents")) {
336                         show_parents = 1;
337                         continue;
338                 }
339                 if (!strcmp(arg, "--bisect")) {
340                         bisect_list = 1;
341                         continue;
342                 }
343                 usage(rev_list_usage);
344
345         }
346
347         list = revs.commits;
348
349         if (!list &&
350             (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects))
351                 usage(rev_list_usage);
352
353         prepare_revision_walk(&revs);
354         if (revs.tree_objects)
355                 mark_edges_uninteresting(revs.commits);
356
357         if (bisect_list)
358                 revs.commits = find_bisection(revs.commits);
359
360         save_commit_buffer = verbose_header;
361         track_object_refs = 0;
362
363         show_commit_list(&revs);
364
365         return 0;
366 }