{"thread":{"id":"3463","subject":"[PATCH] First cut at libifying revlist generation","startedAt":"2006-02-26T00:19:46Z","lastAt":"2006-02-28T01:13:14Z","messageCount":12,"participants":["Linus Torvalds","Junio C Hamano","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"16734","messageId":"Pine.LNX.4.64.0602251608160.22647@g5.osdl.org","threadId":"3463","inReplyTo":null,"subject":"[PATCH] First cut at libifying revlist generation","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-02-26T00:19:46Z","receivedAt":"2006-02-26T00:19:46Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis really just splits things up partially, and creates the\ninterface to set things up by parsign the command line.\n\nNo real code changes so far, although the parsing of filenames is a bit \nstricter. In particular, if there is a \"--\", then we do not accept any \nfilenames before it, and if there isn't any \"--\", then we check that _all_ \npaths listed are valid, not just the first one.\n\nThe new argument parsing automatically also gives us \"--default\" and \n\"--not\" handling as in git-rev-parse.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n\nThe path checking just makes sense. \n\nThis also makes git-rev-list handle \"--all\" and \"--not\" correctly (before, \nit wouldn't handle \"--not\"), and teaches it to handle \"--default\". I \ndidn't do \"--since\" and \"--before\", but I will eventually. The final end \nresult is that we won't need git-rev-parse for most things.\n\nBut basically there should be no code changes, and this is just a mid-way \npoint where a _partial_ set of routines from \"git-rev-list\" has been moved \ninto a library files - revision.c. The half-way point has some ugly \ninterfaces, but I don't want to do it all in one go.\n\nThe _plan_ is to:\n\n - move the actual history traversal into revision.c too\n\n - leave all the git-rev-list -specific stuff (the \"--bisect\" logic, \n   the print-out logic etc) in rev-list.c\n\n - make it trivial to make a small C version of \"git diff\" that just uses \n   the same \"setup_revisions()\" interface and then looks at \n   \"revs->commits\" to see what revisions were passed in (the library \n   interface is already at the point where that should work)\n\n - when the actual history _traversal_ is moved into \"revision.c\" too, it \n   should then be possible to make an equally small \"git log\" and friends \n   (whatchanged etc) into C using the revision.c code.\n\nComments? I think this is safe to apply, because I've done a diff of the \nold non-split rev-list.c against both the new rev-list.c and revision.c, \nand all the changes _look_ like just moving things around and taking the \nnew \"struct rev_info\" into account.\n\nIt also passes all the tests, and in general seems straightforward enough. \nHOEVER, I'd still like to point out that I could have screwed something \nup, and this is just about the most core program in all of git, so it \nwould make a lot of sense if more people double-checked my \"trivial\" \nsplit-up.\n\n\t\tLinus\n\n\ndiff --git a/Makefile b/Makefile\nindex 6c59cee..3575489 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -192,7 +192,7 @@ LIB_FILE=libgit.a\n LIB_H = \\\n \tblob.h cache.h commit.h count-delta.h csum-file.h delta.h \\\n \tdiff.h epoch.h object.h pack.h pkt-line.h quote.h refs.h \\\n-\trun-command.h strbuf.h tag.h tree.h git-compat-util.h\n+\trun-command.h strbuf.h tag.h tree.h git-compat-util.h revision.h\n \n DIFF_OBJS = \\\n \tdiff.o diffcore-break.o diffcore-order.o diffcore-pathspec.o \\\n@@ -205,7 +205,7 @@ LIB_OBJS = \\\n \tquote.o read-cache.o refs.o run-command.o \\\n \tserver-info.o setup.o sha1_file.o sha1_name.o strbuf.o \\\n \ttag.o tree.o usage.o config.o environment.o ctype.o copy.o \\\n-\tfetch-clone.o \\\n+\tfetch-clone.o revision.o \\\n \t$(DIFF_OBJS)\n \n LIBS = $(LIB_FILE)\ndiff --git a/epoch.c b/epoch.c\nindex 3a76748..0f37492 100644\n--- a/epoch.c\n+++ b/epoch.c\n@@ -15,6 +15,7 @@\n \n #include \"cache.h\"\n #include \"commit.h\"\n+#include \"revision.h\"\n #include \"epoch.h\"\n \n struct fraction {\ndiff --git a/epoch.h b/epoch.h\nindex 7493d5a..3756009 100644\n--- a/epoch.h\n+++ b/epoch.h\n@@ -11,7 +11,6 @@ typedef int (*emitter_func) (struct comm\n int sort_list_in_merge_order(struct commit_list *list, emitter_func emitter);\n \n /* Low bits are used by rev-list */\n-#define UNINTERESTING   (1u<<10)\n #define BOUNDARY        (1u<<11)\n #define VISITED         (1u<<12)\n #define DISCONTINUITY   (1u<<13)\ndiff --git a/rev-list.c b/rev-list.c\nindex 67d2a48..d1c52a6 100644\n--- a/rev-list.c\n+++ b/rev-list.c\n@@ -6,9 +6,10 @@\n #include \"blob.h\"\n #include \"epoch.h\"\n #include \"diff.h\"\n+#include \"revision.h\"\n+\n+/* bits #0 and #1 in revision.h */\n \n-#define SEEN\t\t(1u << 0)\n-#define INTERESTING\t(1u << 1)\n #define COUNTED\t\t(1u << 2)\n #define SHOWN\t\t(1u << 3)\n #define TREECHANGE\t(1u << 4)\n@@ -38,60 +39,20 @@ static const char rev_list_usage[] =\n \"    --bisect\"\n ;\n \n-static int dense = 1;\n+struct rev_info revs;\n+\n static int unpacked = 0;\n static int bisect_list = 0;\n-static int tag_objects = 0;\n-static int tree_objects = 0;\n-static int blob_objects = 0;\n-static int edge_hint = 0;\n static int verbose_header = 0;\n static int abbrev = DEFAULT_ABBREV;\n static int show_parents = 0;\n static int hdr_termination = 0;\n static const char *commit_prefix = \"\";\n-static unsigned long max_age = -1;\n-static unsigned long min_age = -1;\n-static int max_count = -1;\n static enum cmit_fmt commit_format = CMIT_FMT_RAW;\n static int merge_order = 0;\n static int show_breaks = 0;\n static int stop_traversal = 0;\n-static int topo_order = 0;\n-static int lifo = 1;\n static int no_merges = 0;\n-static const char **paths = NULL;\n-static int remove_empty_trees = 0;\n-\n-struct name_path {\n-\tstruct name_path *up;\n-\tint elem_len;\n-\tconst char *elem;\n-};\n-\n-static char *path_name(struct name_path *path, const char *name)\n-{\n-\tstruct name_path *p;\n-\tchar *n, *m;\n-\tint nlen = strlen(name);\n-\tint len = nlen + 1;\n-\n-\tfor (p = path; p; p = p->up) {\n-\t\tif (p->elem_len)\n-\t\t\tlen += p->elem_len + 1;\n-\t}\n-\tn = xmalloc(len);\n-\tm = n + len - (nlen + 1);\n-\tstrcpy(m, name);\n-\tfor (p = path; p; p = p->up) {\n-\t\tif (p->elem_len) {\n-\t\t\tm -= p->elem_len + 1;\n-\t\t\tmemcpy(m, p->elem, p->elem_len);\n-\t\t\tm[p->elem_len] = '/';\n-\t\t}\n-\t}\n-\treturn n;\n-}\n \n static void show_commit(struct commit *commit)\n {\n@@ -168,15 +129,15 @@ static int filter_commit(struct commit *\n \t\treturn STOP;\n \tif (commit->object.flags & (UNINTERESTING|SHOWN))\n \t\treturn CONTINUE;\n-\tif (min_age != -1 && (commit->date > min_age))\n+\tif (revs.min_age != -1 && (commit->date > revs.min_age))\n \t\treturn CONTINUE;\n-\tif (max_age != -1 && (commit->date < max_age)) {\n+\tif (revs.max_age != -1 && (commit->date < revs.max_age)) {\n \t\tstop_traversal=1;\n \t\treturn CONTINUE;\n \t}\n \tif (no_merges && (commit->parents && commit->parents->next))\n \t\treturn CONTINUE;\n-\tif (paths && dense) {\n+\tif (revs.paths && revs.dense) {\n \t\tif (!(commit->object.flags & TREECHANGE))\n \t\t\treturn CONTINUE;\n \t\trewrite_parents(commit);\n@@ -196,7 +157,7 @@ static int process_commit(struct commit \n \t\treturn CONTINUE;\n \t}\n \n-\tif (max_count != -1 && !max_count--)\n+\tif (revs.max_count != -1 && !revs.max_count--)\n \t\treturn STOP;\n \n \tshow_commit(commit);\n@@ -204,19 +165,6 @@ static int process_commit(struct commit \n \treturn CONTINUE;\n }\n \n-static struct object_list **add_object(struct object *obj,\n-\t\t\t\t       struct object_list **p,\n-\t\t\t\t       struct name_path *path,\n-\t\t\t\t       const char *name)\n-{\n-\tstruct object_list *entry = xmalloc(sizeof(*entry));\n-\tentry->item = obj;\n-\tentry->next = *p;\n-\tentry->name = path_name(path, name);\n-\t*p = entry;\n-\treturn &entry->next;\n-}\n-\n static struct object_list **process_blob(struct blob *blob,\n \t\t\t\t\t struct object_list **p,\n \t\t\t\t\t struct name_path *path,\n@@ -224,7 +172,7 @@ static struct object_list **process_blob\n {\n \tstruct object *obj = &blob->object;\n \n-\tif (!blob_objects)\n+\tif (!revs.blob_objects)\n \t\treturn p;\n \tif (obj->flags & (UNINTERESTING | SEEN))\n \t\treturn p;\n@@ -241,7 +189,7 @@ static struct object_list **process_tree\n \tstruct tree_entry_list *entry;\n \tstruct name_path me;\n \n-\tif (!tree_objects)\n+\tif (!revs.tree_objects)\n \t\treturn p;\n \tif (obj->flags & (UNINTERESTING | SEEN))\n \t\treturn p;\n@@ -314,75 +262,6 @@ static void show_commit_list(struct comm\n \t}\n }\n \n-static void mark_blob_uninteresting(struct blob *blob)\n-{\n-\tif (!blob_objects)\n-\t\treturn;\n-\tif (blob->object.flags & UNINTERESTING)\n-\t\treturn;\n-\tblob->object.flags |= UNINTERESTING;\n-}\n-\n-static void mark_tree_uninteresting(struct tree *tree)\n-{\n-\tstruct object *obj = &tree->object;\n-\tstruct tree_entry_list *entry;\n-\n-\tif (!tree_objects)\n-\t\treturn;\n-\tif (obj->flags & UNINTERESTING)\n-\t\treturn;\n-\tobj->flags |= UNINTERESTING;\n-\tif (!has_sha1_file(obj->sha1))\n-\t\treturn;\n-\tif (parse_tree(tree) < 0)\n-\t\tdie(\"bad tree %s\", sha1_to_hex(obj->sha1));\n-\tentry = tree->entries;\n-\ttree->entries = NULL;\n-\twhile (entry) {\n-\t\tstruct tree_entry_list *next = entry->next;\n-\t\tif (entry->directory)\n-\t\t\tmark_tree_uninteresting(entry->item.tree);\n-\t\telse\n-\t\t\tmark_blob_uninteresting(entry->item.blob);\n-\t\tfree(entry);\n-\t\tentry = next;\n-\t}\n-}\n-\n-static void mark_parents_uninteresting(struct commit *commit)\n-{\n-\tstruct commit_list *parents = commit->parents;\n-\n-\twhile (parents) {\n-\t\tstruct commit *commit = parents->item;\n-\t\tcommit->object.flags |= UNINTERESTING;\n-\n-\t\t/*\n-\t\t * Normally we haven't parsed the parent\n-\t\t * yet, so we won't have a parent of a parent\n-\t\t * here. However, it may turn out that we've\n-\t\t * reached this commit some other way (where it\n-\t\t * wasn't uninteresting), in which case we need\n-\t\t * to mark its parents recursively too..\n-\t\t */\n-\t\tif (commit->parents)\n-\t\t\tmark_parents_uninteresting(commit);\n-\n-\t\t/*\n-\t\t * A missing commit is ok iff its parent is marked \n-\t\t * uninteresting.\n-\t\t *\n-\t\t * We just mark such a thing parsed, so that when\n-\t\t * it is popped next time around, we won't be trying\n-\t\t * to parse it and get an error.\n-\t\t */\n-\t\tif (!has_sha1_file(commit->object.sha1))\n-\t\t\tcommit->object.parsed = 1;\n-\t\tparents = parents->next;\n-\t}\n-}\n-\n static int everybody_uninteresting(struct commit_list *orig)\n {\n \tstruct commit_list *list = orig;\n@@ -413,7 +292,7 @@ static int count_distance(struct commit_\n \n \t\tif (commit->object.flags & (UNINTERESTING | COUNTED))\n \t\t\tbreak;\n-\t\tif (!paths || (commit->object.flags & TREECHANGE))\n+\t\tif (!revs.paths || (commit->object.flags & TREECHANGE))\n \t\t\tnr++;\n \t\tcommit->object.flags |= COUNTED;\n \t\tp = commit->parents;\n@@ -447,7 +326,7 @@ static struct commit_list *find_bisectio\n \tnr = 0;\n \tp = list;\n \twhile (p) {\n-\t\tif (!paths || (p->item->object.flags & TREECHANGE))\n+\t\tif (!revs.paths || (p->item->object.flags & TREECHANGE))\n \t\t\tnr++;\n \t\tp = p->next;\n \t}\n@@ -457,7 +336,7 @@ static struct commit_list *find_bisectio\n \tfor (p = list; p; p = p->next) {\n \t\tint distance;\n \n-\t\tif (paths && !(p->item->object.flags & TREECHANGE))\n+\t\tif (revs.paths && !(p->item->object.flags & TREECHANGE))\n \t\t\tcontinue;\n \n \t\tdistance = count_distance(p);\n@@ -483,7 +362,7 @@ static void mark_edge_parents_uninterest\n \t\tif (!(parent->object.flags & UNINTERESTING))\n \t\t\tcontinue;\n \t\tmark_tree_uninteresting(parent->tree);\n-\t\tif (edge_hint && !(parent->object.flags & SHOWN)) {\n+\t\tif (revs.edge_hint && !(parent->object.flags & SHOWN)) {\n \t\t\tparent->object.flags |= SHOWN;\n \t\t\tprintf(\"-%s\\n\", sha1_to_hex(parent->object.sha1));\n \t\t}\n@@ -613,7 +492,7 @@ static void try_to_simplify_commit(struc\n \t\t\treturn;\n \n \t\tcase TREE_NEW:\n-\t\t\tif (remove_empty_trees && same_tree_as_empty(p->tree)) {\n+\t\t\tif (revs.remove_empty_trees && same_tree_as_empty(p->tree)) {\n \t\t\t\t*pp = parent->next;\n \t\t\t\tcontinue;\n \t\t\t}\n@@ -664,7 +543,7 @@ static void add_parents_to_list(struct c\n \t * simplify the commit history and find the parent\n \t * that has no differences in the path set if one exists.\n \t */\n-\tif (paths)\n+\tif (revs.paths)\n \t\ttry_to_simplify_commit(commit);\n \n \tparent = commit->parents;\n@@ -693,7 +572,7 @@ static struct commit_list *limit_list(st\n \t\tlist = list->next;\n \t\tfree(entry);\n \n-\t\tif (max_age != -1 && (commit->date < max_age))\n+\t\tif (revs.max_age != -1 && (commit->date < revs.max_age))\n \t\t\tobj->flags |= UNINTERESTING;\n \t\tif (unpacked && has_sha1_pack(obj->sha1))\n \t\t\tobj->flags |= UNINTERESTING;\n@@ -704,155 +583,40 @@ static struct commit_list *limit_list(st\n \t\t\t\tbreak;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (min_age != -1 && (commit->date > min_age))\n+\t\tif (revs.min_age != -1 && (commit->date > revs.min_age))\n \t\t\tcontinue;\n \t\tp = &commit_list_insert(commit, p)->next;\n \t}\n-\tif (tree_objects)\n+\tif (revs.tree_objects)\n \t\tmark_edges_uninteresting(newlist);\n \tif (bisect_list)\n \t\tnewlist = find_bisection(newlist);\n \treturn newlist;\n }\n \n-static void add_pending_object(struct object *obj, const char *name)\n-{\n-\tadd_object(obj, &pending_objects, NULL, name);\n-}\n-\n-static struct commit *get_commit_reference(const char *name, const unsigned char *sha1, unsigned int flags)\n-{\n-\tstruct object *object;\n-\n-\tobject = parse_object(sha1);\n-\tif (!object)\n-\t\tdie(\"bad object %s\", name);\n-\n-\t/*\n-\t * Tag object? Look what it points to..\n-\t */\n-\twhile (object->type == tag_type) {\n-\t\tstruct tag *tag = (struct tag *) object;\n-\t\tobject->flags |= flags;\n-\t\tif (tag_objects && !(object->flags & UNINTERESTING))\n-\t\t\tadd_pending_object(object, tag->tag);\n-\t\tobject = parse_object(tag->tagged->sha1);\n-\t\tif (!object)\n-\t\t\tdie(\"bad object %s\", sha1_to_hex(tag->tagged->sha1));\n-\t}\n-\n-\t/*\n-\t * Commit object? Just return it, we'll do all the complex\n-\t * reachability crud.\n-\t */\n-\tif (object->type == commit_type) {\n-\t\tstruct commit *commit = (struct commit *)object;\n-\t\tobject->flags |= flags;\n-\t\tif (parse_commit(commit) < 0)\n-\t\t\tdie(\"unable to parse commit %s\", name);\n-\t\tif (flags & UNINTERESTING)\n-\t\t\tmark_parents_uninteresting(commit);\n-\t\treturn commit;\n-\t}\n-\n-\t/*\n-\t * Tree object? Either mark it uniniteresting, or add it\n-\t * to the list of objects to look at later..\n-\t */\n-\tif (object->type == tree_type) {\n-\t\tstruct tree *tree = (struct tree *)object;\n-\t\tif (!tree_objects)\n-\t\t\treturn NULL;\n-\t\tif (flags & UNINTERESTING) {\n-\t\t\tmark_tree_uninteresting(tree);\n-\t\t\treturn NULL;\n-\t\t}\n-\t\tadd_pending_object(object, \"\");\n-\t\treturn NULL;\n-\t}\n-\n-\t/*\n-\t * Blob object? You know the drill by now..\n-\t */\n-\tif (object->type == blob_type) {\n-\t\tstruct blob *blob = (struct blob *)object;\n-\t\tif (!blob_objects)\n-\t\t\treturn NULL;\n-\t\tif (flags & UNINTERESTING) {\n-\t\t\tmark_blob_uninteresting(blob);\n-\t\t\treturn NULL;\n-\t\t}\n-\t\tadd_pending_object(object, \"\");\n-\t\treturn NULL;\n-\t}\n-\tdie(\"%s is unknown object\", name);\n-}\n-\n-static void handle_one_commit(struct commit *com, struct commit_list **lst)\n-{\n-\tif (!com || com->object.flags & SEEN)\n-\t\treturn;\n-\tcom->object.flags |= SEEN;\n-\tcommit_list_insert(com, lst);\n-}\n-\n-/* for_each_ref() callback does not allow user data -- Yuck. */\n-static struct commit_list **global_lst;\n-\n-static int include_one_commit(const char *path, const unsigned char *sha1)\n-{\n-\tstruct commit *com = get_commit_reference(path, sha1, 0);\n-\thandle_one_commit(com, global_lst);\n-\treturn 0;\n-}\n-\n-static void handle_all(struct commit_list **lst)\n-{\n-\tglobal_lst = lst;\n-\tfor_each_ref(include_one_commit);\n-\tglobal_lst = NULL;\n-}\n-\n int main(int argc, const char **argv)\n {\n-\tconst char *prefix = setup_git_directory();\n-\tstruct commit_list *list = NULL;\n+\tstruct commit_list *list;\n \tint i, limited = 0;\n \n+\targc = setup_revisions(argc, argv, &revs);\n+\n \tfor (i = 1 ; i < argc; i++) {\n-\t\tint flags;\n \t\tconst char *arg = argv[i];\n-\t\tchar *dotdot;\n-\t\tstruct commit *commit;\n-\t\tunsigned char sha1[20];\n \n \t\t/* accept -<digit>, like traditilnal \"head\" */\n \t\tif ((*arg == '-') && isdigit(arg[1])) {\n-\t\t\tmax_count = atoi(arg + 1);\n+\t\t\trevs.max_count = atoi(arg + 1);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(arg, \"-n\")) {\n \t\t\tif (++i >= argc)\n \t\t\t\tdie(\"-n requires an argument\");\n-\t\t\tmax_count = atoi(argv[i]);\n+\t\t\trevs.max_count = atoi(argv[i]);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strncmp(arg,\"-n\",2)) {\n-\t\t\tmax_count = atoi(arg + 2);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strncmp(arg, \"--max-count=\", 12)) {\n-\t\t\tmax_count = atoi(arg + 12);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strncmp(arg, \"--max-age=\", 10)) {\n-\t\t\tmax_age = atoi(arg + 10);\n-\t\t\tlimited = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strncmp(arg, \"--min-age=\", 10)) {\n-\t\t\tmin_age = atoi(arg + 10);\n-\t\t\tlimited = 1;\n+\t\t\trevs.max_count = atoi(arg + 2);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!strcmp(arg, \"--header\")) {\n@@ -893,23 +657,6 @@ int main(int argc, const char **argv)\n \t\t\tbisect_list = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (!strcmp(arg, \"--all\")) {\n-\t\t\thandle_all(&list);\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--objects\")) {\n-\t\t\ttag_objects = 1;\n-\t\t\ttree_objects = 1;\n-\t\t\tblob_objects = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--objects-edge\")) {\n-\t\t\ttag_objects = 1;\n-\t\t\ttree_objects = 1;\n-\t\t\tblob_objects = 1;\n-\t\t\tedge_hint = 1;\n-\t\t\tcontinue;\n-\t\t}\n \t\tif (!strcmp(arg, \"--unpacked\")) {\n \t\t\tunpacked = 1;\n \t\t\tlimited = 1;\n@@ -923,100 +670,42 @@ int main(int argc, const char **argv)\n \t\t\tshow_breaks = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (!strcmp(arg, \"--topo-order\")) {\n-\t\t        topo_order = 1;\n-\t\t\tlifo = 1;\n-\t\t        limited = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--date-order\")) {\n-\t\t        topo_order = 1;\n-\t\t\tlifo = 0;\n-\t\t        limited = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--dense\")) {\n-\t\t\tdense = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--sparse\")) {\n-\t\t\tdense = 0;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--remove-empty\")) {\n-\t\t\tremove_empty_trees = 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t\tif (!strcmp(arg, \"--\")) {\n-\t\t\ti++;\n-\t\t\tbreak;\n-\t\t}\n-\n-\t\tif (show_breaks && !merge_order)\n-\t\t\tusage(rev_list_usage);\n+\t\tusage(rev_list_usage);\n \n-\t\tflags = 0;\n-\t\tdotdot = strstr(arg, \"..\");\n-\t\tif (dotdot) {\n-\t\t\tunsigned char from_sha1[20];\n-\t\t\tchar *next = dotdot + 2;\n-\t\t\t*dotdot = 0;\n-\t\t\tif (!*next)\n-\t\t\t\tnext = \"HEAD\";\n-\t\t\tif (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) {\n-\t\t\t\tstruct commit *exclude;\n-\t\t\t\tstruct commit *include;\n-\t\t\t\t\n-\t\t\t\texclude = get_commit_reference(arg, from_sha1, UNINTERESTING);\n-\t\t\t\tinclude = get_commit_reference(next, sha1, 0);\n-\t\t\t\tif (!exclude || !include)\n-\t\t\t\t\tdie(\"Invalid revision range %s..%s\", arg, next);\n-\t\t\t\tlimited = 1;\n-\t\t\t\thandle_one_commit(exclude, &list);\n-\t\t\t\thandle_one_commit(include, &list);\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\t*dotdot = '.';\n-\t\t}\n-\t\tif (*arg == '^') {\n-\t\t\tflags = UNINTERESTING;\n-\t\t\targ++;\n-\t\t\tlimited = 1;\n-\t\t}\n-\t\tif (get_sha1(arg, sha1) < 0) {\n-\t\t\tstruct stat st;\n-\t\t\tif (lstat(arg, &st) < 0)\n-\t\t\t\tdie(\"'%s': %s\", arg, strerror(errno));\n-\t\t\tbreak;\n-\t\t}\n-\t\tcommit = get_commit_reference(arg, sha1, flags);\n-\t\thandle_one_commit(commit, &list);\n \t}\n \n+\tlist = revs.commits;\n+\tif (list && list->next)\n+\t\tlimited = 1;\n+\n+\tif (revs.topo_order)\n+\t\tlimited = 1;\n+\n \tif (!list &&\n-\t    (!(tag_objects||tree_objects||blob_objects) && !pending_objects))\n+\t    (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects))\n \t\tusage(rev_list_usage);\n \n-\tpaths = get_pathspec(prefix, argv + i);\n-\tif (paths) {\n+\tif (revs.paths) {\n \t\tlimited = 1;\n-\t\tdiff_tree_setup_paths(paths);\n+\t\tdiff_tree_setup_paths(revs.paths);\n \t}\n+\tif (revs.max_age || revs.min_age)\n+\t\tlimited = 1;\n \n \tsave_commit_buffer = verbose_header;\n \ttrack_object_refs = 0;\n \n \tif (!merge_order) {\t\t\n \t\tsort_by_date(&list);\n-\t\tif (list && !limited && max_count == 1 &&\n-\t\t    !tag_objects && !tree_objects && !blob_objects) {\n+\t\tif (list && !limited && revs.max_count == 1 &&\n+\t\t    !revs.tag_objects && !revs.tree_objects && !revs.blob_objects) {\n \t\t\tshow_commit(list->item);\n \t\t\treturn 0;\n \t\t}\n \t        if (limited)\n \t\t\tlist = limit_list(list);\n-\t\tif (topo_order)\n-\t\t\tsort_in_topological_order(&list, lifo);\n+\t\tif (revs.topo_order)\n+\t\t\tsort_in_topological_order(&list, revs.lifo);\n \t\tshow_commit_list(list);\n \t} else {\n #ifndef NO_OPENSSL\ndiff --git a/revision.c b/revision.c\nnew file mode 100644\nindex 0000000..17dbf9a\n--- /dev/null\n+++ b/revision.c\n@@ -0,0 +1,370 @@\n+#include \"cache.h\"\n+#include \"tag.h\"\n+#include \"blob.h\"\n+#include \"tree.h\"\n+#include \"commit.h\"\n+#include \"refs.h\"\n+#include \"revision.h\"\n+\n+static char *path_name(struct name_path *path, const char *name)\n+{\n+\tstruct name_path *p;\n+\tchar *n, *m;\n+\tint nlen = strlen(name);\n+\tint len = nlen + 1;\n+\n+\tfor (p = path; p; p = p->up) {\n+\t\tif (p->elem_len)\n+\t\t\tlen += p->elem_len + 1;\n+\t}\n+\tn = xmalloc(len);\n+\tm = n + len - (nlen + 1);\n+\tstrcpy(m, name);\n+\tfor (p = path; p; p = p->up) {\n+\t\tif (p->elem_len) {\n+\t\t\tm -= p->elem_len + 1;\n+\t\t\tmemcpy(m, p->elem, p->elem_len);\n+\t\t\tm[p->elem_len] = '/';\n+\t\t}\n+\t}\n+\treturn n;\n+}\n+\n+struct object_list **add_object(struct object *obj,\n+\t\t\t\t       struct object_list **p,\n+\t\t\t\t       struct name_path *path,\n+\t\t\t\t       const char *name)\n+{\n+\tstruct object_list *entry = xmalloc(sizeof(*entry));\n+\tentry->item = obj;\n+\tentry->next = *p;\n+\tentry->name = path_name(path, name);\n+\t*p = entry;\n+\treturn &entry->next;\n+}\n+\n+static void mark_blob_uninteresting(struct blob *blob)\n+{\n+\tif (blob->object.flags & UNINTERESTING)\n+\t\treturn;\n+\tblob->object.flags |= UNINTERESTING;\n+}\n+\n+void mark_tree_uninteresting(struct tree *tree)\n+{\n+\tstruct object *obj = &tree->object;\n+\tstruct tree_entry_list *entry;\n+\n+\tif (obj->flags & UNINTERESTING)\n+\t\treturn;\n+\tobj->flags |= UNINTERESTING;\n+\tif (!has_sha1_file(obj->sha1))\n+\t\treturn;\n+\tif (parse_tree(tree) < 0)\n+\t\tdie(\"bad tree %s\", sha1_to_hex(obj->sha1));\n+\tentry = tree->entries;\n+\ttree->entries = NULL;\n+\twhile (entry) {\n+\t\tstruct tree_entry_list *next = entry->next;\n+\t\tif (entry->directory)\n+\t\t\tmark_tree_uninteresting(entry->item.tree);\n+\t\telse\n+\t\t\tmark_blob_uninteresting(entry->item.blob);\n+\t\tfree(entry);\n+\t\tentry = next;\n+\t}\n+}\n+\n+void mark_parents_uninteresting(struct commit *commit)\n+{\n+\tstruct commit_list *parents = commit->parents;\n+\n+\twhile (parents) {\n+\t\tstruct commit *commit = parents->item;\n+\t\tcommit->object.flags |= UNINTERESTING;\n+\n+\t\t/*\n+\t\t * Normally we haven't parsed the parent\n+\t\t * yet, so we won't have a parent of a parent\n+\t\t * here. However, it may turn out that we've\n+\t\t * reached this commit some other way (where it\n+\t\t * wasn't uninteresting), in which case we need\n+\t\t * to mark its parents recursively too..\n+\t\t */\n+\t\tif (commit->parents)\n+\t\t\tmark_parents_uninteresting(commit);\n+\n+\t\t/*\n+\t\t * A missing commit is ok iff its parent is marked \n+\t\t * uninteresting.\n+\t\t *\n+\t\t * We just mark such a thing parsed, so that when\n+\t\t * it is popped next time around, we won't be trying\n+\t\t * to parse it and get an error.\n+\t\t */\n+\t\tif (!has_sha1_file(commit->object.sha1))\n+\t\t\tcommit->object.parsed = 1;\n+\t\tparents = parents->next;\n+\t}\n+}\n+\n+static void add_pending_object(struct rev_info *revs, struct object *obj, const char *name)\n+{\n+\tadd_object(obj, &revs->pending_objects, NULL, name);\n+}\n+\n+static struct commit *get_commit_reference(struct rev_info *revs, const char *name, const unsigned char *sha1, unsigned int flags)\n+{\n+\tstruct object *object;\n+\n+\tobject = parse_object(sha1);\n+\tif (!object)\n+\t\tdie(\"bad object %s\", name);\n+\n+\t/*\n+\t * Tag object? Look what it points to..\n+\t */\n+\twhile (object->type == tag_type) {\n+\t\tstruct tag *tag = (struct tag *) object;\n+\t\tobject->flags |= flags;\n+\t\tif (revs->tag_objects && !(object->flags & UNINTERESTING))\n+\t\t\tadd_pending_object(revs, object, tag->tag);\n+\t\tobject = parse_object(tag->tagged->sha1);\n+\t\tif (!object)\n+\t\t\tdie(\"bad object %s\", sha1_to_hex(tag->tagged->sha1));\n+\t}\n+\n+\t/*\n+\t * Commit object? Just return it, we'll do all the complex\n+\t * reachability crud.\n+\t */\n+\tif (object->type == commit_type) {\n+\t\tstruct commit *commit = (struct commit *)object;\n+\t\tobject->flags |= flags;\n+\t\tif (parse_commit(commit) < 0)\n+\t\t\tdie(\"unable to parse commit %s\", name);\n+\t\tif (flags & UNINTERESTING)\n+\t\t\tmark_parents_uninteresting(commit);\n+\t\treturn commit;\n+\t}\n+\n+\t/*\n+\t * Tree object? Either mark it uniniteresting, or add it\n+\t * to the list of objects to look at later..\n+\t */\n+\tif (object->type == tree_type) {\n+\t\tstruct tree *tree = (struct tree *)object;\n+\t\tif (!revs->tree_objects)\n+\t\t\treturn NULL;\n+\t\tif (flags & UNINTERESTING) {\n+\t\t\tmark_tree_uninteresting(tree);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tadd_pending_object(revs, object, \"\");\n+\t\treturn NULL;\n+\t}\n+\n+\t/*\n+\t * Blob object? You know the drill by now..\n+\t */\n+\tif (object->type == blob_type) {\n+\t\tstruct blob *blob = (struct blob *)object;\n+\t\tif (!revs->blob_objects)\n+\t\t\treturn NULL;\n+\t\tif (flags & UNINTERESTING) {\n+\t\t\tmark_blob_uninteresting(blob);\n+\t\t\treturn NULL;\n+\t\t}\n+\t\tadd_pending_object(revs, object, \"\");\n+\t\treturn NULL;\n+\t}\n+\tdie(\"%s is unknown object\", name);\n+}\n+\n+static void add_one_commit(struct commit *commit, struct rev_info *revs)\n+{\n+\tif (!commit || (commit->object.flags & SEEN))\n+\t\treturn;\n+\tcommit->object.flags |= SEEN;\n+\tcommit_list_insert(commit, &revs->commits);\n+}\n+\n+static int all_flags;\n+static struct rev_info *all_revs;\n+\n+static int handle_one_ref(const char *path, const unsigned char *sha1)\n+{\n+\tstruct commit *commit = get_commit_reference(all_revs, path, sha1, all_flags);\n+\tadd_one_commit(commit, all_revs);\n+\treturn 0;\n+}\n+\n+static void handle_all(struct rev_info *revs, unsigned flags)\n+{\n+\tall_revs = revs;\n+\tall_flags = flags;\n+\tfor_each_ref(handle_one_ref);\n+}\n+\n+/*\n+ * Parse revision information, filling in the \"rev_info\" structure,\n+ * and removing the used arguments from the argument list.\n+ *\n+ * Returns the number of arguments left (\"new argc\").\n+ */\n+int setup_revisions(int argc, const char **argv, struct rev_info *revs)\n+{\n+\tint i, flags, seen_dashdash;\n+\tconst char *def = NULL;\n+\tconst char **unrecognized = argv+1;\n+\tint left = 1;\n+\n+\tmemset(revs, 0, sizeof(*revs));\n+\trevs->lifo = 1;\n+\trevs->dense = 1;\n+\trevs->prefix = setup_git_directory();\n+\trevs->max_age = -1;\n+\trevs->min_age = -1;\n+\trevs->max_count = -1;\n+\n+\t/* First, search for \"--\" */\n+\tseen_dashdash = 0;\n+\tfor (i = 1; i < argc; i++) {\n+\t\tconst char *arg = argv[i];\n+\t\tif (strcmp(arg, \"--\"))\n+\t\t\tcontinue;\n+\t\targv[i] = NULL;\n+\t\targc = i;\n+\t\trevs->paths = get_pathspec(revs->prefix, argv + i + 1);\n+\t\tseen_dashdash = 1;\n+\t\tbreak;\n+\t}\n+\n+\tflags = 0;\n+\tfor (i = 1; i < argc; i++) {\n+\t\tstruct commit *commit;\n+\t\tconst char *arg = argv[i];\n+\t\tunsigned char sha1[20];\n+\t\tchar *dotdot;\n+\t\tint local_flags;\n+\n+\t\tif (*arg == '-') {\n+\t\t\tif (!strncmp(arg, \"--max-count=\", 12)) {\n+\t\t\t\trevs->max_count = atoi(arg + 12);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strncmp(arg, \"--max-age=\", 10)) {\n+\t\t\t\trevs->max_age = atoi(arg + 10);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strncmp(arg, \"--min-age=\", 10)) {\n+\t\t\t\trevs->min_age = atoi(arg + 10);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--all\")) {\n+\t\t\t\thandle_all(revs, flags);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--not\")) {\n+\t\t\t\tflags ^= UNINTERESTING;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--default\")) {\n+\t\t\t\tif (++i >= argc)\n+\t\t\t\t\tdie(\"bad --default argument\");\n+\t\t\t\tdef = argv[i];\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--topo-order\")) {\n+\t\t\t\trevs->topo_order = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--date-order\")) {\n+\t\t\t\trevs->lifo = 0;\n+\t\t\t\trevs->topo_order = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--dense\")) {\n+\t\t\t\trevs->dense = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--sparse\")) {\n+\t\t\t\trevs->dense = 0;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--remove-empty\")) {\n+\t\t\t\trevs->remove_empty_trees = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--objects\")) {\n+\t\t\t\trevs->tag_objects = 1;\n+\t\t\t\trevs->tree_objects = 1;\n+\t\t\t\trevs->blob_objects = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\tif (!strcmp(arg, \"--objects-edge\")) {\n+\t\t\t\trevs->tag_objects = 1;\n+\t\t\t\trevs->tree_objects = 1;\n+\t\t\t\trevs->blob_objects = 1;\n+\t\t\t\trevs->edge_hint = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t*unrecognized++ = arg;\n+\t\t\tleft++;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tdotdot = strstr(arg, \"..\");\n+\t\tif (dotdot) {\n+\t\t\tunsigned char from_sha1[20];\n+\t\t\tchar *next = dotdot + 2;\n+\t\t\t*dotdot = 0;\n+\t\t\tif (!*next)\n+\t\t\t\tnext = \"HEAD\";\n+\t\t\tif (!get_sha1(arg, from_sha1) && !get_sha1(next, sha1)) {\n+\t\t\t\tstruct commit *exclude;\n+\t\t\t\tstruct commit *include;\n+\n+\t\t\t\texclude = get_commit_reference(revs, arg, from_sha1, flags ^ UNINTERESTING);\n+\t\t\t\tinclude = get_commit_reference(revs, next, sha1, flags);\n+\t\t\t\tif (!exclude || !include)\n+\t\t\t\t\tdie(\"Invalid revision range %s..%s\", arg, next);\n+\t\t\t\tadd_one_commit(exclude, revs);\n+\t\t\t\tadd_one_commit(include, revs);\n+\t\t\t\tcontinue;\n+\t\t\t}\n+\t\t\t*dotdot = '.';\n+\t\t}\n+\t\tlocal_flags = 0;\n+\t\tif (*arg == '^') {\n+\t\t\tlocal_flags = UNINTERESTING;\n+\t\t\targ++;\n+\t\t}\n+\t\tif (get_sha1(arg, sha1) < 0) {\n+\t\t\tstruct stat st;\n+\t\t\tint j;\n+\n+\t\t\tif (seen_dashdash || local_flags)\n+\t\t\t\tdie(\"bad revision '%s'\", arg);\n+\n+\t\t\t/* If we didn't have a \"--\", all filenames must exist */\n+\t\t\tfor (j = i; j < argc; j++) {\n+\t\t\t\tif (lstat(argv[j], &st) < 0)\n+\t\t\t\t\tdie(\"'%s': %s\", arg, strerror(errno));\n+\t\t\t}\n+\t\t\trevs->paths = get_pathspec(revs->prefix, argv + i);\n+\t\t\tbreak;\n+\t\t}\n+\t\tcommit = get_commit_reference(revs, arg, sha1, flags ^ local_flags);\n+\t\tadd_one_commit(commit, revs);\n+\t}\n+\tif (def && !revs->commits) {\n+\t\tunsigned char sha1[20];\n+\t\tstruct commit *commit;\n+\t\tif (get_sha1(def, sha1) < 0)\n+\t\t\tdie(\"bad default revision '%s'\", def);\n+\t\tcommit = get_commit_reference(revs, def, sha1, 0);\n+\t\tadd_one_commit(commit, revs);\n+\t}\n+\t*unrecognized = NULL;\n+\treturn left;\n+}\ndiff --git a/revision.h b/revision.h\nnew file mode 100644\nindex 0000000..5170ac4\n--- /dev/null\n+++ b/revision.h\n@@ -0,0 +1,48 @@\n+#ifndef REVISION_H\n+#define REVISION_H\n+\n+#define SEEN\t\t(1u<<0)\n+#define UNINTERESTING   (1u<<1)\n+\n+struct rev_info {\n+\t/* Starting list */\n+\tstruct commit_list *commits;\n+\tstruct object_list *pending_objects;\n+\n+\t/* Basic information */\n+\tconst char *prefix;\n+\tconst char **paths;\n+\n+\t/* Traversal flags */\n+\tunsigned int\tdense:1,\n+\t\t\tremove_empty_trees:1,\n+\t\t\tlifo:1,\n+\t\t\ttopo_order:1,\n+\t\t\ttag_objects:1,\n+\t\t\ttree_objects:1,\n+\t\t\tblob_objects:1,\n+\t\t\tedge_hint:1;\n+\n+\t/* special limits */\n+\tint max_count;\n+\tunsigned long max_age;\n+\tunsigned long min_age;\n+};\n+\n+/* revision.c */\n+extern int setup_revisions(int argc, const char **argv, struct rev_info *revs);\n+extern void mark_parents_uninteresting(struct commit *commit);\n+extern void mark_tree_uninteresting(struct tree *tree);\n+\n+struct name_path {\n+\tstruct name_path *up;\n+\tint elem_len;\n+\tconst char *elem;\n+};\n+\n+extern struct object_list **add_object(struct object *obj,\n+\t\t\t\t       struct object_list **p,\n+\t\t\t\t       struct name_path *path,\n+\t\t\t\t       const char *name);\n+\n+#endif\n"},{"id":"16739","messageId":"7vwtfi6b4h.fsf@assigned-by-dhcp.cox.net","threadId":"3463","inReplyTo":"Pine.LNX.4.64.0602251608160.22647@g5.osdl.org","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-02-26T03:40:30Z","receivedAt":"2006-02-26T03:40:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> This really just splits things up partially, and creates the\n> interface to set things up by parsign the command line.\n\nSorry, I'll keep this but I ended up wasting the whole day\nsetting up a new machine for my wife (a windows box).  The next\ntask would be to install Cygwin so I can have fun with git...\n"},{"id":"16788","messageId":"Pine.LNX.4.63.0602270257110.4147@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"3463","inReplyTo":"Pine.LNX.4.64.0602251608160.22647@g5.osdl.org","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-02-27T01:57:19Z","receivedAt":"2006-02-27T01:57:19Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nbeware of that patch. It breaks at least one thing: cloning a repository \nwith a tag pointing to a tag object (the tag is cloned, but not the tag \nobject).\n\nSorry to not fix it right away, but I am just too tired.\n\nBy way of figuring this out, I just found a (warning: irony) \"cute \nfeature\" of git-bisect. I needed to apply a certain patch to trigger a \ncertain bug. So I always applied that patch after bisect chose the next \nrev, and of course committed it so that bisect could continue.\n\n(In hindsight, I probably should've applied the patch, \ngit-update-index'ed the file, and hoped that the merge mechanism take care \nof it.)\n\nNow, short of finding the correct commit, bisect would loop endlessly, \ngiving me the same rev to test over and over again (saying \"2 revs to go \nafter this\"), because I would label the current rev (which was the applied \npatch, not the bad rev) as bad.\n\nSo, in a very real sense, it might not be such a phantastic idea as was \nsuggested earlier on this list, that you are able to commit on top of a \nbisected rev.\n\nGood night and good luck,\nDscho\n"},{"id":"16791","messageId":"Pine.LNX.4.64.0602261900370.22647@g5.osdl.org","threadId":"3463","inReplyTo":"Pine.LNX.4.63.0602270257110.4147@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-02-27T03:05:07Z","receivedAt":"2006-02-27T03:05:07Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 27 Feb 2006, Johannes Schindelin wrote:\n> \n> beware of that patch. It breaks at least one thing: cloning a repository \n> with a tag pointing to a tag object (the tag is cloned, but not the tag \n> object).\n> \n> Sorry to not fix it right away, but I am just too tired.\n\nAhh. I know what it is.\n\nI'm pretty sure this trivial and stupid patch on top of the patch I sent \nout should fix it.\n\nDuh. I moved \"pending_objects\" into the \"revs\" structure, but didn't \nremove the stale one, along with its use.\n\n\t\tLinus\n\n---\ndiff --git a/rev-list.c b/rev-list.c\nindex d1c52a6..e9e371c 100644\n--- a/rev-list.c\n+++ b/rev-list.c\n@@ -214,8 +214,6 @@ static struct object_list **process_tree\n \treturn p;\n }\n \n-static struct object_list *pending_objects = NULL;\n-\n static void show_commit_list(struct commit_list *list)\n {\n \tstruct object_list *objects = NULL, **p = &objects, *pending;\n@@ -226,7 +224,7 @@ static void show_commit_list(struct comm\n \t\tif (process_commit(commit) == STOP)\n \t\t\tbreak;\n \t}\n-\tfor (pending = pending_objects; pending; pending = pending->next) {\n+\tfor (pending = revs.pending_objects; pending; pending = pending->next) {\n \t\tstruct object *obj = pending->item;\n \t\tconst char *name = pending->name;\n \t\tif (obj->flags & (UNINTERESTING | SEEN))\n"},{"id":"16792","messageId":"7vpsl93395.fsf@assigned-by-dhcp.cox.net","threadId":"3463","inReplyTo":"Pine.LNX.4.64.0602251608160.22647@g5.osdl.org","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-02-27T03:11:02Z","receivedAt":"2006-02-27T03:11:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Comments? I think this is safe to apply, because I've done a diff of the \n> old non-split rev-list.c against both the new rev-list.c and revision.c, \n> and all the changes _look_ like just moving things around and taking the \n> new \"struct rev_info\" into account.\n\nI think you would need something the attached patch, at least.\n\nI have a suspicion that this was your easter egg to see how\ncareful I am reading what I apply -- and I failed.  Johannes\ngets a test-pilot star for this.  This also means we need a bit\nbetter set of tests.\n\nThe diff between old rev-list.c and new split files would not\nhave caught the static variable gotcha.\n\nI am clueless about the \"limited = (list && list->next)\" part,\nbut there is only one commit involved hence the test is false\nwith my testcase \"git-rev-list --objects v1.0.0^0..v1.0.0\"; I\nthink the old code said dotdot is a limited case.\n\n---\ndiff --git a/rev-list.c b/rev-list.c\nindex d1c52a6..630626e 100644\n--- a/rev-list.c\n+++ b/rev-list.c\n@@ -214,8 +214,6 @@ static struct object_list **process_tree\n \treturn p;\n }\n \n-static struct object_list *pending_objects = NULL;\n-\n static void show_commit_list(struct commit_list *list)\n {\n \tstruct object_list *objects = NULL, **p = &objects, *pending;\n@@ -226,7 +224,7 @@ static void show_commit_list(struct comm\n \t\tif (process_commit(commit) == STOP)\n \t\t\tbreak;\n \t}\n-\tfor (pending = pending_objects; pending; pending = pending->next) {\n+\tfor (pending = revs.pending_objects; pending; pending = pending->next) {\n \t\tstruct object *obj = pending->item;\n \t\tconst char *name = pending->name;\n \t\tif (obj->flags & (UNINTERESTING | SEEN))\n@@ -675,7 +673,7 @@ int main(int argc, const char **argv)\n \t}\n \n \tlist = revs.commits;\n-\tif (list && list->next)\n+\tif (list)\n \t\tlimited = 1;\n \n \tif (revs.topo_order)\n@@ -689,7 +687,7 @@ int main(int argc, const char **argv)\n \t\tlimited = 1;\n \t\tdiff_tree_setup_paths(revs.paths);\n \t}\n-\tif (revs.max_age || revs.min_age)\n+\tif (revs.max_age != -1 || revs.min_age != -1)\n \t\tlimited = 1;\n \n \tsave_commit_buffer = verbose_header;\n"},{"id":"16793","messageId":"Pine.LNX.4.64.0602261914270.22647@g5.osdl.org","threadId":"3463","inReplyTo":"7vpsl93395.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-02-27T03:19:13Z","receivedAt":"2006-02-27T03:19:13Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 26 Feb 2006, Junio C Hamano wrote:\n> \n> I am clueless about the \"limited = (list && list->next)\" part,\n> but there is only one commit involved hence the test is false\n> with my testcase \"git-rev-list --objects v1.0.0^0..v1.0.0\"; I\n> think the old code said dotdot is a limited case.\n\ndotdot should insert _two_ commits onto the list - the positive and \nthe negative one.  Doesn't it? \n\nSo the\n\n\tif (list && list->next)\n\ncheck should be correct. If we have just one entry, there's no reason to \ndo everything up-front, we can just run with it (and get the nice \nstreaming behaviour).\n\n> -static struct object_list *pending_objects = NULL;\n> -\n> -\tfor (pending = pending_objects; pending; pending = pending->next) {\n> +\tfor (pending = revs.pending_objects; pending; pending = pending->next) {\n\nBut this part is obviously correct. I already sent out the same patch a \nminute ago ;)\n\n> -\tif (revs.max_age || revs.min_age)\n> +\tif (revs.max_age != -1 || revs.min_age != -1)\n\nAs is this. I for a while had zero meaning \"no age\", and I actually think \nit probably should be that way, but then we'd have to switch the \ndate-related functions around, which is why I decided not to do it after \nall (but missed this one that I had already written for that case).\n\n\t\tLinus\n"},{"id":"16794","messageId":"7vy7zx1j6u.fsf@assigned-by-dhcp.cox.net","threadId":"3463","inReplyTo":"Pine.LNX.4.64.0602261914270.22647@g5.osdl.org","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-02-27T05:09:45Z","receivedAt":"2006-02-27T05:09:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> On Sun, 26 Feb 2006, Junio C Hamano wrote:\n>> \n>> I am clueless about the \"limited = (list && list->next)\" part,\n>> but there is only one commit involved hence the test is false\n>> with my testcase \"git-rev-list --objects v1.0.0^0..v1.0.0\"; I\n>> think the old code said dotdot is a limited case.\n>\n> dotdot should insert _two_ commits onto the list - the positive and \n> the negative one.  Doesn't it? \n\nNot really, because the second invocation of add_one_commit()\nsays \"I've seen that *commit*\", which is correct.  And the story\nis obviously the same if you used longhand \"^v1.0.0^0 v1.0.0\".\n\nAs a symbolic notation v1.0.0^0..v1.0.0 may not make much sense,\nbut the point is \"the other end says he has that commit object,\nbut now he wants the tag we later attached to that commit\nobject; let's list the objects we need to send him\".  This is\nwhat upload-pack does.\n\nA bad consequence of not limiting is that:\n\n\tgit-rev-list ^v1.0.0^0 v1.0.0 | tail -n 1\n\ngives this commit ;-):\n\n\te83c5163316f89bfbde7d9ab23ca2e25604af290\n\nArgh.\n"},{"id":"16795","messageId":"Pine.LNX.4.64.0602262119200.22647@g5.osdl.org","threadId":"3463","inReplyTo":"7vy7zx1j6u.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-02-27T05:20:12Z","receivedAt":"2006-02-27T05:20:12Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 26 Feb 2006, Junio C Hamano wrote:\n> \n> Not really, because the second invocation of add_one_commit()\n> says \"I've seen that *commit*\", which is correct.  And the story\n> is obviously the same if you used longhand \"^v1.0.0^0 v1.0.0\".\n\nOk.\n\nI suspect that the simplest fix is to just move \"limited\" into the \"revs\" \nstructure, the way I did pretty much everything else. That way nothing \nreally changes: we'll have the exact same logic, the flag just moved \naround.\n\n\t\tLinus\n"},{"id":"16799","messageId":"Pine.LNX.4.63.0602270947380.5937@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"3463","inReplyTo":"7vpsl93395.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-02-27T09:00:09Z","receivedAt":"2006-02-27T09:00:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 26 Feb 2006, Junio C Hamano wrote:\n\n> Johannes gets a test-pilot star for this.  This also means we need a bit \n> better set of tests.\n\nWell, I don't deserve this. I cheated.\n\nIn my personal version of git, there are a few subtle things different \nthan in the official version. Most of them, I sent out already, and they \nwere rejected, such as \nhttp://article.gmane.org/gmane.comp.version-control.git/10718, which \nhelped me tremendously in identyfing the bug.\n\nBut there is also a test case in my version, which was a failure, \noriginally. I wrote it to demonstrate that the stupid version of \ngit-fetch was stupid. It did not demonstrate that, but rather quite a bit \nof (my) normal usage. That is the reason it takes a really long time for a \ntest case, and that in turn is the reason I did not dare to submit it.\n\nCiao,\nDscho\n"},{"id":"16831","messageId":"Pine.LNX.4.64.0602270851560.22647@g5.osdl.org","threadId":"3463","inReplyTo":"Pine.LNX.4.64.0602262119200.22647@g5.osdl.org","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-02-27T16:54:36Z","receivedAt":"2006-02-27T16:54:36Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 26 Feb 2006, Linus Torvalds wrote:\n> \n> I suspect that the simplest fix is to just move \"limited\" into the \"revs\" \n> structure, the way I did pretty much everything else. That way nothing \n> really changes: we'll have the exact same logic, the flag just moved \n> around.\n\nHere's a cleanup patch that does that. It also moves \"unpacked\" (and the \nflag parsing) into rev_info, since that actually does affect the revision \nwalker too, and thus logically belongs there.\n\nIf you prefer, I can generate a totally re-done patch that combines all \nthe fixes so far.\n\n\t\tLinus\n\n----\ndiff-tree d33c6e5017d52d36f8da44162c0d87899efd247c (from 4b0fd13e13f49fa73ddd03a69f7d2ad1109139d4)\nAuthor: Linus Torvalds <torvalds@osdl.org>\nDate:   Mon Feb 27 08:50:26 2006 -0800\n\n    Fix rev-list \"limited\" handling\n    \n    Also, move \"unpacked\" into the rev_info structure, where it logically belongs.\n    \n    Signed-off-by: Linus Torvalds <torvalds@osdl.org>\n\ndiff --git a/rev-list.c b/rev-list.c\nindex e9e371c..2e80930 100644\n--- a/rev-list.c\n+++ b/rev-list.c\n@@ -41,7 +41,6 @@ static const char rev_list_usage[] =\n \n struct rev_info revs;\n \n-static int unpacked = 0;\n static int bisect_list = 0;\n static int verbose_header = 0;\n static int abbrev = DEFAULT_ABBREV;\n@@ -572,7 +571,7 @@ static struct commit_list *limit_list(st\n \n \t\tif (revs.max_age != -1 && (commit->date < revs.max_age))\n \t\t\tobj->flags |= UNINTERESTING;\n-\t\tif (unpacked && has_sha1_pack(obj->sha1))\n+\t\tif (revs.unpacked && has_sha1_pack(obj->sha1))\n \t\t\tobj->flags |= UNINTERESTING;\n \t\tadd_parents_to_list(commit, &list);\n \t\tif (obj->flags & UNINTERESTING) {\n@@ -595,7 +594,7 @@ static struct commit_list *limit_list(st\n int main(int argc, const char **argv)\n {\n \tstruct commit_list *list;\n-\tint i, limited = 0;\n+\tint i;\n \n \targc = setup_revisions(argc, argv, &revs);\n \n@@ -655,11 +654,6 @@ int main(int argc, const char **argv)\n \t\t\tbisect_list = 1;\n \t\t\tcontinue;\n \t\t}\n-\t\tif (!strcmp(arg, \"--unpacked\")) {\n-\t\t\tunpacked = 1;\n-\t\t\tlimited = 1;\n-\t\t\tcontinue;\n-\t\t}\n \t\tif (!strcmp(arg, \"--merge-order\")) {\n \t\t        merge_order = 1;\n \t\t\tcontinue;\n@@ -673,34 +667,25 @@ int main(int argc, const char **argv)\n \t}\n \n \tlist = revs.commits;\n-\tif (list && list->next)\n-\t\tlimited = 1;\n-\n-\tif (revs.topo_order)\n-\t\tlimited = 1;\n \n \tif (!list &&\n \t    (!(revs.tag_objects||revs.tree_objects||revs.blob_objects) && !revs.pending_objects))\n \t\tusage(rev_list_usage);\n \n-\tif (revs.paths) {\n-\t\tlimited = 1;\n+\tif (revs.paths)\n \t\tdiff_tree_setup_paths(revs.paths);\n-\t}\n-\tif (revs.max_age || revs.min_age)\n-\t\tlimited = 1;\n \n \tsave_commit_buffer = verbose_header;\n \ttrack_object_refs = 0;\n \n \tif (!merge_order) {\t\t\n \t\tsort_by_date(&list);\n-\t\tif (list && !limited && revs.max_count == 1 &&\n+\t\tif (list && !revs.limited && revs.max_count == 1 &&\n \t\t    !revs.tag_objects && !revs.tree_objects && !revs.blob_objects) {\n \t\t\tshow_commit(list->item);\n \t\t\treturn 0;\n \t\t}\n-\t        if (limited)\n+\t        if (revs.limited)\n \t\t\tlist = limit_list(list);\n \t\tif (revs.topo_order)\n \t\t\tsort_in_topological_order(&list, revs.lifo);\ndiff --git a/revision.c b/revision.c\nindex 17dbf9a..0422593 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -143,8 +143,10 @@ static struct commit *get_commit_referen\n \t\tobject->flags |= flags;\n \t\tif (parse_commit(commit) < 0)\n \t\t\tdie(\"unable to parse commit %s\", name);\n-\t\tif (flags & UNINTERESTING)\n+\t\tif (flags & UNINTERESTING) {\n \t\t\tmark_parents_uninteresting(commit);\n+\t\t\trevs->limited = 1;\n+\t\t}\n \t\treturn commit;\n \t}\n \n@@ -255,10 +257,12 @@ int setup_revisions(int argc, const char\n \t\t\t}\n \t\t\tif (!strncmp(arg, \"--max-age=\", 10)) {\n \t\t\t\trevs->max_age = atoi(arg + 10);\n+\t\t\t\trevs->limited = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strncmp(arg, \"--min-age=\", 10)) {\n \t\t\t\trevs->min_age = atoi(arg + 10);\n+\t\t\t\trevs->limited = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--all\")) {\n@@ -277,11 +281,13 @@ int setup_revisions(int argc, const char\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--topo-order\")) {\n \t\t\t\trevs->topo_order = 1;\n+\t\t\t\trevs->limited = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--date-order\")) {\n \t\t\t\trevs->lifo = 0;\n \t\t\t\trevs->topo_order = 1;\n+\t\t\t\trevs->limited = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n \t\t\tif (!strcmp(arg, \"--dense\")) {\n@@ -309,6 +315,11 @@ int setup_revisions(int argc, const char\n \t\t\t\trevs->edge_hint = 1;\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!strcmp(arg, \"--unpacked\")) {\n+\t\t\t\trevs->unpacked = 1;\n+\t\t\t\trevs->limited = 1;\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\t*unrecognized++ = arg;\n \t\t\tleft++;\n \t\t\tcontinue;\n@@ -365,6 +376,8 @@ int setup_revisions(int argc, const char\n \t\tcommit = get_commit_reference(revs, def, sha1, 0);\n \t\tadd_one_commit(commit, revs);\n \t}\n+\tif (revs->paths)\n+\t\trevs->limited = 1;\n \t*unrecognized = NULL;\n \treturn left;\n }\ndiff --git a/revision.h b/revision.h\nindex 5170ac4..a22f198 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -21,7 +21,9 @@ struct rev_info {\n \t\t\ttag_objects:1,\n \t\t\ttree_objects:1,\n \t\t\tblob_objects:1,\n-\t\t\tedge_hint:1;\n+\t\t\tedge_hint:1,\n+\t\t\tlimited:1,\n+\t\t\tunpacked:1;\n \n \t/* special limits */\n \tint max_count;\n"},{"id":"16864","messageId":"7vu0akwe4t.fsf@assigned-by-dhcp.cox.net","threadId":"3463","inReplyTo":"Pine.LNX.4.64.0602270851560.22647@g5.osdl.org","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-02-27T23:55:30Z","receivedAt":"2006-02-27T23:55:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Linus Torvalds <torvalds@osdl.org> writes:\n\n> Here's a cleanup patch that does that. It also moves \"unpacked\" (and the \n> flag parsing) into rev_info, since that actually does affect the revision \n> walker too, and thus logically belongs there.\n\nMakes sense.  Thanks.\n"},{"id":"16870","messageId":"7vr75ouvyt.fsf@assigned-by-dhcp.cox.net","threadId":"3463","inReplyTo":"Pine.LNX.4.63.0602270947380.5937@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH] First cut at libifying revlist generation","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-02-28T01:13:14Z","receivedAt":"2006-02-28T01:13:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> writes:\n\n> http://article.gmane.org/gmane.comp.version-control.git/10718, which \n> helped me tremendously in identyfing the bug.\n\nI'm willing to accept a response to \"Yup. That sounds sensible.\"\n"}]}