diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | epoch.c | 1 | ||||
-rw-r--r-- | epoch.h | 1 | ||||
-rw-r--r-- | rev-list.c | 397 | ||||
-rw-r--r-- | revision.c | 370 | ||||
-rw-r--r-- | revision.h | 48 |
6 files changed, 464 insertions, 357 deletions
@@ -192,7 +192,7 @@ LIB_FILE=libgit.a LIB_H = \ blob.h cache.h commit.h count-delta.h csum-file.h delta.h \ diff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \ - run-command.h strbuf.h tag.h tree.h git-compat-util.h + run-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h DIFF_OBJS = \ diff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \ @@ -205,7 +205,7 @@ LIB_OBJS = \ quote.o read-cache.o refs.o run-command.o \ server-info.o setup.o sha1_file.o sha1_name.o strbuf.o \ tag.o tree.o usage.o config.o environment.o ctype.o copy.o \ - fetch-clone.o \ + fetch-clone.o revision.o \ $(DIFF_OBJS) LIBS = $(LIB_FILE) @@ -15,6 +15,7 @@ #include "cache.h" #include "commit.h" +#include "revision.h" #include "epoch.h" struct fraction { @@ -11,7 +11,6 @@ typedef int (*emitter_func) (struct commit *); int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter); /* Low bits are used by rev-list */ -#define UNINTERESTING (1u<<10) #define BOUNDARY (1u<<11) #define VISITED (1u<<12) #define DISCONTINUITY (1u<<13) diff --git a/rev-list.c b/rev-list.c index 67d2a483f..d1c52a6a9 100644 --- a/rev-list.c +++ b/rev-list.c @@ -6,9 +6,10 @@ #include "blob.h" #include "epoch.h" #include "diff.h" +#include "revision.h" + +/* bits #0 and #1 in revision.h */ -#define SEEN (1u << 0) -#define INTERESTING (1u << 1) #define COUNTED (1u << 2) #define SHOWN (1u << 3) #define TREECHANGE (1u << 4) @@ -38,60 +39,20 @@ static const char rev_list_usage[] = " --bisect" ; -static int dense = 1; +struct rev_info revs; + static int unpacked = 0; static int bisect_list = 0; -static int tag_objects = 0; -static int tree_objects = 0; -static int blob_objects = 0; -static int edge_hint = 0; static int verbose_header = 0; static int abbrev = DEFAULT_ABBREV; static int show_parents = 0; static int hdr_termination = 0; static const char *commit_prefix = ""; -static unsigned long max_age = -1; -static unsigned long min_age = -1; -static int max_count = -1; static enum cmit_fmt commit_format = CMIT_FMT_RAW; static int merge_order = 0; static int show_breaks = 0; static int stop_traversal = 0; -static int topo_order = 0; -static int lifo = 1; static int no_merges = 0; -static const char **paths = NULL; -static int remove_empty_trees = 0; - -struct name_path { - struct name_path *up; - int elem_len; - const char *elem; -}; - -static char *path_name(struct name_path *path, const char *name) -{ - struct name_path *p; - char *n, *m; - int nlen = strlen(name); - int len = nlen + 1; - - for (p = path; p; p = p->up) { - if (p->elem_len) - len += p->elem_len + 1; - } - n = xmalloc(len); - m = n + len - (nlen + 1); - strcpy(m, name); - for (p = path; p; p = p->up) { - if (p->elem_len) { - m -= p->elem_len + 1; - memcpy(m, p->elem, p->elem_len); - m[p->elem_len] = '/'; - } - } - return n; -} static void show_commit(struct commit *commit) { @@ -168,15 +129,15 @@ static int filter_commit(struct commit * commit) return STOP; if (commit->object.flags & (UNINTERESTING|SHOWN)) return CONTINUE; - if (min_age != -1 && (commit->date > min_age)) + if (revs.min_age != -1 && (commit->date > revs.min_age)) return CONTINUE; - if (max_age != -1 && (commit->date < max_age)) { + if (revs.max_age != -1 && (commit->date < revs.max_age)) { stop_traversal=1; return CONTINUE; } if (no_merges && (commit->parents && commit->parents->next)) return CONTINUE; - if (paths && dense) { + if (revs.paths && revs.dense) { if (!(commit->object.flags & TREECHANGE)) return CONTINUE; rewrite_parents(commit); @@ -196,7 +157,7 @@ static int process_commit(struct commit * commit) return CONTINUE; } - if (max_count != -1 && !max_count--) + if (revs.max_count != -1 && !revs.max_count--) return STOP; show_commit(commit); @@ -204,19 +165,6 @@ static int process_commit(struct commit * commit) return CONTINUE; } -static struct object_list **add_object(struct object *obj, - struct object_list **p, - struct name_path *path, - const char *name) -{ - struct object_list *entry = xmalloc(sizeof(*entry)); - entry->item = obj; - entry->next = *p; - entry->name = path_name(path, name); - *p = entry; - return &entry->next; -} - static struct object_list **process_blob(struct blob *blob, struct object_list **p, struct name_path *path, @@ -224,7 +172,7 @@ static struct object_list **process_blob(struct blob *blob, { struct object *obj = &blob->object; - if (!blob_objects) + if (!revs.blob_objects) return p; if (obj->flags & (UNINTERESTING | SEEN)) return p; @@ -241,7 +189,7 @@ static struct object_list **process_tree(struct tree *tree, struct tree_entry_list *entry; struct name_path me; - if (!tree_objects) + if (!revs.tree_objects) return p; if (obj->flags & (UNINTERESTING | SEEN)) return p; @@ -314,75 +262,6 @@ static void show_commit_list(struct commit_list *list) } } -static void mark_blob_uninteresting(struct blob *blob) -{ - if (!blob_objects) - return; - if (blob->object.flags & UNINTERESTING) - return; - blob->object.flags |= UNINTERESTING; -} - -static void mark_tree_uninteresting(struct tree *tree) -{ - struct object *obj = &tree->object; - struct tree_entry_list *entry; - - if (!tree_objects) - return; - if (obj->flags & UNINTERESTING) - return; - obj->flags |= UNINTERESTING; - if (!has_sha1_file(obj->sha1)) - return; - if (parse_tree(tree) < 0) - die("bad tree %s", sha1_to_hex(obj->sha1)); - entry = tree->entries; - tree->entries = NULL; - while (entry) { - struct tree_entry_list *next = entry->next; - if (entry->directory) - mark_tree_uninteresting(entry->item.tree); - else - mark_blob_uninteresting(entry->item.blob); - free(entry); - entry = next; - } -} - -static void mark_parents_uninteresting(struct commit *commit) -{ - struct commit_list *parents = commit->parents; - - while (parents) { - struct commit *commit = parents->item; - commit->object.flags |= UNINTERESTING; - - /* - * Normally we haven't parsed the parent - * yet, so we won't have a parent of a parent - * here. However, it may turn out that we've - * reached this commit some other way (where it - * wasn't uninteresting), in which case we need - * to mark its parents recursively too.. - */ - if (commit->parents) - mark_parents_uninteresting(commit); - - /* - * A missing commit is ok iff its parent is marked - * uninteresting. - * - * We just mark such a thing parsed, so that when - * it is popped next time around, we won't be trying - * to parse it and get an error. - */ - if (!has_sha1_file(commit->object.sha1)) - commit->object.parsed = 1; - parents = parents->next; - } -} - static int everybody_uninteresting(struct commit_list *orig) { struct commit_list *list = orig; @@ -413,7 +292,7 @@ static int count_distance(struct commit_list *entry) if (commit->object.flags & (UNINTERESTING | COUNTED)) break; - if (!paths || (commit->object.flags & TREECHANGE)) + if (!revs.paths || (commit->object.flags & TREECHANGE)) nr++; commit->object.flags |= COUNTED; p = commit->parents; @@ -447,7 +326,7 @@ static struct commit_list *find_bisection(struct commit_list *list) nr = 0; p = list; while (p) { - if (!paths || (p->item->object.flags & TREECHANGE)) + if (!revs.paths || (p->item->object.flags & TREECHANGE)) nr++; p = p->next; } @@ -457,7 +336,7 @@ static struct commit_list *find_bisection(struct commit_list *list) for (p = list; p; p = p->next) { int distance; - if (paths && !(p->item->object.flags & TREECHANGE)) + if (revs.paths && !(p->item->object.flags & TREECHANGE)) continue; distance = count_distance(p); @@ -483,7 +362,7 @@ static void mark_edge_parents_uninteresting(struct commit *commit) if (!(parent->object.flags & UNINTERESTING)) continue; mark_tree_uninteresting(parent->tree); - if (edge_hint && !(parent->object.flags & SHOWN)) { + if (revs.edge_hint && !(parent->object.flags & SHOWN)) { parent->object.flags |= SHOWN; printf("-%s\n", sha1_to_hex(parent->object.sha1)); } @@ -613,7 +492,7 @@ static void try_to_simplify_commit(struct commit *commit) return; case TREE_NEW: - if (remove_empty_trees && same_tree_as_empty(p->tree)) { + if (revs.remove_empty_trees && same_tree_as_empty(p->tree)) { *pp = parent->next; continue; } @@ -664,7 +543,7 @@ static void add_parents_to_list(struct commit *commit, struct commit_list **list * simplify the commit history and find the parent * that has no differences in the path set if one exists. */ - if (paths) + if (revs.paths) try_to_simplify_commit(commit); parent = commit->parents; @@ -693,7 +572,7 @@ static struct commit_list *limit_list(struct commit_list *list) list = list->next; free(entry); - if (max_age != -1 && (commit->date < max_age)) + if (revs.max_age != -1 && (commit->date < revs.max_age)) obj->flags |= UNINTERESTING; if (unpacked && has_sha1_pack(obj->sha1)) obj->flags |= UNINTERESTING; @@ -704,155 +583,40 @@ static struct commit_list *limit_list(struct commit_list *list) break; continue; } - if (min_age != -1 && (commit->date > min_age)) + if (revs.min_age != -1 && (commit->date > revs.min_age)) continue; p = &commit_list_insert(commit, p)->next; } - if (tree_objects) + if (revs.tree_objects) mark_edges_uninteresting(newlist); if (bisect_list) newlist = find_bisection(newlist); return newlist; } -static void add_pending_object(struct object *obj, const char *name) -{ - add_object(obj, &pending_objects, NULL, name); -} - -static struct commit *get_commit_reference(const char *name, const unsigned char *sha1, unsigned int flags) -{ - struct object *object; - - object = parse_object(sha1); - if (!object) - die("bad object %s", name); - - /* - * Tag object? Look what it points to.. - */ - while (object->type == tag_type) { - struct tag *tag = (struct tag *) object; - object->flags |= flags; - if (tag_objects && !(object->flags & UNINTERESTING)) - add_pending_object(object, tag->tag); - object = parse_object(tag->tagged->sha1); - if (!object) - die("bad object %s", sha1_to_hex(tag->tagged->sha1)); - } - - /* - * Commit object? Just return it, we'll do all the complex - * reachability crud. - */ - if (object->type == commit_type) { - struct commit *commit = (struct commit *)object; - object->flags |= flags; - if (parse_commit(commit) < 0) - die("unable to parse commit %s", name); - if (flags & UNINTERESTING) - mark_parents_uninteresting(commit); - return commit; - } - - /* - * Tree object? Either mark it uniniteresting, or add it - * to the list of objects to look at later.. - */ - if (object->type == tree_type) { - struct tree *tree = (struct tree *)object; - if (!tree_objects) - return NULL; - if (flags & UNINTERESTING) { - mark_tree_uninteresting(tree); - return NULL; - } - add_pending_object(object, ""); - return NULL; - } - - /* - * Blob object? You know the drill by now.. - */ - if (object->type == blob_type) { - struct blob *blob = (struct blob *)object; - if (!blob_objects) - return NULL; - if (flags & UNINTERESTING) { - mark_blob_uninteresting(blob); - return NULL; - } - add_pending_object(object, ""); - return NULL; - } - die("%s is unknown object", name); -} - -static void handle_one_commit(struct commit *com, struct commit_list **lst) -{ - if (!com || com->object.flags & SEEN) - return; - com->object.flags |= SEEN; - commit_list_insert(com, lst); -} - -/* for_each_ref() callback does not allow user data -- Yuck. */ -static struct commit_list **global_lst; - -static int include_one_commit(const char *path, const unsigned char *sha1) -{ - struct commit *com = get_commit_reference(path, sha1, 0); - handle_one_commit(com, global_lst); - return 0; -} - -static void handle_all(struct commit_list **lst) -{ - global_lst = lst; - for_each_ref(include_one_commit); - global_lst = NULL; -} - int main(int argc, const char **argv) { - const char *prefix = setup_git_directory(); - struct commit_list *list = NULL; + struct commit_list *list; int i, limited = 0; + argc = setup_revisions(argc, argv, &revs); + for (i = 1 ; i < argc; i++) { - int flags; const char *arg = argv[i]; - char *dotdot; - struct commit *commit; - unsigned char sha1[20]; /* accept -<digit>, like traditilnal "head" */ if ((*arg == '-') && isdigit(arg[1])) { - max_count = atoi(arg + 1); + revs.max_count = atoi(arg + 1); continue; } if (!strcmp(arg, "-n")) { if (++i >= argc) die("-n requires an argument"); - max_count = atoi(argv[i]); + revs.max_count = atoi(argv[i]); continue; } if (!strncmp(arg,"-n",2)) { - max_count = atoi(arg + 2); - continue; - } - if (!strncmp(arg, "--max-count=", 12)) { - max_count = atoi(arg + 12); - continue; - } - if (!strncmp(arg, "--max-age=", 10)) { - max_age = atoi(arg + 10); - limited = 1; - continue; - } - if (!strncmp(arg, "--min-age=", 10)) { - min_age = atoi(arg + 10); - limited = 1; + revs.max_count = atoi(arg + 2); continue; } if (!strcmp(arg, "--header")) { @@ -893,23 +657,6 @@ int main(int argc, const char **argv) bisect_list = 1; continue; } - if (!strcmp(arg, "--all")) { - handle_all(&list); - continue; - } - if (!strcmp(arg, "--objects")) { - tag_objects = 1; - tree_objects = 1; - blob_objects = 1; - continue; - } - if (!strcmp(arg, "--objects-edge")) { - tag_objects = 1; - tree_objects = 1; - blob_objects = 1; - edge_hint = 1; - continue; - } if (!strcmp(arg, "--unpacked")) { unpacked = 1; limited = 1; @@ -923,100 +670,42 @@ int main(int argc, const char **argv) show_breaks = 1; continue; } - if (!strcmp(arg, "--topo-order")) { - topo_order = 1; - lifo = 1; - limited = 1; - continue; - } - if (!strcmp(arg, "--date-order")) { - topo_order = 1; - lifo = 0; - limited = 1; - continue; - } - if (!strcmp(arg, "--dense")) { - dense = 1; - continue; - } - if (!strcmp(arg, "--sparse")) { - dense = 0; - continue; - } - if (!strcmp(arg, "--remove-empty")) { - remove_empty_trees = 1; - continue; - } - if (!strcmp(arg, "--")) { - i++; - break; - } + usage(rev_list_usage); - if (show_breaks && !merge_order) - usage(rev_list_usage); - - flags = 0; - dotdot = strstr(arg, ".."); - if (dotdot) { - unsigned char from_sha1[20]; - char *next = dotdot + 2; - *dotdot = 0; - if (!*next) - next = "HEAD"; - if (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) { - struct commit *exclude; - struct commit *include; - - exclude = get_commit_reference(arg, from_sha1, UNINTERESTING); - include = get_commit_reference(next, sha1, 0); - if (!exclude || !include) - die("Invalid revision range %s..%s", arg, next); - limited = 1; - handle_one_commit(exclude, &list); - handle_one_commit(include, &list); - continue; - } - *dotdot = '.'; - } - if (*arg == '^') { - flags = UNINTERESTING; - arg++; - limited = 1; - } - if (get_sha1(arg, sha1) < 0) { - struct stat st; - if (lstat(arg, &st) < 0) - die("'%s': %s", arg, strerror(errno)); - break; - } - commit = get_commit_reference(arg, sha1, flags); - handle_one_commit(commit, &list); } + list = revs.commits; + if (list && list->next) + limited = 1; + + if (revs.topo_order) + limited = 1; + if (!list && - (!(tag_objects||tree_objects||blob_objects) && !pending_objects)) + (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects)) usage(rev_list_usage); - paths = get_pathspec(prefix, argv + i); - if (paths) { + if (revs.paths) { limited = 1; - diff_tree_setup_paths(paths); + diff_tree_setup_paths(revs.paths); } + if (revs.max_age || revs.min_age) + limited = 1; save_commit_buffer = verbose_header; track_object_refs = 0; if (!merge_order) { sort_by_date(&list); - if (list && !limited && max_count == 1 && - !tag_objects && !tree_objects && !blob_objects) { + if (list && !limited && revs.max_count == 1 && + !revs.tag_objects && !revs.tree_objects && !revs.blob_objects) { show_commit(list->item); return 0; } if (limited) list = limit_list(list); - if (topo_order) - sort_in_topological_order(&list, lifo); + if (revs.topo_order) + sort_in_topological_order(&list, revs.lifo); show_commit_list(list); } else { #ifndef NO_OPENSSL diff --git a/revision.c b/revision.c new file mode 100644 index 000000000..d61410bc5 --- /dev/null +++ b/revision.c @@ -0,0 +1,370 @@ +#include "cache.h" +#include "tag.h" +#include "blob.h" +#include "tree.h" +#include "commit.h" +#include "refs.h" +#include "revision.h" + +static char *path_name(struct name_path *path, const char *name) +{ + struct name_path *p; + char *n, *m; + int nlen = strlen(name); + int len = nlen + 1; + + for (p = path; p; p = p->up) { + if (p->elem_len) + len += p->elem_len + 1; + } + n = xmalloc(len); + m = n + len - (nlen + 1); + strcpy(m, name); + for (p = path; p; p = p->up) { + if (p->elem_len) { + m -= p->elem_len + 1; + memcpy(m, p->elem, p->elem_len); + m[p->elem_len] = '/'; + } + } + return n; +} + +struct object_list **add_object(struct object *obj, + struct object_list **p, + struct name_path *path, + const char *name) +{ + struct object_list *entry = xmalloc(sizeof(*entry)); + entry->item = obj; + entry->next = *p; + entry->name = path_name(path, name); + *p = entry; + return &entry->next; +} + +static void mark_blob_uninteresting(struct blob *blob) +{ + if (blob->object.flags & UNINTERESTING) + return; + blob->object.flags |= UNINTERESTING; +} + +void mark_tree_uninteresting(struct tree *tree) +{ + struct object *obj = &tree->object; + struct tree_entry_list *entry; + + if (obj->flags & UNINTERESTING) + return; + obj->flags |= UNINTERESTING; + if (!has_sha1_file(obj->sha1)) + return; + if (parse_tree(tree) < 0) + die("bad tree %s", sha1_to_hex(obj->sha1)); + entry = tree->entries; + tree->entries = NULL; + while (entry) { + struct tree_entry_list *next = entry->next; + if (entry->directory) + mark_tree_uninteresting(entry->item.tree); + else + mark_blob_uninteresting(entry->item.blob); + free(entry); + entry = next; + } +} + +void mark_parents_uninteresting(struct commit *commit) +{ + struct commit_list *parents = commit->parents; + + while (parents) { + struct commit *commit = parents->item; + commit->object.flags |= UNINTERESTING; + + /* + * Normally we haven't parsed the parent + * yet, so we won't have a parent of a parent + * here. However, it may turn out that we've + * reached this commit some other way (where it + * wasn't uninteresting), in which case we need + * to mark its parents recursively too.. + */ + if (commit->parents) + mark_parents_uninteresting(commit); + + /* + * A missing commit is ok iff its parent is marked + * uninteresting. + * + * We just mark such a thing parsed, so that when + * it is popped next time around, we won't be trying + * to parse it and get an error. + */ + if (!has_sha1_file(commit->object.sha1)) + commit->object.parsed = 1; + parents = parents->next; + } +} + +static void add_pending_object(struct rev_info *revs, struct object *obj, const char *name) +{ + add_object(obj, &revs->pending_objects, NULL, name); +} + +static struct commit *get_commit_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags) +{ + struct object *object; + + object = parse_object(sha1); + if (!object) + die("bad object %s", name); + + /* + * Tag object? Look what it points to.. + */ + while (object->type == tag_type) { + struct tag *tag = (struct tag *) object; + object->flags |= flags; + if (revs->tag_objects && !(object->flags & UNINTERESTING)) + add_pending_object(revs, object, tag->tag); + object = parse_object(tag->tagged->sha1); + if (!object) + die("bad object %s", sha1_to_hex(tag->tagged->sha1)); + } + + /* + * Commit object? Just return it, we'll do all the complex + * reachability crud. + */ + if (object->type == commit_type) { + struct commit *commit = (struct commit *)object; + object->flags |= flags; + if (parse_commit(commit) < 0) + die("unable to parse commit %s", name); + if (flags & UNINTERESTING) + mark_parents_uninteresting(commit); + return commit; + } + + /* + * Tree object? Either mark it uniniteresting, or add it + * to the list of objects to look at later.. + */ + if (object->type == tree_type) { + struct tree *tree = (struct tree *)object; + if (!revs->tree_objects) + return NULL; + if (flags & UNINTERESTING) { + mark_tree_uninteresting(tree); + return NULL; + } + add_pending_object(revs, object, ""); + return NULL; + } + + /* + * Blob object? You know the drill by now.. + */ + if (object->type == blob_type) { + struct blob *blob = (struct blob *)object; + if (!revs->blob_objects) + return NULL; + if (flags & UNINTERESTING) { + mark_blob_uninteresting(blob); + return NULL; + } + add_pending_object(revs, object, ""); + return NULL; + } + die("%s is unknown object", name); +} + +static void add_one_commit(struct commit *commit, struct rev_info *revs) +{ + if (!commit || (commit->object.flags & SEEN)) + return; + commit->object.flags |= SEEN; + commit_list_insert(commit, &revs->commits); +} + +static int all_flags; +static struct rev_info *all_revs; + +static int handle_one_ref(const char *path, const unsigned char *sha1) +{ + struct commit *commit = get_commit_reference(all_revs, path, sha1, all_flags); + add_one_commit(commit, all_revs); + return 0; +} + +static void handle_all(struct rev_info *revs, unsigned flags) +{ + all_revs = revs; + all_flags = flags; + for_each_ref(handle_one_ref); +} + +/* + * Parse revision information, filling in the "rev_info" structure, + * and removing the used arguments from the argument list. + * + * Returns the number of arguments left ("new argc"). + */ +int setup_revisions(int argc, const char **argv, struct rev_info *revs) +{ + int i, flags, seen_dashdash; + const char *def = NULL; + const char **unrecognized = argv+1; + int left = 1; + + memset(revs, 0, sizeof(*revs)); + revs->lifo = 1; + revs->dense = 1; + revs->prefix = setup_git_directory(); + revs->max_age = -1; + revs->min_age = -1; + revs->max_count = -1; + + /* First, search for "--" */ + seen_dashdash = 0; + for (i = 1; i < argc; i++) { + const char *arg = argv[i]; + if (strcmp(arg, "--")) + continue; + argv[i] = NULL; + argc = i; + revs->paths = get_pathspec(revs->prefix, argv + i + 1); + seen_dashdash = 1; + break; + } + + flags = 0; + for (i = 1; i < argc; i++) { + struct commit *commit; + const char *arg = argv[i]; + unsigned char sha1[20]; + char *dotdot; + int local_flags; + + if (*arg == '-') { + if (!strncmp(arg, "--max-count=", 12)) { + revs->max_count = atoi(arg + 12); + continue; + } + if (!strncmp(arg, "--max-age=", 10)) { + revs->max_age = atoi(arg + 10); + continue; + } + if (!strncmp(arg, "--min-age=", 10)) { + revs->min_age = atoi(arg + 10); + continue; + } + if (!strcmp(arg, "--all")) { + handle_all(revs, flags); + continue; + } + if (!strcmp(arg, "--not")) { + flags ^= UNINTERESTING; + continue; + } + if (!strcmp(arg, "--default")) { + if (++i >= argc) + die("bad --default argument"); + def = argv[i]; + continue; + } + if (!strcmp(arg, "--topo-order")) { + revs->topo_order = 1; + continue; + } + if (!strcmp(arg, "--date-order")) { + revs->lifo = 0; + revs->topo_order = 1; + continue; + } + if (!strcmp(arg, "--dense")) { + revs->dense = 1; + continue; + } + if (!strcmp(arg, "--sparse")) { + revs->dense = 0; + continue; + } + if (!strcmp(arg, "--remove-empty")) { + revs->remove_empty_trees = 1; + continue; + } + if (!strcmp(arg, "--objects")) { + revs->tag_objects = 1; + revs->tree_objects = 1; + revs->blob_objects = 1; + continue; + } + if (!strcmp(arg, "--objects-edge")) { + revs->tag_objects = 1; + revs->tree_objects = 1; + revs->blob_objects = 1; + revs->edge_hint = 1; + continue; + } + *unrecognized++ = arg; + left++; + continue; + } + dotdot = strstr(arg, ".."); + if (dotdot) { + unsigned char from_sha1[20]; + char *next = dotdot + 2; + *dotdot = 0; + if (!*next) + next = "HEAD"; + if (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) { + struct commit *exclude; + struct commit *include; + + exclude = get_commit_reference(revs, arg, from_sha1, flags ^ UNINTERESTING); + include = get_commit_reference(revs, next, sha1, flags); + if (!exclude || !include) + die("Invalid revision range %s..%s", arg, next); + add_one_commit(exclude, revs); + add_one_commit(include, revs); + continue; + } + *dotdot = '.'; + } + local_flags = 0; + if (*arg == '^') { + local_flags = UNINTERESTING; + arg++; + } + if (get_sha1(arg, sha1) < 0) { + struct stat st; + int j; + + if (seen_dashdash || local_flags) + die("bad revision '%s'", arg); + + /* If we didn't have a "--", all filenames must exist */ + for (j = i; j < argc; j++) { + if (lstat(argv[j], &st) < 0) + die("'%s': %s", arg, strerror(errno)); + } + revs->paths = get_pathspec(revs->prefix, argv + i); + break; + } + commit = get_commit_reference(revs, arg, sha1, flags ^ local_flags); + add_one_commit(commit, revs); + } + if (def && !revs->commits) { + unsigned char sha1[20]; + struct commit *commit; + if (get_sha1(def, sha1) < 0) + die("bad default revision '%s'", def); + commit = get_commit_reference(revs, def, sha1, 0); + add_one_commit(commit, revs); + } + *unrecognized = NULL; + return left; +} diff --git a/revision.h b/revision.h new file mode 100644 index 000000000..5170ac425 --- /dev/null +++ b/revision.h @@ -0,0 +1,48 @@ +#ifndef REVISION_H +#define REVISION_H + +#define SEEN (1u<<0) +#define UNINTERESTING (1u<<1) + +struct rev_info { + /* Starting list */ + struct commit_list *commits; + struct object_list *pending_objects; + + /* Basic information */ + const char *prefix; + const char **paths; + + /* Traversal flags */ + unsigned int dense:1, + remove_empty_trees:1, + lifo:1, + topo_order:1, + tag_objects:1, + tree_objects:1, + blob_objects:1, + edge_hint:1; + + /* special limits */ + int max_count; + unsigned long max_age; + unsigned long min_age; +}; + +/* revision.c */ +extern int setup_revisions(int argc, const char **argv, struct rev_info *revs); +extern void mark_parents_uninteresting(struct commit *commit); +extern void mark_tree_uninteresting(struct tree *tree); + +struct name_path { + struct name_path *up; + int elem_len; + const char *elem; +}; + +extern struct object_list **add_object(struct object *obj, + struct object_list **p, + struct name_path *path, + const char *name); + +#endif |