Linus Torvalds | 6474510 | 2005-04-23 19:04:40 -0700 | [diff] [blame] | 1 | #include "cache.h" |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 2 | #include "tag.h" |
Linus Torvalds | 6474510 | 2005-04-23 19:04:40 -0700 | [diff] [blame] | 3 | #include "commit.h" |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 4 | #include "tree.h" |
| 5 | #include "blob.h" |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 6 | #include "epoch.h" |
Linus Torvalds | 6474510 | 2005-04-23 19:04:40 -0700 | [diff] [blame] | 7 | |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 8 | #define SEEN (1u << 0) |
| 9 | #define INTERESTING (1u << 1) |
Linus Torvalds | 8b3a1e0 | 2005-06-17 22:54:50 -0700 | [diff] [blame] | 10 | #define COUNTED (1u << 2) |
Linus Torvalds | bce6286 | 2005-07-06 09:56:16 -0700 | [diff] [blame] | 11 | #define SHOWN (1u << 3) |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 12 | |
Linus Torvalds | a6f68d4 | 2005-05-25 18:29:09 -0700 | [diff] [blame] | 13 | static const char rev_list_usage[] = |
Junio C Hamano | 54c6870 | 2005-07-27 00:04:16 -0700 | [diff] [blame] | 14 | "git-rev-list [OPTION] commit-id <commit-id>\n" |
Linus Torvalds | a6f68d4 | 2005-05-25 18:29:09 -0700 | [diff] [blame] | 15 | " --max-count=nr\n" |
| 16 | " --max-age=epoch\n" |
| 17 | " --min-age=epoch\n" |
Johannes Schindelin | 76cd8eb | 2005-08-08 11:37:21 +0200 | [diff] [blame] | 18 | " --parents\n" |
Linus Torvalds | 12d2a18 | 2005-07-03 13:29:54 -0700 | [diff] [blame] | 19 | " --bisect\n" |
| 20 | " --objects\n" |
| 21 | " --unpacked\n" |
Linus Torvalds | 9d97aa6 | 2005-06-01 08:42:22 -0700 | [diff] [blame] | 22 | " --header\n" |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 23 | " --pretty\n" |
Johannes Schindelin | 76cd8eb | 2005-08-08 11:37:21 +0200 | [diff] [blame] | 24 | " --no-merges\n" |
| 25 | " --merge-order [ --show-breaks ]\n" |
| 26 | " --topo-order"; |
Linus Torvalds | a6f68d4 | 2005-05-25 18:29:09 -0700 | [diff] [blame] | 27 | |
Linus Torvalds | 12d2a18 | 2005-07-03 13:29:54 -0700 | [diff] [blame] | 28 | static int unpacked = 0; |
Linus Torvalds | 8b3a1e0 | 2005-06-17 22:54:50 -0700 | [diff] [blame] | 29 | static int bisect_list = 0; |
Linus Torvalds | 3c90f03 | 2005-06-29 10:40:14 -0700 | [diff] [blame] | 30 | static int tag_objects = 0; |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 31 | static int tree_objects = 0; |
| 32 | static int blob_objects = 0; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 33 | static int verbose_header = 0; |
| 34 | static int show_parents = 0; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 35 | static int hdr_termination = 0; |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 36 | static const char *commit_prefix = ""; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 37 | static unsigned long max_age = -1; |
| 38 | static unsigned long min_age = -1; |
| 39 | static int max_count = -1; |
Linus Torvalds | 000182e | 2005-06-05 09:02:03 -0700 | [diff] [blame] | 40 | static enum cmit_fmt commit_format = CMIT_FMT_RAW; |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 41 | static int merge_order = 0; |
| 42 | static int show_breaks = 0; |
Jon Seymour | 5e749e2 | 2005-06-20 12:29:41 +1000 | [diff] [blame] | 43 | static int stop_traversal = 0; |
Linus Torvalds | d2d02a4 | 2005-07-06 10:25:04 -0700 | [diff] [blame] | 44 | static int topo_order = 0; |
Johannes Schindelin | 76cd8eb | 2005-08-08 11:37:21 +0200 | [diff] [blame] | 45 | static int no_merges = 0; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 46 | |
| 47 | static void show_commit(struct commit *commit) |
| 48 | { |
Jon Seymour | 51b1e17 | 2005-06-20 12:29:38 +1000 | [diff] [blame] | 49 | commit->object.flags |= SHOWN; |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 50 | if (show_breaks) { |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 51 | commit_prefix = "| "; |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 52 | if (commit->object.flags & DISCONTINUITY) { |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 53 | commit_prefix = "^ "; |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 54 | } else if (commit->object.flags & BOUNDARY) { |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 55 | commit_prefix = "= "; |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 56 | } |
| 57 | } |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 58 | printf("%s%s", commit_prefix, sha1_to_hex(commit->object.sha1)); |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 59 | if (show_parents) { |
| 60 | struct commit_list *parents = commit->parents; |
| 61 | while (parents) { |
| 62 | printf(" %s", sha1_to_hex(parents->item->object.sha1)); |
| 63 | parents = parents->next; |
| 64 | } |
| 65 | } |
Junio C Hamano | d87449c | 2005-08-08 22:15:40 -0700 | [diff] [blame] | 66 | if (commit_format == CMIT_FMT_ONELINE) |
| 67 | putchar(' '); |
| 68 | else |
| 69 | putchar('\n'); |
| 70 | |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 71 | if (verbose_header) { |
Linus Torvalds | 000182e | 2005-06-05 09:02:03 -0700 | [diff] [blame] | 72 | static char pretty_header[16384]; |
| 73 | pretty_print_commit(commit_format, commit->buffer, ~0, pretty_header, sizeof(pretty_header)); |
| 74 | printf("%s%c", pretty_header, hdr_termination); |
Linus Torvalds | 7620d39 | 2005-07-04 16:36:48 -0700 | [diff] [blame] | 75 | } |
| 76 | fflush(stdout); |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | static int filter_commit(struct commit * commit) |
| 80 | { |
Jon Seymour | d2775a8 | 2005-07-07 02:39:34 +1000 | [diff] [blame] | 81 | if (stop_traversal && (commit->object.flags & BOUNDARY)) |
Jon Seymour | 5e749e2 | 2005-06-20 12:29:41 +1000 | [diff] [blame] | 82 | return STOP; |
Jon Seymour | 51b1e17 | 2005-06-20 12:29:38 +1000 | [diff] [blame] | 83 | if (commit->object.flags & (UNINTERESTING|SHOWN)) |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 84 | return CONTINUE; |
| 85 | if (min_age != -1 && (commit->date > min_age)) |
| 86 | return CONTINUE; |
Jon Seymour | 5e749e2 | 2005-06-20 12:29:41 +1000 | [diff] [blame] | 87 | if (max_age != -1 && (commit->date < max_age)) { |
Jon Seymour | d2775a8 | 2005-07-07 02:39:34 +1000 | [diff] [blame] | 88 | stop_traversal=1; |
| 89 | return merge_order?CONTINUE:STOP; |
Jon Seymour | 5e749e2 | 2005-06-20 12:29:41 +1000 | [diff] [blame] | 90 | } |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 91 | if (max_count != -1 && !max_count--) |
| 92 | return STOP; |
Johannes Schindelin | 76cd8eb | 2005-08-08 11:37:21 +0200 | [diff] [blame] | 93 | if (no_merges && (commit->parents && commit->parents->next)) |
| 94 | return CONTINUE; |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 95 | return DO; |
| 96 | } |
| 97 | |
| 98 | static int process_commit(struct commit * commit) |
| 99 | { |
| 100 | int action=filter_commit(commit); |
| 101 | |
| 102 | if (action == STOP) { |
| 103 | return STOP; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 104 | } |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 105 | |
| 106 | if (action == CONTINUE) { |
| 107 | return CONTINUE; |
| 108 | } |
| 109 | |
| 110 | show_commit(commit); |
| 111 | |
| 112 | return CONTINUE; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 113 | } |
| 114 | |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 115 | static struct object_list **add_object(struct object *obj, struct object_list **p, const char *name) |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 116 | { |
| 117 | struct object_list *entry = xmalloc(sizeof(*entry)); |
| 118 | entry->item = obj; |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 119 | entry->next = *p; |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 120 | entry->name = name; |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 121 | *p = entry; |
| 122 | return &entry->next; |
| 123 | } |
| 124 | |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 125 | static struct object_list **process_blob(struct blob *blob, struct object_list **p, const char *name) |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 126 | { |
| 127 | struct object *obj = &blob->object; |
| 128 | |
| 129 | if (!blob_objects) |
| 130 | return p; |
| 131 | if (obj->flags & (UNINTERESTING | SEEN)) |
| 132 | return p; |
| 133 | obj->flags |= SEEN; |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 134 | return add_object(obj, p, name); |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 135 | } |
| 136 | |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 137 | static struct object_list **process_tree(struct tree *tree, struct object_list **p, const char *name) |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 138 | { |
| 139 | struct object *obj = &tree->object; |
| 140 | struct tree_entry_list *entry; |
| 141 | |
| 142 | if (!tree_objects) |
| 143 | return p; |
| 144 | if (obj->flags & (UNINTERESTING | SEEN)) |
| 145 | return p; |
| 146 | if (parse_tree(tree) < 0) |
| 147 | die("bad tree object %s", sha1_to_hex(obj->sha1)); |
| 148 | obj->flags |= SEEN; |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 149 | p = add_object(obj, p, name); |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 150 | for (entry = tree->entries ; entry ; entry = entry->next) { |
| 151 | if (entry->directory) |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 152 | p = process_tree(entry->item.tree, p, entry->name); |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 153 | else |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 154 | p = process_blob(entry->item.blob, p, entry->name); |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 155 | } |
| 156 | return p; |
| 157 | } |
| 158 | |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 159 | static struct object_list *pending_objects = NULL; |
| 160 | |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 161 | static void show_commit_list(struct commit_list *list) |
| 162 | { |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 163 | struct object_list *objects = NULL, **p = &objects, *pending; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 164 | while (list) { |
| 165 | struct commit *commit = pop_most_recent_commit(&list, SEEN); |
| 166 | |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 167 | p = process_tree(commit->tree, p, ""); |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 168 | if (process_commit(commit) == STOP) |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 169 | break; |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 170 | } |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 171 | for (pending = pending_objects; pending; pending = pending->next) { |
| 172 | struct object *obj = pending->item; |
| 173 | const char *name = pending->name; |
| 174 | if (obj->flags & (UNINTERESTING | SEEN)) |
| 175 | continue; |
| 176 | if (obj->type == tag_type) { |
| 177 | obj->flags |= SEEN; |
| 178 | p = add_object(obj, p, name); |
| 179 | continue; |
| 180 | } |
| 181 | if (obj->type == tree_type) { |
| 182 | p = process_tree((struct tree *)obj, p, name); |
| 183 | continue; |
| 184 | } |
| 185 | if (obj->type == blob_type) { |
| 186 | p = process_blob((struct blob *)obj, p, name); |
| 187 | continue; |
| 188 | } |
| 189 | die("unknown pending object %s (%s)", sha1_to_hex(obj->sha1), name); |
| 190 | } |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 191 | while (objects) { |
Linus Torvalds | 9ce43d1 | 2005-06-26 15:26:05 -0700 | [diff] [blame] | 192 | printf("%s %s\n", sha1_to_hex(objects->item->sha1), objects->name); |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 193 | objects = objects->next; |
| 194 | } |
| 195 | } |
| 196 | |
| 197 | static void mark_blob_uninteresting(struct blob *blob) |
| 198 | { |
| 199 | if (!blob_objects) |
| 200 | return; |
| 201 | if (blob->object.flags & UNINTERESTING) |
| 202 | return; |
| 203 | blob->object.flags |= UNINTERESTING; |
| 204 | } |
| 205 | |
| 206 | static void mark_tree_uninteresting(struct tree *tree) |
| 207 | { |
| 208 | struct object *obj = &tree->object; |
| 209 | struct tree_entry_list *entry; |
| 210 | |
| 211 | if (!tree_objects) |
| 212 | return; |
| 213 | if (obj->flags & UNINTERESTING) |
| 214 | return; |
| 215 | obj->flags |= UNINTERESTING; |
Linus Torvalds | 454fbbc | 2005-07-10 15:09:46 -0700 | [diff] [blame] | 216 | if (!has_sha1_file(obj->sha1)) |
| 217 | return; |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 218 | if (parse_tree(tree) < 0) |
| 219 | die("bad tree %s", sha1_to_hex(obj->sha1)); |
| 220 | entry = tree->entries; |
| 221 | while (entry) { |
| 222 | if (entry->directory) |
| 223 | mark_tree_uninteresting(entry->item.tree); |
| 224 | else |
| 225 | mark_blob_uninteresting(entry->item.blob); |
| 226 | entry = entry->next; |
| 227 | } |
Linus Torvalds | 81f2bb1 | 2005-06-02 09:19:53 -0700 | [diff] [blame] | 228 | } |
| 229 | |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 230 | static void mark_parents_uninteresting(struct commit *commit) |
| 231 | { |
| 232 | struct commit_list *parents = commit->parents; |
| 233 | |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 234 | if (tree_objects) |
| 235 | mark_tree_uninteresting(commit->tree); |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 236 | while (parents) { |
| 237 | struct commit *commit = parents->item; |
| 238 | commit->object.flags |= UNINTERESTING; |
Linus Torvalds | 454fbbc | 2005-07-10 15:09:46 -0700 | [diff] [blame] | 239 | |
| 240 | /* |
Linus Torvalds | 6c3b84c | 2005-07-29 15:50:30 -0700 | [diff] [blame] | 241 | * Normally we haven't parsed the parent |
| 242 | * yet, so we won't have a parent of a parent |
| 243 | * here. However, it may turn out that we've |
| 244 | * reached this commit some other way (where it |
| 245 | * wasn't uninteresting), in which case we need |
| 246 | * to mark its parents recursively too.. |
| 247 | */ |
| 248 | if (commit->parents) |
| 249 | mark_parents_uninteresting(commit); |
| 250 | |
| 251 | /* |
Linus Torvalds | 454fbbc | 2005-07-10 15:09:46 -0700 | [diff] [blame] | 252 | * A missing commit is ok iff its parent is marked |
| 253 | * uninteresting. |
| 254 | * |
| 255 | * We just mark such a thing parsed, so that when |
| 256 | * it is popped next time around, we won't be trying |
| 257 | * to parse it and get an error. |
| 258 | */ |
| 259 | if (!has_sha1_file(commit->object.sha1)) |
| 260 | commit->object.parsed = 1; |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 261 | parents = parents->next; |
| 262 | } |
| 263 | } |
| 264 | |
Linus Torvalds | 4311d32 | 2005-07-23 10:01:49 -0700 | [diff] [blame] | 265 | static int everybody_uninteresting(struct commit_list *orig) |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 266 | { |
Linus Torvalds | 4311d32 | 2005-07-23 10:01:49 -0700 | [diff] [blame] | 267 | struct commit_list *list = orig; |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 268 | while (list) { |
| 269 | struct commit *commit = list->item; |
| 270 | list = list->next; |
| 271 | if (commit->object.flags & UNINTERESTING) |
| 272 | continue; |
| 273 | return 0; |
| 274 | } |
Linus Torvalds | 4311d32 | 2005-07-23 10:01:49 -0700 | [diff] [blame] | 275 | |
| 276 | /* |
| 277 | * Ok, go back and mark all the edge trees uninteresting, |
| 278 | * since otherwise we can have situations where a parent |
| 279 | * that was marked uninteresting (and we never even had |
| 280 | * to look at) had lots of objects that we don't want to |
| 281 | * include. |
| 282 | * |
| 283 | * NOTE! This still doesn't mean that the object list is |
| 284 | * "correct", since we may end up listing objects that |
| 285 | * even older commits (that we don't list) do actually |
| 286 | * reference, but it gets us to a minimal list (or very |
| 287 | * close) in practice. |
| 288 | */ |
| 289 | if (!tree_objects) |
| 290 | return 1; |
| 291 | |
| 292 | while (orig) { |
| 293 | struct commit *commit = orig->item; |
| 294 | if (!parse_commit(commit) && commit->tree) |
| 295 | mark_tree_uninteresting(commit->tree); |
| 296 | orig = orig->next; |
| 297 | } |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 298 | return 1; |
| 299 | } |
| 300 | |
Linus Torvalds | 8b3a1e0 | 2005-06-17 22:54:50 -0700 | [diff] [blame] | 301 | /* |
| 302 | * This is a truly stupid algorithm, but it's only |
| 303 | * used for bisection, and we just don't care enough. |
| 304 | * |
| 305 | * We care just barely enough to avoid recursing for |
| 306 | * non-merge entries. |
| 307 | */ |
| 308 | static int count_distance(struct commit_list *entry) |
| 309 | { |
| 310 | int nr = 0; |
| 311 | |
| 312 | while (entry) { |
| 313 | struct commit *commit = entry->item; |
| 314 | struct commit_list *p; |
| 315 | |
| 316 | if (commit->object.flags & (UNINTERESTING | COUNTED)) |
| 317 | break; |
| 318 | nr++; |
| 319 | commit->object.flags |= COUNTED; |
| 320 | p = commit->parents; |
| 321 | entry = p; |
| 322 | if (p) { |
| 323 | p = p->next; |
| 324 | while (p) { |
| 325 | nr += count_distance(p); |
| 326 | p = p->next; |
| 327 | } |
| 328 | } |
| 329 | } |
| 330 | return nr; |
| 331 | } |
| 332 | |
Linus Torvalds | 3d95806 | 2005-06-18 20:02:49 -0700 | [diff] [blame] | 333 | static void clear_distance(struct commit_list *list) |
Linus Torvalds | 8b3a1e0 | 2005-06-17 22:54:50 -0700 | [diff] [blame] | 334 | { |
| 335 | while (list) { |
| 336 | struct commit *commit = list->item; |
| 337 | commit->object.flags &= ~COUNTED; |
| 338 | list = list->next; |
| 339 | } |
| 340 | } |
| 341 | |
| 342 | static struct commit_list *find_bisection(struct commit_list *list) |
| 343 | { |
| 344 | int nr, closest; |
| 345 | struct commit_list *p, *best; |
| 346 | |
| 347 | nr = 0; |
| 348 | p = list; |
| 349 | while (p) { |
| 350 | nr++; |
| 351 | p = p->next; |
| 352 | } |
| 353 | closest = 0; |
| 354 | best = list; |
| 355 | |
| 356 | p = list; |
| 357 | while (p) { |
| 358 | int distance = count_distance(p); |
| 359 | clear_distance(list); |
| 360 | if (nr - distance < distance) |
| 361 | distance = nr - distance; |
| 362 | if (distance > closest) { |
| 363 | best = p; |
| 364 | closest = distance; |
| 365 | } |
| 366 | p = p->next; |
| 367 | } |
| 368 | if (best) |
| 369 | best->next = NULL; |
| 370 | return best; |
| 371 | } |
| 372 | |
Linus Torvalds | 6da4016 | 2005-07-03 10:10:45 -0700 | [diff] [blame] | 373 | static struct commit_list *limit_list(struct commit_list *list) |
Linus Torvalds | 3b42a63 | 2005-06-02 09:25:44 -0700 | [diff] [blame] | 374 | { |
| 375 | struct commit_list *newlist = NULL; |
| 376 | struct commit_list **p = &newlist; |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 377 | while (list) { |
Linus Torvalds | 3b42a63 | 2005-06-02 09:25:44 -0700 | [diff] [blame] | 378 | struct commit *commit = pop_most_recent_commit(&list, SEEN); |
| 379 | struct object *obj = &commit->object; |
| 380 | |
Linus Torvalds | 12d2a18 | 2005-07-03 13:29:54 -0700 | [diff] [blame] | 381 | if (unpacked && has_sha1_pack(obj->sha1)) |
| 382 | obj->flags |= UNINTERESTING; |
Linus Torvalds | 337cb3f | 2005-06-04 14:38:28 -0700 | [diff] [blame] | 383 | if (obj->flags & UNINTERESTING) { |
Linus Torvalds | 3b42a63 | 2005-06-02 09:25:44 -0700 | [diff] [blame] | 384 | mark_parents_uninteresting(commit); |
| 385 | if (everybody_uninteresting(list)) |
| 386 | break; |
| 387 | continue; |
| 388 | } |
| 389 | p = &commit_list_insert(commit, p)->next; |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 390 | } |
Linus Torvalds | 8b3a1e0 | 2005-06-17 22:54:50 -0700 | [diff] [blame] | 391 | if (bisect_list) |
| 392 | newlist = find_bisection(newlist); |
Linus Torvalds | 3b42a63 | 2005-06-02 09:25:44 -0700 | [diff] [blame] | 393 | return newlist; |
| 394 | } |
| 395 | |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 396 | static void add_pending_object(struct object *obj, const char *name) |
| 397 | { |
| 398 | add_object(obj, &pending_objects, name); |
| 399 | } |
| 400 | |
Linus Torvalds | 3c90f03 | 2005-06-29 10:40:14 -0700 | [diff] [blame] | 401 | static struct commit *get_commit_reference(const char *name, unsigned int flags) |
| 402 | { |
| 403 | unsigned char sha1[20]; |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 404 | struct object *object; |
Linus Torvalds | 3c90f03 | 2005-06-29 10:40:14 -0700 | [diff] [blame] | 405 | |
| 406 | if (get_sha1(name, sha1)) |
| 407 | usage(rev_list_usage); |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 408 | object = parse_object(sha1); |
| 409 | if (!object) |
| 410 | die("bad object %s", name); |
| 411 | |
| 412 | /* |
| 413 | * Tag object? Look what it points to.. |
| 414 | */ |
Junio C Hamano | 013aab8 | 2005-07-10 23:55:56 -0700 | [diff] [blame] | 415 | while (object->type == tag_type) { |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 416 | struct tag *tag = (struct tag *) object; |
| 417 | object->flags |= flags; |
| 418 | if (tag_objects && !(object->flags & UNINTERESTING)) |
| 419 | add_pending_object(object, tag->tag); |
Junio C Hamano | 013aab8 | 2005-07-10 23:55:56 -0700 | [diff] [blame] | 420 | object = parse_object(tag->tagged->sha1); |
Sergey Vlasov | 7f1335c | 2005-08-19 22:28:35 +0400 | [diff] [blame] | 421 | if (!object) |
| 422 | die("bad object %s", sha1_to_hex(tag->tagged->sha1)); |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 423 | } |
| 424 | |
| 425 | /* |
| 426 | * Commit object? Just return it, we'll do all the complex |
| 427 | * reachability crud. |
| 428 | */ |
| 429 | if (object->type == commit_type) { |
| 430 | struct commit *commit = (struct commit *)object; |
| 431 | object->flags |= flags; |
| 432 | if (parse_commit(commit) < 0) |
| 433 | die("unable to parse commit %s", name); |
Linus Torvalds | 454fbbc | 2005-07-10 15:09:46 -0700 | [diff] [blame] | 434 | if (flags & UNINTERESTING) |
| 435 | mark_parents_uninteresting(commit); |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 436 | return commit; |
| 437 | } |
| 438 | |
| 439 | /* |
| 440 | * Tree object? Either mark it uniniteresting, or add it |
| 441 | * to the list of objects to look at later.. |
| 442 | */ |
| 443 | if (object->type == tree_type) { |
| 444 | struct tree *tree = (struct tree *)object; |
| 445 | if (!tree_objects) |
Linus Torvalds | 960bba0 | 2005-07-03 13:07:52 -0700 | [diff] [blame] | 446 | return NULL; |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 447 | if (flags & UNINTERESTING) { |
| 448 | mark_tree_uninteresting(tree); |
| 449 | return NULL; |
| 450 | } |
| 451 | add_pending_object(object, ""); |
| 452 | return NULL; |
| 453 | } |
| 454 | |
| 455 | /* |
| 456 | * Blob object? You know the drill by now.. |
| 457 | */ |
| 458 | if (object->type == blob_type) { |
| 459 | struct blob *blob = (struct blob *)object; |
| 460 | if (!blob_objects) |
Linus Torvalds | 960bba0 | 2005-07-03 13:07:52 -0700 | [diff] [blame] | 461 | return NULL; |
Linus Torvalds | 36f8d17 | 2005-06-29 11:30:24 -0700 | [diff] [blame] | 462 | if (flags & UNINTERESTING) { |
| 463 | mark_blob_uninteresting(blob); |
| 464 | return NULL; |
| 465 | } |
| 466 | add_pending_object(object, ""); |
| 467 | return NULL; |
| 468 | } |
| 469 | die("%s is unknown object", name); |
Linus Torvalds | 3c90f03 | 2005-06-29 10:40:14 -0700 | [diff] [blame] | 470 | } |
| 471 | |
Junio C Hamano | 1215879 | 2005-08-04 02:31:15 -0700 | [diff] [blame] | 472 | static void handle_one_commit(struct commit *com, struct commit_list **lst) |
| 473 | { |
| 474 | if (!com || com->object.flags & SEEN) |
| 475 | return; |
| 476 | com->object.flags |= SEEN; |
| 477 | commit_list_insert(com, lst); |
| 478 | } |
| 479 | |
| 480 | |
Linus Torvalds | 6474510 | 2005-04-23 19:04:40 -0700 | [diff] [blame] | 481 | int main(int argc, char **argv) |
| 482 | { |
Linus Torvalds | 6474510 | 2005-04-23 19:04:40 -0700 | [diff] [blame] | 483 | struct commit_list *list = NULL; |
Linus Torvalds | 337cb3f | 2005-06-04 14:38:28 -0700 | [diff] [blame] | 484 | int i, limited = 0; |
Linus Torvalds | 6474510 | 2005-04-23 19:04:40 -0700 | [diff] [blame] | 485 | |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 486 | setup_git_directory(); |
Kay Sievers | fcfda02 | 2005-05-06 10:00:11 +0200 | [diff] [blame] | 487 | for (i = 1 ; i < argc; i++) { |
Linus Torvalds | 337cb3f | 2005-06-04 14:38:28 -0700 | [diff] [blame] | 488 | int flags; |
Kay Sievers | fcfda02 | 2005-05-06 10:00:11 +0200 | [diff] [blame] | 489 | char *arg = argv[i]; |
Junio C Hamano | 1215879 | 2005-08-04 02:31:15 -0700 | [diff] [blame] | 490 | char *dotdot; |
Linus Torvalds | 337cb3f | 2005-06-04 14:38:28 -0700 | [diff] [blame] | 491 | struct commit *commit; |
Kay Sievers | fcfda02 | 2005-05-06 10:00:11 +0200 | [diff] [blame] | 492 | |
| 493 | if (!strncmp(arg, "--max-count=", 12)) { |
| 494 | max_count = atoi(arg + 12); |
Linus Torvalds | a6f68d4 | 2005-05-25 18:29:09 -0700 | [diff] [blame] | 495 | continue; |
Kay Sievers | fcfda02 | 2005-05-06 10:00:11 +0200 | [diff] [blame] | 496 | } |
Linus Torvalds | a6f68d4 | 2005-05-25 18:29:09 -0700 | [diff] [blame] | 497 | if (!strncmp(arg, "--max-age=", 10)) { |
| 498 | max_age = atoi(arg + 10); |
| 499 | continue; |
| 500 | } |
| 501 | if (!strncmp(arg, "--min-age=", 10)) { |
| 502 | min_age = atoi(arg + 10); |
| 503 | continue; |
| 504 | } |
| 505 | if (!strcmp(arg, "--header")) { |
| 506 | verbose_header = 1; |
| 507 | continue; |
| 508 | } |
Linus Torvalds | 000182e | 2005-06-05 09:02:03 -0700 | [diff] [blame] | 509 | if (!strncmp(arg, "--pretty", 8)) { |
| 510 | commit_format = get_commit_format(arg+8); |
Linus Torvalds | 9d97aa6 | 2005-06-01 08:42:22 -0700 | [diff] [blame] | 511 | verbose_header = 1; |
Linus Torvalds | 9d97aa6 | 2005-06-01 08:42:22 -0700 | [diff] [blame] | 512 | hdr_termination = '\n'; |
Junio C Hamano | d87449c | 2005-08-08 22:15:40 -0700 | [diff] [blame] | 513 | if (commit_format == CMIT_FMT_ONELINE) |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 514 | commit_prefix = ""; |
Junio C Hamano | d87449c | 2005-08-08 22:15:40 -0700 | [diff] [blame] | 515 | else |
Pavel Roskin | d998a08 | 2005-08-24 17:58:42 -0400 | [diff] [blame] | 516 | commit_prefix = "commit "; |
Linus Torvalds | 9d97aa6 | 2005-06-01 08:42:22 -0700 | [diff] [blame] | 517 | continue; |
| 518 | } |
Johannes Schindelin | 76cd8eb | 2005-08-08 11:37:21 +0200 | [diff] [blame] | 519 | if (!strncmp(arg, "--no-merges", 11)) { |
| 520 | no_merges = 1; |
| 521 | continue; |
| 522 | } |
Linus Torvalds | 9765800 | 2005-05-30 19:30:07 -0700 | [diff] [blame] | 523 | if (!strcmp(arg, "--parents")) { |
| 524 | show_parents = 1; |
| 525 | continue; |
| 526 | } |
Linus Torvalds | 8b3a1e0 | 2005-06-17 22:54:50 -0700 | [diff] [blame] | 527 | if (!strcmp(arg, "--bisect")) { |
| 528 | bisect_list = 1; |
| 529 | continue; |
| 530 | } |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 531 | if (!strcmp(arg, "--objects")) { |
Linus Torvalds | 3c90f03 | 2005-06-29 10:40:14 -0700 | [diff] [blame] | 532 | tag_objects = 1; |
Linus Torvalds | 9de4875 | 2005-06-24 22:56:58 -0700 | [diff] [blame] | 533 | tree_objects = 1; |
| 534 | blob_objects = 1; |
| 535 | continue; |
| 536 | } |
Linus Torvalds | 12d2a18 | 2005-07-03 13:29:54 -0700 | [diff] [blame] | 537 | if (!strcmp(arg, "--unpacked")) { |
| 538 | unpacked = 1; |
| 539 | limited = 1; |
| 540 | continue; |
| 541 | } |
Linus Torvalds | 12ba7ea | 2005-07-05 12:12:50 -0700 | [diff] [blame] | 542 | if (!strcmp(arg, "--merge-order")) { |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 543 | merge_order = 1; |
| 544 | continue; |
| 545 | } |
Linus Torvalds | 12ba7ea | 2005-07-05 12:12:50 -0700 | [diff] [blame] | 546 | if (!strcmp(arg, "--show-breaks")) { |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 547 | show_breaks = 1; |
| 548 | continue; |
| 549 | } |
Linus Torvalds | d2d02a4 | 2005-07-06 10:25:04 -0700 | [diff] [blame] | 550 | if (!strcmp(arg, "--topo-order")) { |
| 551 | topo_order = 1; |
Linus Torvalds | e6c3505 | 2005-07-06 10:51:43 -0700 | [diff] [blame] | 552 | limited = 1; |
Linus Torvalds | d2d02a4 | 2005-07-06 10:25:04 -0700 | [diff] [blame] | 553 | continue; |
| 554 | } |
Linus Torvalds | a6f68d4 | 2005-05-25 18:29:09 -0700 | [diff] [blame] | 555 | |
Junio C Hamano | 1215879 | 2005-08-04 02:31:15 -0700 | [diff] [blame] | 556 | if (show_breaks && !merge_order) |
| 557 | usage(rev_list_usage); |
| 558 | |
Linus Torvalds | 337cb3f | 2005-06-04 14:38:28 -0700 | [diff] [blame] | 559 | flags = 0; |
Junio C Hamano | 1215879 | 2005-08-04 02:31:15 -0700 | [diff] [blame] | 560 | dotdot = strstr(arg, ".."); |
| 561 | if (dotdot) { |
| 562 | char *next = dotdot + 2; |
| 563 | struct commit *exclude = NULL; |
| 564 | struct commit *include = NULL; |
| 565 | *dotdot = 0; |
| 566 | exclude = get_commit_reference(arg, UNINTERESTING); |
| 567 | include = get_commit_reference(next, 0); |
| 568 | if (exclude && include) { |
| 569 | limited = 1; |
| 570 | handle_one_commit(exclude, &list); |
| 571 | handle_one_commit(include, &list); |
| 572 | continue; |
| 573 | } |
| 574 | *next = '.'; |
| 575 | } |
Linus Torvalds | 337cb3f | 2005-06-04 14:38:28 -0700 | [diff] [blame] | 576 | if (*arg == '^') { |
| 577 | flags = UNINTERESTING; |
| 578 | arg++; |
| 579 | limited = 1; |
| 580 | } |
Linus Torvalds | 3c90f03 | 2005-06-29 10:40:14 -0700 | [diff] [blame] | 581 | commit = get_commit_reference(arg, flags); |
Junio C Hamano | 1215879 | 2005-08-04 02:31:15 -0700 | [diff] [blame] | 582 | handle_one_commit(commit, &list); |
Kay Sievers | fcfda02 | 2005-05-06 10:00:11 +0200 | [diff] [blame] | 583 | } |
| 584 | |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 585 | if (!merge_order) { |
Jon Seymour | a7336ae | 2005-07-07 10:59:13 +1000 | [diff] [blame] | 586 | sort_by_date(&list); |
Petr Baudis | 17ebe97 | 2005-06-08 22:59:43 +0200 | [diff] [blame] | 587 | if (limited) |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 588 | list = limit_list(list); |
Linus Torvalds | d2d02a4 | 2005-07-06 10:25:04 -0700 | [diff] [blame] | 589 | if (topo_order) |
| 590 | sort_in_topological_order(&list); |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 591 | show_commit_list(list); |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 592 | } else { |
Petr Baudis | dd53c7a | 2005-07-29 17:50:51 +0200 | [diff] [blame] | 593 | #ifndef NO_OPENSSL |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 594 | if (sort_list_in_merge_order(list, &process_commit)) { |
Petr Baudis | dd53c7a | 2005-07-29 17:50:51 +0200 | [diff] [blame] | 595 | die("merge order sort failed\n"); |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 596 | } |
Petr Baudis | dd53c7a | 2005-07-29 17:50:51 +0200 | [diff] [blame] | 597 | #else |
| 598 | die("merge order sort unsupported, OpenSSL not linked"); |
| 599 | #endif |
jon@blackcubes.dyndns.org | a3437b8 | 2005-06-06 15:39:40 +0000 | [diff] [blame] | 600 | } |
Linus Torvalds | 8906300 | 2005-05-30 18:46:32 -0700 | [diff] [blame] | 601 | |
Linus Torvalds | 6474510 | 2005-04-23 19:04:40 -0700 | [diff] [blame] | 602 | return 0; |
| 603 | } |