{"thread":{"id":"93","subject":"[RFC] General object parsing","startedAt":"2005-04-18T00:25:26Z","lastAt":"2005-04-19T02:04:29Z","messageCount":16,"participants":["Daniel Barkalow","Linus Torvalds","David Woodhouse","Junio C Hamano"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"581","messageId":"Pine.LNX.4.21.0504171958520.30848-100000@iabervon.org","threadId":"93","inReplyTo":null,"subject":"[RFC] General object parsing","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T00:25:26Z","receivedAt":"2005-04-18T00:25:26Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"After the fiasco with confusing struct revision for a struct commit, I've\nworked out something that makes more sense. I've actually ported\nfsck-cache, rev-tree, and my merge-base to it, so it should at least be\ncomprehensive.\n\nThe design is as follows:\n\nThere is a struct object for each object in the database, although they\nare only created on demand. It contains the type and sha1 of the\nobject, as well as a flag for whether the object contents have been read,\nmore flags for general use, a list of objects which it references, and a\nflag for whether any objects reference it.\n\nEach struct object is embedded in a type-specific struct, which contains\nfurther information. For example, struct commit has the date, the parents,\nand the tree.\n\nParsing objects is progressive; objects are created in an unread state\n(with no disk access), and functions can be called to parse each object as\nit is determined to be interesting. This should generally allow for only\nthe necessary portions of a large set of object references to be read.\n\nAny comment on the design, or should I send my implementation?\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"},{"id":"591","messageId":"Pine.LNX.4.58.0504171807590.7211@ppc970.osdl.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504171958520.30848-100000@iabervon.org","subject":"Re: [RFC] General object parsing","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-18T01:15:49Z","receivedAt":"2005-04-18T01:15:49Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 17 Apr 2005, Daniel Barkalow wrote:\n> \n> Any comment on the design, or should I send my implementation?\n\nShow the patches, and maybe I (and others) can make comments on the \nthing.. It doesn't sound broken by design, the only question is how much \nharder (if any) it is to use than the rather trivial \"revision.h\" which \ngets us really small files.\n\nIn particular, is there some easy way to walk backwards by time? \"git log\"  \ndefinitely needs that, and merge-base clearly wants something similar. I\nalso pretty much guarantee that visualization tools want that - creating a\nvisual representation of the dag by time.\n\nIf you need to read the whole thing to get that representation, then \ntrying to be clever isn't even worth it - it's such a common thing that I \nbet rev-tree + caches is actually way superior.\n\nBut if there are simple helper functions to get the \"next backwards in \ntime\" case (by looking at the parent dates in a merge), then that should \nbe ok to do incrementally.\n\n\t\t\tLinus\n"},{"id":"604","messageId":"Pine.LNX.4.21.0504172206460.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.58.0504171807590.7211@ppc970.osdl.org","subject":"Re: [RFC] General object parsing","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T02:15:54Z","receivedAt":"2005-04-18T02:15:54Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sun, 17 Apr 2005, Linus Torvalds wrote:\n\n> On Sun, 17 Apr 2005, Daniel Barkalow wrote:\n> > \n> > Any comment on the design, or should I send my implementation?\n> \n> Show the patches, and maybe I (and others) can make comments on the \n> thing.. It doesn't sound broken by design, the only question is how much \n> harder (if any) it is to use than the rather trivial \"revision.h\" which \n> gets us really small files.\n\nI don't think it's much different in difficulty, plus it handles more\n(parsing the objects more completely). They'll follow.\n\n> In particular, is there some easy way to walk backwards by time? \"git log\"  \n> definitely needs that, and merge-base clearly wants something similar. I\n> also pretty much guarantee that visualization tools want that - creating a\n> visual representation of the dag by time.\n\nI think that should be easy, although I haven't written code to do it. If\nyou output the whole history, sorted by date, you obviously need to get \nthe whole history, but I expect people will have some sort of pruning to\nkeep it down to a size they care about.\n\n> But if there are simple helper functions to get the \"next backwards in \n> time\" case (by looking at the parent dates in a merge), then that should \n> be ok to do incrementally.\n\nHaven't written that yet, but I can do so.\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"},{"id":"606","messageId":"Pine.LNX.4.21.0504172229240.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172206460.30848-100000@iabervon.org","subject":"[0/5] Parsers for git objects, porting some programs","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T02:33:49Z","receivedAt":"2005-04-18T02:33:49Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This series introduces common parsers for objects, and ports the programs\nthat currently use revision.h to them.\n\n 1: the header files\n 2: the implementations\n 3: port rev-tree\n 4: port fsck-cache\n 5: port merge-base\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"},{"id":"607","messageId":"Pine.LNX.4.21.0504172233580.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172229240.30848-100000@iabervon.org","subject":"[1/5] Header files for object parsing","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T02:35:21Z","receivedAt":"2005-04-18T02:35:21Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This adds the structs and function declarations for parsing git objects.\n\nSigned-Off-By: Daniel Barkalow <barkalow@iabervon.org>\nIndex: blob.h\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/blob.h  (mode:100644 sha1:9a23db3a7deca67981b67ceb768411e31f723715)\n@@ -0,0 +1,14 @@\n+#ifndef BLOB_H\n+#define BLOB_H\n+\n+#include \"object.h\"\n+\n+extern const char *blob_type;\n+\n+struct blob {\n+\tstruct object object;\n+};\n+\n+struct blob *lookup_blob(unsigned char *sha1);\n+\n+#endif /* BLOB_H */\nIndex: commit.h\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/commit.h  (mode:100644 sha1:8cd20b046875f5f7e534b0607fdd97f330f53272)\n@@ -0,0 +1,27 @@\n+#ifndef COMMIT_H\n+#define COMMIT_H\n+\n+#include \"object.h\"\n+#include \"tree.h\"\n+\n+struct commit_list {\n+\tstruct commit *item;\n+\tstruct commit_list *next;\n+};\n+\n+struct commit {\n+\tstruct object object;\n+\tunsigned long date;\n+\tstruct commit_list *parents;\n+\tstruct tree *tree;\n+};\n+\n+extern const char *commit_type;\n+\n+struct commit *lookup_commit(unsigned char *sha1);\n+\n+int parse_commit(struct commit *item);\n+\n+void free_commit_list(struct commit_list *list);\n+\n+#endif /* COMMIT_H */\nIndex: object.h\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/object.h  (mode:100644 sha1:20f879e0867b8d6a052c458d9230fbc7786d2864)\n@@ -0,0 +1,29 @@\n+#ifndef OBJECT_H\n+#define OBJECT_H\n+\n+struct object_list {\n+\tstruct object *item;\n+\tstruct object_list *next;\n+};\n+\n+struct object {\n+\tunsigned parsed : 1;\n+\tunsigned used : 1;\n+\tunsigned int flags;\n+\tunsigned char sha1[20];\n+\tconst char *type;\n+\tstruct object_list *refs;\n+};\n+\n+int nr_objs;\n+struct object **objs;\n+\n+struct object *lookup_object(unsigned char *sha1);\n+\n+void created_object(unsigned char *sha1, struct object *obj);\n+\n+void add_ref(struct object *refer, struct object *target);\n+\n+void mark_reachable(struct object *obj, unsigned int mask);\n+\n+#endif /* OBJECT_H */\nIndex: tree.h\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/tree.h  (mode:100644 sha1:14ebbacded09d5e058c7f94652dcb9e12bc31cae)\n@@ -0,0 +1,17 @@\n+#ifndef TREE_H\n+#define TREE_H\n+\n+#include \"object.h\"\n+\n+extern const char *tree_type;\n+\n+struct tree {\n+\tstruct object object;\n+\tunsigned has_full_path : 1;\n+};\n+\n+struct tree *lookup_tree(unsigned char *sha1);\n+\n+int parse_tree(struct tree *tree);\n+\n+#endif /* TREE_H */\n\n"},{"id":"608","messageId":"Pine.LNX.4.21.0504172235260.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172229240.30848-100000@iabervon.org","subject":"[2/5] Implementations of parsing functions","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T02:36:20Z","receivedAt":"2005-04-18T02:36:20Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This implements the parsing functions.\n\nSigned-Off-By: Daniel Barkalow <barkalow@iabervon.org>\nIndex: blob.c\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/blob.c  (mode:100644 sha1:04e0c1da9b1f4cdb1d1c5881b785babd3b0ceb09)\n@@ -0,0 +1,24 @@\n+#include \"blob.h\"\n+#include \"cache.h\"\n+#include <stdlib.h>\n+\n+const char *blob_type = \"blob\";\n+\n+struct blob *lookup_blob(unsigned char *sha1)\n+{\n+\tstruct object *obj = lookup_object(sha1);\n+\tif (!obj) {\n+\t\tstruct blob *ret = malloc(sizeof(struct blob));\n+\t\tbzero(ret, sizeof(struct blob));\n+\t\tcreated_object(sha1, &ret->object);\n+\t\tret->object.type = blob_type;\n+\t\tret->object.parsed = 1;\n+\t\treturn ret;\n+\t}\n+\tif (obj->parsed && obj->type != blob_type) {\n+\t\terror(\"Object %s is a %s, not a blob\", \n+\t\t      sha1_to_hex(sha1), obj->type);\n+\t\treturn NULL;\n+\t}\n+\treturn (struct blob *) obj;\n+}\nIndex: commit.c\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/commit.c  (mode:100644 sha1:0099baa63971d86ee30ef2a7da25057f0f45a964)\n@@ -0,0 +1,85 @@\n+#include \"commit.h\"\n+#include \"cache.h\"\n+#include <string.h>\n+\n+const char *commit_type = \"commit\";\n+\n+struct commit *lookup_commit(unsigned char *sha1)\n+{\n+\tstruct object *obj = lookup_object(sha1);\n+\tif (!obj) {\n+\t\tstruct commit *ret = malloc(sizeof(struct commit));\n+\t\tbzero(ret, sizeof(struct commit));\n+\t\tcreated_object(sha1, &ret->object);\n+\t\treturn ret;\n+\t}\n+\tif (obj->parsed && obj->type != commit_type) {\n+\t\terror(\"Object %s is a %s, not a commit\", \n+\t\t      sha1_to_hex(sha1), obj->type);\n+\t\treturn NULL;\n+\t}\n+\treturn (struct commit *) obj;\n+}\n+\n+static unsigned long parse_commit_date(const char *buf)\n+{\n+\tunsigned long date;\n+\n+\tif (memcmp(buf, \"author\", 6))\n+\t\treturn 0;\n+\twhile (*buf++ != '\\n')\n+\t\t/* nada */;\n+\tif (memcmp(buf, \"committer\", 9))\n+\t\treturn 0;\n+\twhile (*buf++ != '>')\n+\t\t/* nada */;\n+\tdate = strtoul(buf, NULL, 10);\n+\tif (date == ULONG_MAX)\n+\t\tdate = 0;\n+\treturn date;\n+}\n+\n+int parse_commit(struct commit *item)\n+{\n+\tchar type[20];\n+\tvoid * buffer, *bufptr;\n+\tunsigned long size;\n+\tunsigned char parent[20];\n+\tif (item->object.parsed)\n+\t\treturn 0;\n+\titem->object.parsed = 1;\n+\tbuffer = bufptr = read_sha1_file(item->object.sha1, type, &size);\n+\tif (!buffer)\n+\t\treturn error(\"Could not read %s\",\n+\t\t\t     sha1_to_hex(item->object.sha1));\n+\tif (strcmp(type, commit_type))\n+\t\treturn error(\"Object %s not a commit\",\n+\t\t\t     sha1_to_hex(item->object.sha1));\n+\titem->object.type = commit_type;\n+\tget_sha1_hex(bufptr + 5, parent);\n+\titem->tree = lookup_tree(parent);\n+\tadd_ref(&item->object, &item->tree->object);\n+\tbufptr += 46; /* \"tree \" + \"hex sha1\" + \"\\n\" */\n+\twhile (!memcmp(bufptr, \"parent \", 7) &&\n+\t       !get_sha1_hex(bufptr + 7, parent)) {\n+\t\tstruct commit_list *new_parent = \n+\t\t\tmalloc(sizeof(struct commit_list));\n+\t\tnew_parent->next = item->parents;\n+\t\tnew_parent->item = lookup_commit(parent);\n+\t\tadd_ref(&item->object, &new_parent->item->object);\n+\t\titem->parents = new_parent;\n+\t\tbufptr += 48;\n+\t}\n+\titem->date = parse_commit_date(bufptr);\n+\tfree(buffer);\n+\treturn 0;\n+}\n+\n+void free_commit_list(struct commit_list *list)\n+{\n+\twhile (list) {\n+\t\tstruct commit_list *temp = list;\n+\t\tlist = temp->next;\n+\t\tfree(temp);\n+\t}\n+}\nIndex: object.c\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/object.c  (mode:100644 sha1:986624ac7a7fd9229e05e1f181fd500640298d9e)\n@@ -0,0 +1,96 @@\n+#include \"object.h\"\n+#include \"cache.h\"\n+#include <stdlib.h>\n+#include <string.h>\n+\n+struct object **objs;\n+int nr_objs;\n+static int obj_allocs;\n+\n+static int find_object(unsigned char *sha1)\n+{\n+\tint first = 0, last = nr_objs;\n+\n+        while (first < last) {\n+                int next = (first + last) / 2;\n+                struct object *obj = objs[next];\n+                int cmp;\n+\n+                cmp = memcmp(sha1, obj->sha1, 20);\n+                if (!cmp)\n+                        return next;\n+                if (cmp < 0) {\n+                        last = next;\n+                        continue;\n+                }\n+                first = next+1;\n+        }\n+        return -first-1;\n+}\n+\n+struct object *lookup_object(unsigned char *sha1)\n+{\n+\tint pos = find_object(sha1);\n+\tif (pos >= 0)\n+\t\treturn objs[pos];\n+\treturn NULL;\n+}\n+\n+void created_object(unsigned char *sha1, struct object *obj)\n+{\n+\tint pos = find_object(sha1);\n+\n+\tobj->parsed = 0;\n+\tmemcpy(obj->sha1, sha1, 20);\n+\tobj->type = NULL;\n+\tobj->refs = NULL;\n+\tobj->used = 0;\n+\n+\tif (pos >= 0)\n+\t\tdie(\"Inserting %s twice\\n\", sha1_to_hex(sha1));\n+\tpos = -pos-1;\n+\n+\tif (obj_allocs == nr_objs) {\n+\t\tobj_allocs = alloc_nr(obj_allocs);\n+\t\tobjs = realloc(objs, obj_allocs * sizeof(struct object *));\n+\t}\n+\n+\t/* Insert it into the right place */\n+\tmemmove(objs + pos + 1, objs + pos, (nr_objs - pos) * \n+\t\tsizeof(struct object *));\n+\n+\tobjs[pos] = obj;\n+\tnr_objs++;\n+}\n+\n+void add_ref(struct object *refer, struct object *target)\n+{\n+\tstruct object_list **pp = &refer->refs;\n+\tstruct object_list *p;\n+\t\n+\twhile ((p = *pp) != NULL) {\n+\t\tif (p->item == target)\n+\t\t\treturn;\n+\t\tpp = &p->next;\n+\t}\n+\n+\ttarget->used = 1;\n+\tp = malloc(sizeof(*p));\n+\tp->item = target;\n+\tp->next = NULL;\n+\t*pp = p;\n+}\n+\n+void mark_reachable(struct object *obj, unsigned int mask)\n+{\n+\tstruct object_list *p = obj->refs;\n+\n+\t/* If we've been here already, don't bother */\n+\tif (obj->flags & mask)\n+\t\treturn;\n+\tobj->flags |= mask;\n+\twhile (p) {\n+\t\tmark_reachable(p->item, mask);\n+\t\tp = p->next;\n+\t}\n+}\nIndex: tree.c\n===================================================================\n--- /dev/null  (tree:5ca133e1b74aee39b2124c0ec9fd51539babb5e0)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/tree.c  (mode:100644 sha1:7c5e5e46f4967b0812b06c0114946c3a6432c8d8)\n@@ -0,0 +1,67 @@\n+#include \"tree.h\"\n+#include \"blob.h\"\n+#include \"cache.h\"\n+#include <stdlib.h>\n+\n+const char *tree_type = \"tree\";\n+\n+struct tree *lookup_tree(unsigned char *sha1)\n+{\n+\tstruct object *obj = lookup_object(sha1);\n+\tif (!obj) {\n+\t\tstruct tree *ret = malloc(sizeof(struct tree));\n+\t\tbzero(ret, sizeof(struct tree));\n+\t\tcreated_object(sha1, &ret->object);\n+\t\treturn ret;\n+\t}\n+\tif (obj->parsed && obj->type != tree_type) {\n+\t\terror(\"Object %s is a %s, not a tree\", \n+\t\t      sha1_to_hex(sha1), obj->type);\n+\t\treturn NULL;\n+\t}\n+\treturn (struct tree *) obj;\n+}\n+\n+int parse_tree(struct tree *item)\n+{\n+\tchar type[20];\n+\tvoid *buffer, *bufptr;\n+\tunsigned long size;\n+\tif (item->object.parsed)\n+\t\treturn 0;\n+\titem->object.parsed = 1;\n+\titem->object.type = tree_type;\n+\tbuffer = bufptr = read_sha1_file(item->object.sha1, type, &size);\n+\tif (!buffer)\n+\t\treturn error(\"Could not read %s\",\n+\t\t\t     sha1_to_hex(item->object.sha1));\n+\tif (strcmp(type, tree_type))\n+\t\treturn error(\"Object %s not a tree\",\n+\t\t\t     sha1_to_hex(item->object.sha1));\n+\twhile (size) {\n+\t\tstruct object *obj;\n+\t\tint len = 1+strlen(bufptr);\n+\t\tunsigned char *file_sha1 = bufptr + len;\n+\t\tchar *path = strchr(bufptr, ' ');\n+\t\tunsigned int mode;\n+\t\tif (size < len + 20 || !path || \n+\t\t    sscanf(bufptr, \"%o\", &mode) != 1)\n+\t\t\treturn -1;\n+\n+\t\t/* Warn about trees that don't do the recursive thing.. */\n+\t\tif (strchr(path, '/')) {\n+\t\t\titem->has_full_path = 1;\n+\t\t}\n+\n+\t\tbufptr += len + 20;\n+\t\tsize -= len + 20;\n+\n+\t\tif (S_ISDIR(mode)) {\n+\t\t\tobj = &lookup_tree(file_sha1)->object;\n+\t\t} else {\n+\t\t\tobj = &lookup_blob(file_sha1)->object;\n+\t\t}\n+\t\tadd_ref(&item->object, obj);\n+\t}\n+\treturn 0;\n+}\n\n"},{"id":"609","messageId":"Pine.LNX.4.21.0504172236261.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172229240.30848-100000@iabervon.org","subject":"[3/5] Port rev-tree to parsing functions","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T02:37:36Z","receivedAt":"2005-04-18T02:37:36Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This ports rev-tree to use the parsing functions introduced in the\nprevious patches.\n\nSigned-Off-By: Daniel Barkalow <barkalow@iabervon.org>\nIndex: Makefile\n===================================================================\n--- 5ca133e1b74aee39b2124c0ec9fd51539babb5e0/Makefile  (mode:100644 sha1:773166a462f88b1c69930ce36d336d3d7badc319)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/Makefile  (mode:100644 sha1:c8908268d3c2253d3905671de5cabe4c84674128)\n@@ -52,8 +52,8 @@\n diff-tree: diff-tree.o read-cache.o\n \t$(CC) $(CFLAGS) -o diff-tree diff-tree.o read-cache.o $(LIBS)\n \n-rev-tree: rev-tree.o read-cache.o\n-\t$(CC) $(CFLAGS) -o rev-tree rev-tree.o read-cache.o $(LIBS)\n+rev-tree: rev-tree.o read-cache.o object.o commit.o tree.o blob.o\n+\t$(CC) $(CFLAGS) -o rev-tree rev-tree.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)\n \n show-files: show-files.o read-cache.o\n \t$(CC) $(CFLAGS) -o show-files show-files.o read-cache.o $(LIBS)\nIndex: rev-tree.c\n===================================================================\n--- 5ca133e1b74aee39b2124c0ec9fd51539babb5e0/rev-tree.c  (mode:100644 sha1:2d331b04c8243baab9546611ced07ba3439ab8ae)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/rev-tree.c  (mode:100644 sha1:38e992ac027c733f38b18932caa4032849936d05)\n@@ -4,7 +4,7 @@\n #include <ctype.h>\n \n #include \"cache.h\"\n-#include \"revision.h\"\n+#include \"commit.h\"\n \n /*\n  * revision.h leaves the low 16 bits of the \"flags\" field of the\n@@ -18,38 +18,7 @@\n \n static void read_cache_file(const char *path)\n {\n-\tFILE *file = fopen(path, \"r\");\n-\tchar line[500];\n-\n-\tif (!file)\n-\t\tdie(\"bad revtree cache file (%s)\", path);\n-\n-\twhile (fgets(line, sizeof(line), file)) {\n-\t\tunsigned long date;\n-\t\tunsigned char sha1[20];\n-\t\tstruct revision *rev;\n-\t\tconst char *buf;\n-\n-\t\tif (sscanf(line, \"%lu\", &date) != 1)\n-\t\t\tbreak;\n-\t\tbuf = strchr(line, ' ');\n-\t\tif (!buf)\n-\t\t\tbreak;\n-\t\tif (get_sha1_hex(buf+1, sha1))\n-\t\t\tbreak;\n-\t\trev = lookup_rev(sha1);\n-\t\trev->flags |= SEEN;\n-\t\trev->date = date;\n-\n-\t\t/* parents? */\n-\t\twhile ((buf = strchr(buf+1, ' ')) != NULL) {\n-\t\t\tunsigned char parent[20];\n-\t\t\tif (get_sha1_hex(buf + 1, parent))\n-\t\t\t\tbreak;\n-\t\t\tadd_relationship(rev, parent);\n-\t\t}\n-\t}\n-\tfclose(file);\n+\tdie(\"no revtree cache file yet\");\n }\n \n /*\n@@ -61,16 +30,16 @@\n  * And sometimes we're only interested in \"edge\" commits, ie\n  * places where the marking changes between parent and child.\n  */\n-static int interesting(struct revision *rev)\n+static int interesting(struct commit *rev)\n {\n-\tunsigned mask = marked(rev);\n+\tunsigned mask = rev->object.flags;\n \n \tif (!mask)\n \t\treturn 0;\n \tif (show_edges) {\n-\t\tstruct parent *p = rev->parent;\n+\t\tstruct commit_list *p = rev->parents;\n \t\twhile (p) {\n-\t\t\tif (mask != marked(p->parent))\n+\t\t\tif (mask != p->item->object.flags)\n \t\t\t\treturn 1;\n \t\t\tp = p->next;\n \t\t}\n@@ -82,6 +51,18 @@\n \treturn 1;\n }\n \n+void process_commit(unsigned char *sha1) {\n+\tstruct commit_list *parents;\n+\tstruct commit *obj = lookup_commit(sha1);\n+\tparse_commit(obj);\n+\t\n+\tparents = obj->parents;\n+\twhile (parents) {\n+\t\tprocess_commit(parents->item->object.sha1);\n+\t\tparents = parents->next;\n+\t}\n+}\n+\n /*\n  * Usage: rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id2>]\n  *\n@@ -119,7 +100,7 @@\n \t\t}\n \t\tif (nr >= MAX_COMMITS || get_sha1_hex(arg, sha1[nr]))\n \t\t\tusage(\"rev-tree [--edges] [--cache <cache-file>] <commit-id> [<commit-id>]\");\n-\t\tparse_commit(sha1[nr]);\n+\t\tprocess_commit(sha1[nr]);\n \t\tnr++;\n \t}\n \n@@ -127,22 +108,30 @@\n \t * Now we have the maximal tree. Walk the different sha files back to the root.\n \t */\n \tfor (i = 0; i < nr; i++)\n-\t\tmark_reachable(lookup_rev(sha1[i]), 1 << i);\n+\t\tmark_reachable(&lookup_commit(sha1[i])->object, 1 << i);\n \n \t/*\n \t * Now print out the results..\n \t */\n-\tfor (i = 0; i < nr_revs; i++) {\n-\t\tstruct revision *rev = revs[i];\n-\t\tstruct parent *p;\n+\tfor (i = 0; i < nr_objs; i++) {\n+\t\tstruct object *obj = objs[i];\n+\t\tstruct commit *commit;\n+\t\tstruct commit_list *p;\n+\n+\t\tif (obj->type != commit_type)\n+\t\t\tcontinue;\n+\n+\t\tcommit = (struct commit *) obj;\n \n-\t\tif (!interesting(rev))\n+\t\tif (!interesting(commit))\n \t\t\tcontinue;\n \n-\t\tprintf(\"%lu %s:%d\", rev->date, sha1_to_hex(rev->sha1), marked(rev));\n-\t\tp = rev->parent;\n+\t\tprintf(\"%lu %s:%d\", commit->date, sha1_to_hex(obj->sha1), \n+\t\t       obj->flags);\n+\t\tp = commit->parents;\n \t\twhile (p) {\n-\t\t\tprintf(\" %s:%d\", sha1_to_hex(p->parent->sha1), marked(p->parent));\n+\t\t\tprintf(\" %s:%d\", sha1_to_hex(p->item->object.sha1), \n+\t\t\t       p->item->object.flags);\n \t\t\tp = p->next;\n \t\t}\n \t\tprintf(\"\\n\");\n\n"},{"id":"610","messageId":"Pine.LNX.4.21.0504172237390.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172229240.30848-100000@iabervon.org","subject":"[4/5] Port fsck-cache to use parsing functions","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T02:40:21Z","receivedAt":"2005-04-18T02:40:21Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This ports fsck-cache to use parsing functions. Note that performance\ncould be improved here by only reading each object once, but this requires\nsomewhat more complicated flow control.\n\nSigned-Off-By: Daniel Barkalow <barkalow@iabervon.org>\nIndex: Makefile\n===================================================================\n--- 499f6cf77edad6935da0106cca4472e50fdbde34/Makefile  (mode:100644 sha1:f00a9c3c1cdbfef7e96cfa98256aad35e63131e7)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/Makefile  (mode:100644 sha1:c8908268d3c2253d3905671de5cabe4c84674128)\n@@ -43,8 +43,8 @@\n cat-file: cat-file.o read-cache.o\n \t$(CC) $(CFLAGS) -o cat-file cat-file.o read-cache.o $(LIBS)\n \n-fsck-cache: fsck-cache.o read-cache.o\n-\t$(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o $(LIBS)\n+fsck-cache: fsck-cache.o read-cache.o object.o commit.o tree.o blob.o\n+\t$(CC) $(CFLAGS) -o fsck-cache fsck-cache.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)\n \n checkout-cache: checkout-cache.o read-cache.o\n \t$(CC) $(CFLAGS) -o checkout-cache checkout-cache.o read-cache.o $(LIBS)\nIndex: fsck-cache.c\n===================================================================\n--- 499f6cf77edad6935da0106cca4472e50fdbde34/fsck-cache.c  (mode:100644 sha1:cff04ce34e9445cd57db9c1026040d56f045e5e7)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/fsck-cache.c  (mode:100644 sha1:2000f16efc84911a51a40664fef8a637c90e2dcc)\n@@ -3,7 +3,11 @@\n #include <sys/types.h>\n #include <dirent.h>\n \n-#include \"revision.h\"\n+#include \"commit.h\"\n+#include \"tree.h\"\n+#include \"blob.h\"\n+\n+#define REACHABLE 0x0001\n \n static int show_unreachable = 0;\n static unsigned char head_sha1[20];\n@@ -13,96 +17,54 @@\n \tint i;\n \n \t/* Look up all the requirements, warn about missing objects.. */\n-\tfor (i = 0; i < nr_revs; i++) {\n-\t\tstruct revision *rev = revs[i];\n+\tfor (i = 0; i < nr_objs; i++) {\n+\t\tstruct object *obj = objs[i];\n \n-\t\tif (show_unreachable && !(rev->flags & REACHABLE)) {\n-\t\t\tprintf(\"unreachable %s\\n\", sha1_to_hex(rev->sha1));\n+\t\tif (show_unreachable && !(obj->flags & REACHABLE)) {\n+\t\t\tprintf(\"unreachable %s\\n\", sha1_to_hex(obj->sha1));\n \t\t\tcontinue;\n \t\t}\n \n-\t\tswitch (rev->flags & (SEEN | USED)) {\n-\t\tcase 0:\n-\t\t\tprintf(\"bad %s\\n\", sha1_to_hex(rev->sha1));\n-\t\t\tbreak;\n-\t\tcase USED:\n-\t\t\tprintf(\"missing %s\\n\", sha1_to_hex(rev->sha1));\n-\t\t\tbreak;\n-\t\tcase SEEN:\n-\t\t\tprintf(\"dangling %s\\n\", sha1_to_hex(rev->sha1));\n-\t\t\tbreak;\n+\t\tif (!obj->parsed) {\n+\t\t\tprintf(\"missing %s %s\\n\", obj->type, \n+\t\t\t       sha1_to_hex(obj->sha1));\n+\t\t}\n+\t\tif (!obj->used) {\n+\t\t\tprintf(\"dangling %s %s\\n\", obj->type, \n+\t\t\t       sha1_to_hex(obj->sha1));\n \t\t}\n \t}\n }\n \n-static void mark_needs_sha1(unsigned char *parent, const char * tag, unsigned char *child)\n-{\n-\tstruct revision * child_rev = add_relationship(lookup_rev(parent), child);\n-\tchild_rev->flags |= USED;\n-}\n-\n-static int mark_sha1_seen(unsigned char *sha1, char *tag)\n-{\n-\tstruct revision *rev = lookup_rev(sha1);\n-\n-\trev->flags |= SEEN;\n-\treturn 0;\n-}\n-\n static int fsck_tree(unsigned char *sha1, void *data, unsigned long size)\n {\n-\tint warn_old_tree = 1;\n-\n-\twhile (size) {\n-\t\tint len = 1+strlen(data);\n-\t\tunsigned char *file_sha1 = data + len;\n-\t\tchar *path = strchr(data, ' ');\n-\t\tunsigned int mode;\n-\t\tif (size < len + 20 || !path || sscanf(data, \"%o\", &mode) != 1)\n-\t\t\treturn -1;\n-\n-\t\t/* Warn about trees that don't do the recursive thing.. */\n-\t\tif (warn_old_tree && strchr(path, '/')) {\n-\t\t\tfprintf(stderr, \"warning: fsck-cache: tree %s has full pathnames in it\\n\", sha1_to_hex(sha1));\n-\t\t\twarn_old_tree = 0;\n-\t\t}\n-\n-\t\tdata += len + 20;\n-\t\tsize -= len + 20;\n-\t\tmark_needs_sha1(sha1, S_ISDIR(mode) ? \"tree\" : \"blob\", file_sha1);\n+\tstruct tree *item = lookup_tree(sha1);\n+\tif (parse_tree(item))\n+\t\treturn -1;\n+\tif (item->has_full_path) {\n+\t\tfprintf(stderr, \"warning: fsck-cache: tree %s \"\n+\t\t\t\"has full pathnames in it\\n\", sha1_to_hex(sha1));\n \t}\n \treturn 0;\n }\n \n static int fsck_commit(unsigned char *sha1, void *data, unsigned long size)\n {\n-\tint parents;\n-\tunsigned char tree_sha1[20];\n-\tunsigned char parent_sha1[20];\n-\n-\tif (memcmp(data, \"tree \", 5))\n+\tstruct commit *commit = lookup_commit(sha1);\n+\tif (parse_commit(commit))\n \t\treturn -1;\n-\tif (get_sha1_hex(data + 5, tree_sha1) < 0)\n+\tif (!commit->tree)\n \t\treturn -1;\n-\tmark_needs_sha1(sha1, \"tree\", tree_sha1);\n-\tdata += 5 + 40 + 1;\t/* \"tree \" + <hex sha1> + '\\n' */\n-\tparents = 0;\n-\twhile (!memcmp(data, \"parent \", 7)) {\n-\t\tif (get_sha1_hex(data + 7, parent_sha1) < 0)\n-\t\t\treturn -1;\n-\t\tmark_needs_sha1(sha1, \"commit\", parent_sha1);\n-\t\tdata += 7 + 40 + 1; \t/* \"parent \" + <hex sha1> + '\\n' */\n-\t\tparents++;\n-\t}\n-\tif (!parents)\n+\tif (!commit->parents)\n \t\tprintf(\"root %s\\n\", sha1_to_hex(sha1));\n \treturn 0;\n }\n \n-static int fsck_entry(unsigned char *sha1, char *tag, void *data, unsigned long size)\n+static int fsck_entry(unsigned char *sha1, char *tag, void *data, \n+\t\t      unsigned long size)\n {\n \tif (!strcmp(tag, \"blob\")) {\n-\t\t/* Nothing to check */;\n+\t\tlookup_blob(sha1); /* Nothing to check; but notice it. */\n \t} else if (!strcmp(tag, \"tree\")) {\n \t\tif (fsck_tree(sha1, data, size) < 0)\n \t\t\treturn -1;\n@@ -111,7 +73,7 @@\n \t\t\treturn -1;\n \t} else\n \t\treturn -1;\n-\treturn mark_sha1_seen(sha1, tag);\n+\treturn 0;\n }\n \n static int fsck_name(char *hex)\n@@ -125,7 +87,8 @@\n \t\t\tunsigned long size;\n \t\t\tvoid *buffer = NULL;\n \t\t\tif (!check_sha1_signature(sha1, map, mapsize))\n-\t\t\t\tbuffer = unpack_sha1_file(map, mapsize, type, &size);\n+\t\t\t\tbuffer = unpack_sha1_file(map, mapsize, type,\n+\t\t\t\t\t\t\t  &size);\n \t\t\tmunmap(map, mapsize);\n \t\t\tif (buffer && !fsck_entry(sha1, type, buffer, size))\n \t\t\t\treturn 0;\n@@ -186,7 +149,10 @@\n \t\t\tcontinue;\n \t\t}\n \t\tif (!get_sha1_hex(argv[i], head_sha1)) {\n-\t\t\tmark_reachable(lookup_rev(head_sha1), REACHABLE);\n+\t\t\tstruct object *obj =\n+\t\t\t\t&lookup_commit(head_sha1)->object;\n+\t\t\tobj->used = 1;\n+\t\t\tmark_reachable(obj, REACHABLE);\n \t\t\theads++;\n \t\t\tcontinue;\n \t\t}\n\n"},{"id":"611","messageId":"Pine.LNX.4.21.0504172240250.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172229240.30848-100000@iabervon.org","subject":"[5/5] Switch implementations of merge-base, port to parsing","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T02:42:38Z","receivedAt":"2005-04-18T02:42:38Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This switches to my implementation of merge-base, but with the new parsing\nlibrary.\n\nSigned-Off-By: Daniel Barkalow <barkalow@iabervon.org>\nIndex: Makefile\n===================================================================\n--- 108bfb69c14c55c3c6e30a298307390c82cf1b3b/Makefile  (mode:100644 sha1:affc0e96030d4514f8306ee29020ca6bb320648f)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/Makefile  (mode:100644 sha1:c8908268d3c2253d3905671de5cabe4c84674128)\n@@ -64,8 +64,8 @@\n ls-tree: ls-tree.o read-cache.o\n \t$(CC) $(CFLAGS) -o ls-tree ls-tree.o read-cache.o $(LIBS)\n \n-merge-base: merge-base.o read-cache.o\n-\t$(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o $(LIBS)\n+merge-base: merge-base.o read-cache.o object.o commit.o tree.o blob.o\n+\t$(CC) $(CFLAGS) -o merge-base merge-base.o read-cache.o object.o commit.o tree.o blob.o $(LIBS)\n \n read-cache.o: cache.h\n show-diff.o: cache.h\nIndex: merge-base.c\n===================================================================\n--- 108bfb69c14c55c3c6e30a298307390c82cf1b3b/merge-base.c  (mode:100644 sha1:c98cad0befcf7e04fcc329d9bb7cb550506a4574)\n+++ 1172a9b8f45b2fd640985595cc5258db3b027828/merge-base.c  (mode:100644 sha1:414ff419c679dba122b2f21b698c1e2c8abdd965)\n@@ -1,57 +1,95 @@\n+#include <stdlib.h>\n #include \"cache.h\"\n-#include \"revision.h\"\n+#include \"commit.h\"\n \n-/*\n- * This is stupid. We could have much better heurstics, I bet.\n- */\n-static int better(struct revision *new, struct revision *old)\n+static struct commit *process_list(struct commit_list **list_p, int this_mark,\n+\t\t\t\t   int other_mark)\n {\n-\treturn new->date > old->date;\n+\tstruct commit_list *parent, *temp;\n+\tstruct commit_list *posn = *list_p;\n+\t*list_p = NULL;\n+\twhile (posn) {\n+\t\tparse_commit(posn->item);\n+\t\tif (posn->item->object.flags & this_mark) {\n+\t\t\t/*\n+\t\t\t  printf(\"%d already seen %s %x\\n\",\n+\t\t\t  this_mark\n+\t\t\t  sha1_to_hex(posn->parent->sha1),\n+\t\t\t  posn->parent->flags);\n+\t\t\t*/\n+\t\t\t/* do nothing; this indicates that this side\n+\t\t\t * split and reformed, and we only need to\n+\t\t\t * mark it once.\n+\t\t\t */\n+\t\t} else if (posn->item->object.flags & other_mark) {\n+\t\t\treturn posn->item;\n+\t\t} else {\n+\t\t\t/*\n+\t\t\t  printf(\"%d based on %s\\n\",\n+\t\t\t  this_mark,\n+\t\t\t  sha1_to_hex(posn->parent->sha1));\n+\t\t\t*/\n+\t\t\tposn->item->object.flags |= this_mark;\n+\t\t\t\n+\t\t\tparent = posn->item->parents;\n+\t\t\twhile (parent) {\n+\t\t\t\ttemp = malloc(sizeof(struct commit_list));\n+\t\t\t\ttemp->next = *list_p;\n+\t\t\t\ttemp->item = parent->item;\n+\t\t\t\t*list_p = temp;\n+\t\t\t\tparent = parent->next;\n+\t\t\t}\n+\t\t}\n+\t\tposn = posn->next;\n+\t}\n+\treturn NULL;\n }\n \n-static struct revision *common_parent(struct revision *rev1, struct revision *rev2)\n+struct commit *common_ancestor(struct commit *rev1, struct commit *rev2)\n {\n-\tint i;\n-\tstruct revision *best = NULL;\n+\tstruct commit_list *rev1list = malloc(sizeof(struct commit_list));\n+\tstruct commit_list *rev2list = malloc(sizeof(struct commit_list));\n+\n+\trev1list->item = rev1;\n+\trev1list->next = NULL;\n+\n+\trev2list->item = rev2;\n+\trev2list->next = NULL;\n \n-\tmark_reachable(rev1, 1);\n-\tmark_reachable(rev2, 2);\n-\tfor (i = 0; i < nr_revs ;i++) {\n-\t\tstruct revision *rev = revs[i];\n-\t\tif ((rev->flags & 3) != 3)\n-\t\t\tcontinue;\n-\t\tif (!best) {\n-\t\t\tbest = rev;\n-\t\t\tcontinue;\n+\twhile (rev1list || rev2list) {\n+\t\tstruct commit *ret;\n+\t\tret = process_list(&rev1list, 0x1, 0x2);\n+\t\tif (ret) {\n+\t\t\t/* XXXX free lists */\n+\t\t\treturn ret;\n+\t\t}\n+\t\tret = process_list(&rev2list, 0x2, 0x1);\n+\t\tif (ret) {\n+\t\t\t/* XXXX free lists */\n+\t\t\treturn ret;\n \t\t}\n-\t\tif (better(rev, best))\n-\t\t\tbest = rev;\n \t}\n-\treturn best;\n+\treturn NULL;\n }\n \n int main(int argc, char **argv)\n {\n-\tunsigned char rev1[20], rev2[20];\n-\tstruct revision *common;\n-\n-\tif (argc != 3 || get_sha1_hex(argv[1], rev1) || get_sha1_hex(argv[2], rev2))\n-\t\tusage(\"merge-base <commit1> <commit2>\");\n+\tstruct commit *rev1, *rev2, *ret;\n+\tunsigned char rev1key[20], rev2key[20];\n \n-\t/*\n-\t * We will eventually want to include a revision cache file\n-\t * that \"rev-tree.c\" has generated, since this is going to\n-\t * otherwise be quite expensive for big trees..\n-\t *\n-\t * That's some time off, though, and in the meantime we know\n-\t * that we have a solution to the eventual expense.\n-\t */\n-\tparse_commit(rev1);\n-\tparse_commit(rev2);\n-\n-\tcommon = common_parent(lookup_rev(rev1), lookup_rev(rev2));\n-\tif (!common)\n-\t\tdie(\"no common parent found\");\n-\tprintf(\"%s\\n\", sha1_to_hex(common->sha1));\n-\treturn 0;\n+\tif (argc != 3 ||\n+\t    get_sha1_hex(argv[1], rev1key) ||\n+\t    get_sha1_hex(argv[2], rev2key)) {\n+\t\tusage(\"merge-base <commit-id> <commit-id>\");\n+\t}\n+\trev1 = lookup_commit(rev1key);\n+\trev2 = lookup_commit(rev2key);\n+\tret = common_ancestor(rev1, rev2);\n+\tif (ret) {\n+\t\tprintf(\"%s\\n\", sha1_to_hex(ret->object.sha1));\n+\t\treturn 0;\n+\t} else {\n+\t\treturn 1;\n+\t}\n+\t\n }\n\n"},{"id":"620","messageId":"Pine.LNX.4.21.0504172337380.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172206460.30848-100000@iabervon.org","subject":"Re: [RFC] General object parsing","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T03:51:48Z","receivedAt":"2005-04-18T03:51:48Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Sun, 17 Apr 2005, Daniel Barkalow wrote:\n\n> > But if there are simple helper functions to get the \"next backwards in \n> > time\" case (by looking at the parent dates in a merge), then that should \n> > be ok to do incrementally.\n> \n> Haven't written that yet, but I can do so.\n\nOkay, I wrote this. I now have a merge-base that will find the most recent\nancestor while never looking at any parents of any commit older than the\nanswer. (But I'll let the previous stuff get reviewed first)\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"},{"id":"624","messageId":"1113799537.11910.76.camel@localhost.localdomain","threadId":"93","inReplyTo":"Pine.LNX.4.58.0504171807590.7211@ppc970.osdl.org","subject":"Re: [RFC] General object parsing","fromName":"David Woodhouse","fromEmail":"dwmw2@infradead.org","sentAt":"2005-04-18T04:45:36Z","receivedAt":"2005-04-18T04:45:36Z","isPatch":false,"sender":{"key":"dwmw2@infradead.org","avatar":"https://gravatar.com/avatar/7afd4f07e0cf7d7e046ae2d23678296b37777c96488e6f3451e78a5514154ebd?d=mp&s=160"},"body":"On Sun, 2005-04-17 at 18:15 -0700, Linus Torvalds wrote:\n> In particular, is there some easy way to walk backwards by time? \"git log\"  \n> definitely needs that, and merge-base clearly wants something similar. \n\nActually the ideal output of 'git log' isn't strictly chronological.\nIIRC my bkexport scripts used to make a chronologically sorted list, and\nI ended up changing it.\n\nSimple example: if there are changesets which have been lurking in some\ntree for months waiting for you to pull, and the only thing you did\nsince I ran 'git log' on your tree yesterday is pull from that tree,\nthen those changesets are what I want to see at the top of 'git log'\noutput.\n\nIn fact this probably means that the depth-first tree walking of the\noriginal gitlog.sh is probably the right thing to do, but when we hit a\nmerge we want to try to make sure we process the _remote_ parent first.\n\nAre we sorting the 'parent' links in merges so that two merges of the\nsame branches are guaranteed to be identical (assuming identical\ncontents otherwise)? Or is it just that we didn't think about it, and so\nmerges are putting the local and remote parents in the 'wrong' order by\ncoincidence?\n\n-- \ndwmw2\n\n"},{"id":"676","messageId":"Pine.LNX.4.58.0504181126480.15725@ppc970.osdl.org","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504172229240.30848-100000@iabervon.org","subject":"Re: [0/5] Parsers for git objects, porting some programs","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2005-04-18T18:34:35Z","receivedAt":"2005-04-18T18:34:35Z","isPatch":false,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Sun, 17 Apr 2005, Daniel Barkalow wrote:\n>\n> This series introduces common parsers for objects, and ports the programs\n> that currently use revision.h to them.\n> \n>  1: the header files\n>  2: the implementations\n>  3: port rev-tree\n>  4: port fsck-cache\n>  5: port merge-base\n\nOk, having now looked at the code, I don't have any objections at all. \nCould you clarify the \"fsck\" issue about reading the same object twice? \nWhen does that happen?\n\n\t\tLinus\n"},{"id":"684","messageId":"Pine.LNX.4.21.0504181558180.30848-100000@iabervon.org","threadId":"93","inReplyTo":"Pine.LNX.4.58.0504181126480.15725@ppc970.osdl.org","subject":"Re: [0/5] Parsers for git objects, porting some programs","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-18T20:12:00Z","receivedAt":"2005-04-18T20:12:00Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 18 Apr 2005, Linus Torvalds wrote:\n\n> On Sun, 17 Apr 2005, Daniel Barkalow wrote:\n> >\n> > This series introduces common parsers for objects, and ports the programs\n> > that currently use revision.h to them.\n> > \n> >  1: the header files\n> >  2: the implementations\n> >  3: port rev-tree\n> >  4: port fsck-cache\n> >  5: port merge-base\n> \n> Ok, having now looked at the code, I don't have any objections at all. \n> Could you clarify the \"fsck\" issue about reading the same object twice? \n> When does that happen?\n\nCurrently, the fsck-cache code is unpacking the objects to find out what\ntype they are, and the old code would pass the unpacked objects to the\nparsing code. The new code doesn't take the unpacked objects, so it\nunpacks them again. (I.e., fsck-cache will look at each object exactly\ntwice). The right solution is to have the internals reorganized slightly\nsuch that a \"parse_object\" method, which does what fsck-cache wants (i.e.,\nparse this object regardless of what type it is, and tell me the type),\ncould be fit in efficiently. But it doesn't affect the header file\ninterface, and it's only relevant to fsck-cache, which wants to look at\nrandom junk that it doesn't have a reference to.\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"},{"id":"753","messageId":"7v7jizsh1f.fsf@assigned-by-dhcp.cox.net","threadId":"93","inReplyTo":"Pine.LNX.4.21.0504181558180.30848-100000@iabervon.org","subject":"Re: [0/5] Parsers for git objects, porting some programs","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-04-19T01:15:40Z","receivedAt":"2005-04-19T01:15:40Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":">>>>> \"DB\" == Daniel Barkalow <barkalow@iabervon.org> writes:\n\nDB> On Mon, 18 Apr 2005, Linus Torvalds wrote:\n>> On Sun, 17 Apr 2005, Daniel Barkalow wrote:\n>> >\n>> > This series introduces common parsers for objects, and ports the programs\n>> > that currently use revision.h to them.\n>> > \n>> >  1: the header files\n>> >  2: the implementations\n>> >  3: port rev-tree\n>> >  4: port fsck-cache\n>> >  5: port merge-base\n>> \n>> Ok, having now looked at the code, I don't have any objections at all. \n\nI was looking at the tree part and am thinking that it would\nmake it much nicer if your tree object records path for each\nentry.  Currently it just borrows from object.refs to represent\nits children, which is good enough for the applications listed\nabove (none of them would care where in the tree the object\nbelongs to), but I was thinking about an incremental dumper I\ntalked about in another thread and noticed that I cannot use the\ncurrent struct tree as is to compare two trees to find related\nsha1 files (then I would inflate both, run diff and record the\noutput as a recipe to create one sha1 object from the other).\n\nOr am I misreading the code that parses tree objects?\n\n"},{"id":"755","messageId":"Pine.LNX.4.21.0504182118170.30848-100000@iabervon.org","threadId":"93","inReplyTo":"7v7jizsh1f.fsf@assigned-by-dhcp.cox.net","subject":"Re: [0/5] Parsers for git objects, porting some programs","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-19T01:23:56Z","receivedAt":"2005-04-19T01:23:56Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 18 Apr 2005, Junio C Hamano wrote:\n\n> I was looking at the tree part and am thinking that it would\n> make it much nicer if your tree object records path for each\n> entry. \n\nYou're entirely right, and I've actually now written the code that does\nit. I'm planning to send out a patch for that shortly.\n\n> Currently it just borrows from object.refs to represent\n> its children\n\nNote that object.refs needs to get filled out for those\napplications, even if the information is also included in the\nparse; object.refs is for finding what you can reach without worrying\nabout how you do it.\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"},{"id":"766","messageId":"Pine.LNX.4.21.0504182201190.30848-100000@iabervon.org","threadId":"93","inReplyTo":"7v7jizsh1f.fsf@assigned-by-dhcp.cox.net","subject":"Re: [0/5] Parsers for git objects, porting some programs","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-04-19T02:04:29Z","receivedAt":"2005-04-19T02:04:29Z","isPatch":false,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"On Mon, 18 Apr 2005, Junio C Hamano wrote:\n\n> >>>>> \"DB\" == Daniel Barkalow <barkalow@iabervon.org> writes:\n> \n> DB> On Mon, 18 Apr 2005, Linus Torvalds wrote:\n> >> On Sun, 17 Apr 2005, Daniel Barkalow wrote:\n> >> >\n> >> > This series introduces common parsers for objects, and ports the programs\n> >> > that currently use revision.h to them.\n> >> > \n> >> >  1: the header files\n> >> >  2: the implementations\n> >> >  3: port rev-tree\n> >> >  4: port fsck-cache\n> >> >  5: port merge-base\n> >> \n> >> Ok, having now looked at the code, I don't have any objections at all. \n> \n> I was looking at the tree part and am thinking that it would\n> make it much nicer if your tree object records path for each\n> entry.\n\nAs it turns out, the code I just doesn't actually record the path; it does\neverything else, and it should be easy to add the path to those entries. I\nmainly wanted object type (i.e., do I have to recurse into the object), so\nI skipped that one. But it should now be clear what you need to add.\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"}]}