{"thread":{"id":"4343","subject":"[PATCH 0/10] re-based and expanded tree-walker cleanup patches","startedAt":"2006-05-29T19:15:01Z","lastAt":"2006-06-26T00:44:26Z","messageCount":24,"participants":["Linus Torvalds","Junio C Hamano","Shawn Pearce","Eric W. Biederman"],"isPatch":true,"patchVersion":1,"patchTotal":10},"messages":[{"id":"20897","messageId":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","threadId":"4343","inReplyTo":null,"subject":"[PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:15:01Z","receivedAt":"2006-05-29T19:15:01Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nOk, this is largely the same series as the previous 1..4 patches, but \nrebased on top of the current master tree because the cache-tree patches \nadded some tree_entry_list walkers (which accounts for one extra patch in \nthe series, and some trivial merge fixups).\n\nTwo new patches then clean up fsck-objects, which really didn't want the \nold tree_entry_list at all (and had added some hacks to the list entry \njust because fsck actually needed to check the raw data).\n\nAnother two new patches convert the last remnant of tree_entry_list in \nrevision.c and fetch.c respectively to the new world order.\n\nAnd the final patch then moves the \"tree_entry_list\" crud into the only \nremaining user, namely builtin-read-tree.c. That file is pretty messy and \nhard to convert, and I don't want to touch it right now, so I left it with \nthe nasty compatibility functions. But now that's at least well-contained.\n\nI think the series is all good, and should replace the old one in \"next\" \n(and cook there for a while just to make sure it's ok).\n\n\t\tLinus\n"},{"id":"20898","messageId":"Pine.LNX.4.64.0605291215280.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 1/10] Make \"struct tree\" contain the pointer to the tree buffer","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:16:12Z","receivedAt":"2006-05-29T19:16:12Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis allows us to avoid allocating information for names etc, because\nwe can just use the information from the tree buffer directly.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n builtin-read-tree.c |    4 ++--\n builtin-rev-list.c  |    3 ++-\n fsck-objects.c      |    7 +++----\n object.c            |    5 ++++-\n tree.c              |   47 ++++++++++++++++++++++-------------------------\n tree.h              |    4 +++-\n 6 files changed, 36 insertions(+), 34 deletions(-)\n\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 716f792..6876f3d 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -39,7 +39,7 @@ static struct tree_entry_list df_conflic\n \n typedef int (*merge_fn_t)(struct cache_entry **src);\n \n-static int entcmp(char *name1, int dir1, char *name2, int dir2)\n+static int entcmp(const char *name1, int dir1, const char *name2, int dir2)\n {\n \tint len1 = strlen(name1);\n \tint len2 = strlen(name2);\n@@ -67,7 +67,7 @@ static int unpack_trees_rec(struct tree_\n \tint src_size = len + 1;\n \tdo {\n \t\tint i;\n-\t\tchar *first;\n+\t\tconst char *first;\n \t\tint firstdir = 0;\n \t\tint pathlen;\n \t\tunsigned ce_size;\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 5277d3c..72c1549 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -136,10 +136,11 @@ static struct object_list **process_tree\n \t\t\tp = process_tree(entry->item.tree, p, &me, entry->name);\n \t\telse\n \t\t\tp = process_blob(entry->item.blob, p, &me, entry->name);\n-\t\tfree(entry->name);\n \t\tfree(entry);\n \t\tentry = next;\n \t}\n+\tfree(tree->buffer);\n+\ttree->buffer = NULL;\n \treturn p;\n }\n \ndiff --git a/fsck-objects.c b/fsck-objects.c\nindex 1922b6d..5e65df4 100644\n--- a/fsck-objects.c\n+++ b/fsck-objects.c\n@@ -198,17 +198,16 @@ static int fsck_tree(struct tree *item)\n \t\t\tdefault:\n \t\t\t\tbreak;\n \t\t\t}\n-\t\t\tfree(last->name);\n \t\t\tfree(last);\n \t\t}\n \n \t\tlast = entry;\n \t}\n-\tif (last) {\n-\t\tfree(last->name);\n+\tif (last)\n \t\tfree(last);\n-\t}\n \titem->entries = NULL;\n+\tfree(item->buffer);\n+\titem->buffer = NULL;\n \n \tretval = 0;\n \tif (has_full_path) {\ndiff --git a/object.c b/object.c\nindex 4d46e0d..1a7823c 100644\n--- a/object.c\n+++ b/object.c\n@@ -200,8 +200,11 @@ struct object *parse_object(const unsign\n \t\t\tobj = &blob->object;\n \t\t} else if (!strcmp(type, tree_type)) {\n \t\t\tstruct tree *tree = lookup_tree(sha1);\n-\t\t\tparse_tree_buffer(tree, buffer, size);\n \t\t\tobj = &tree->object;\n+\t\t\tif (!tree->object.parsed) {\n+\t\t\t\tparse_tree_buffer(tree, buffer, size);\n+\t\t\t\tbuffer = NULL;\n+\t\t\t}\n \t\t} else if (!strcmp(type, commit_type)) {\n \t\t\tstruct commit *commit = lookup_commit(sha1);\n \t\t\tparse_commit_buffer(commit, buffer, size);\ndiff --git a/tree.c b/tree.c\nindex d599fb5..1e76d9c 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -3,6 +3,7 @@ #include \"tree.h\"\n #include \"blob.h\"\n #include \"commit.h\"\n #include \"tag.h\"\n+#include \"tree-walk.h\"\n #include <stdlib.h>\n \n const char *tree_type = \"tree\";\n@@ -145,46 +146,45 @@ struct tree *lookup_tree(const unsigned \n \n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n {\n-\tvoid *bufptr = buffer;\n+\tstruct tree_desc desc;\n \tstruct tree_entry_list **list_p;\n \tint n_refs = 0;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n \titem->object.parsed = 1;\n+\titem->buffer = buffer;\n+\titem->size = size;\n+\n+\tdesc.buf = buffer;\n+\tdesc.size = size;\n+\n \tlist_p = &item->entries;\n-\twhile (size) {\n-\t\tstruct object *obj;\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *path;\n+\t\tconst unsigned char *sha1;\n \t\tstruct tree_entry_list *entry;\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\tsha1 = tree_entry_extract(&desc, &path, &mode);\n \n \t\tentry = xmalloc(sizeof(struct tree_entry_list));\n-\t\tentry->name = strdup(path + 1);\n+\t\tentry->name = path;\n+\t\tentry->mode = mode;\n \t\tentry->directory = S_ISDIR(mode) != 0;\n \t\tentry->executable = (mode & S_IXUSR) != 0;\n \t\tentry->symlink = S_ISLNK(mode) != 0;\n-\t\tentry->zeropad = *(char *)bufptr == '0';\n-\t\tentry->mode = mode;\n+\t\tentry->zeropad = *(const char *)(desc.buf) == '0';\n \t\tentry->next = NULL;\n \n-\t\tbufptr += len + 20;\n-\t\tsize -= len + 20;\n+\t\tupdate_tree_entry(&desc);\n \n \t\tif (entry->directory) {\n-\t\t\tentry->item.tree = lookup_tree(file_sha1);\n-\t\t\tobj = &entry->item.tree->object;\n+\t\t\tentry->item.tree = lookup_tree(sha1);\n \t\t} else {\n-\t\t\tentry->item.blob = lookup_blob(file_sha1);\n-\t\t\tobj = &entry->item.blob->object;\n+\t\t\tentry->item.blob = lookup_blob(sha1);\n \t\t}\n-\t\tif (obj)\n-\t\t\tn_refs++;\n+\t\tn_refs++;\n \t\t*list_p = entry;\n \t\tlist_p = &entry->next;\n \t}\n@@ -206,7 +206,6 @@ int parse_tree(struct tree *item)\n \t char type[20];\n \t void *buffer;\n \t unsigned long size;\n-\t int ret;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n@@ -219,9 +218,7 @@ int parse_tree(struct tree *item)\n \t\treturn error(\"Object %s not a tree\",\n \t\t\t     sha1_to_hex(item->object.sha1));\n \t}\n-\tret = parse_tree_buffer(item, buffer, size);\n-\tfree(buffer);\n-\treturn ret;\n+\treturn parse_tree_buffer(item, buffer, size);\n }\n \n struct tree *parse_tree_indirect(const unsigned char *sha1)\ndiff --git a/tree.h b/tree.h\nindex 330ab64..066ac5d 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -12,7 +12,7 @@ struct tree_entry_list {\n \tunsigned symlink : 1;\n \tunsigned zeropad : 1;\n \tunsigned int mode;\n-\tchar *name;\n+\tconst char *name;\n \tunion {\n \t\tstruct object *any;\n \t\tstruct tree *tree;\n@@ -22,6 +22,8 @@ struct tree_entry_list {\n \n struct tree {\n \tstruct object object;\n+\tvoid *buffer;\n+\tunsigned long size;\n \tstruct tree_entry_list *entries;\n };\n \n-- \n1.3.3.gcd01d\n"},{"id":"20899","messageId":"Pine.LNX.4.64.0605291216220.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 2/10] Make \"tree_entry\" have a SHA1 instead of a union of object pointers","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:16:46Z","receivedAt":"2006-05-29T19:16:46Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis is preparatory work for further cleanups, where we try to make\ntree_entry look more like the more efficient tree-walk descriptor.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n blame.c             |    4 ++--\n builtin-read-tree.c |    9 +++++----\n builtin-rev-list.c  |    4 ++--\n fsck-objects.c      |    1 +\n http-push.c         |    4 ++--\n object.c            |    2 +-\n revision.c          |    4 ++--\n tree.c              |   25 ++++++++++++++-----------\n tree.h              |    8 ++------\n 9 files changed, 31 insertions(+), 30 deletions(-)\n\ndiff --git a/blame.c b/blame.c\nindex 99ceea8..88bfec2 100644\n--- a/blame.c\n+++ b/blame.c\n@@ -149,7 +149,7 @@ static void free_patch(struct patch *p)\n \tfree(p);\n }\n \n-static int get_blob_sha1_internal(unsigned char *sha1, const char *base,\n+static int get_blob_sha1_internal(const unsigned char *sha1, const char *base,\n \t\t\t\t  int baselen, const char *pathname,\n \t\t\t\t  unsigned mode, int stage);\n \n@@ -178,7 +178,7 @@ static int get_blob_sha1(struct tree *t,\n \treturn 0;\n }\n \n-static int get_blob_sha1_internal(unsigned char *sha1, const char *base,\n+static int get_blob_sha1_internal(const unsigned char *sha1, const char *base,\n \t\t\t\t  int baselen, const char *pathname,\n \t\t\t\t  unsigned mode, int stage)\n {\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 6876f3d..5e513c8 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -161,9 +161,10 @@ #endif\n \t\t\t}\n \n \t\t\tif (posns[i]->directory) {\n+\t\t\t\tstruct tree *tree = lookup_tree(posns[i]->sha1);\n \t\t\t\tany_dirs = 1;\n-\t\t\t\tparse_tree(posns[i]->item.tree);\n-\t\t\t\tsubposns[i] = posns[i]->item.tree->entries;\n+\t\t\t\tparse_tree(tree);\n+\t\t\t\tsubposns[i] = tree->entries;\n \t\t\t\tposns[i] = posns[i]->next;\n \t\t\t\tsrc[i + merge] = &df_conflict_entry;\n \t\t\t\tcontinue;\n@@ -187,7 +188,7 @@ #endif\n \n \t\t\tany_files = 1;\n \n-\t\t\tmemcpy(ce->sha1, posns[i]->item.any->sha1, 20);\n+\t\t\tmemcpy(ce->sha1, posns[i]->sha1, 20);\n \t\t\tsrc[i + merge] = ce;\n \t\t\tsubposns[i] = &df_conflict_list;\n \t\t\tposns[i] = posns[i]->next;\n@@ -783,7 +784,7 @@ static void prime_cache_tree_rec(struct \n \t\t\tcnt++;\n \t\telse {\n \t\t\tstruct cache_tree_sub *sub;\n-\t\t\tstruct tree *subtree = (struct tree *)ent->item.tree;\n+\t\t\tstruct tree *subtree = lookup_tree(ent->sha1);\n \t\t\tif (!subtree->object.parsed)\n \t\t\t\tparse_tree(subtree);\n \t\t\tsub = cache_tree_sub(it, ent->name);\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 72c1549..94f520b 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -133,9 +133,9 @@ static struct object_list **process_tree\n \twhile (entry) {\n \t\tstruct tree_entry_list *next = entry->next;\n \t\tif (entry->directory)\n-\t\t\tp = process_tree(entry->item.tree, p, &me, entry->name);\n+\t\t\tp = process_tree(lookup_tree(entry->sha1), p, &me, entry->name);\n \t\telse\n-\t\t\tp = process_blob(entry->item.blob, p, &me, entry->name);\n+\t\t\tp = process_blob(lookup_blob(entry->sha1), p, &me, entry->name);\n \t\tfree(entry);\n \t\tentry = next;\n \t}\ndiff --git a/fsck-objects.c b/fsck-objects.c\nindex 5e65df4..ed2eb27 100644\n--- a/fsck-objects.c\n+++ b/fsck-objects.c\n@@ -464,6 +464,7 @@ int main(int argc, char **argv)\n {\n \tint i, heads;\n \n+\ttrack_object_refs = 1;\n \tsetup_git_directory();\n \n \tfor (i = 1; i < argc; i++) {\ndiff --git a/http-push.c b/http-push.c\nindex b4327d9..f492a5d 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1733,9 +1733,9 @@ static struct object_list **process_tree\n \twhile (entry) {\n \t\tstruct tree_entry_list *next = entry->next;\n \t\tif (entry->directory)\n-\t\t\tp = process_tree(entry->item.tree, p, &me, entry->name);\n+\t\t\tp = process_tree(lookup_tree(entry->sha1), p, &me, entry->name);\n \t\telse\n-\t\t\tp = process_blob(entry->item.blob, p, &me, entry->name);\n+\t\t\tp = process_blob(lookup_blob(entry->sha1), p, &me, entry->name);\n \t\tfree(entry);\n \t\tentry = next;\n \t}\ndiff --git a/object.c b/object.c\nindex 1a7823c..9adc874 100644\n--- a/object.c\n+++ b/object.c\n@@ -9,7 +9,7 @@ struct object **objs;\n static int nr_objs;\n int obj_allocs;\n \n-int track_object_refs = 1;\n+int track_object_refs = 0;\n \n static int hashtable_index(const unsigned char *sha1)\n {\ndiff --git a/revision.c b/revision.c\nindex 42c077a..8d70a6f 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -68,9 +68,9 @@ void mark_tree_uninteresting(struct tree\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\t\tmark_tree_uninteresting(lookup_tree(entry->sha1));\n \t\telse\n-\t\t\tmark_blob_uninteresting(entry->item.blob);\n+\t\t\tmark_blob_uninteresting(lookup_blob(entry->sha1));\n \t\tfree(entry);\n \t\tentry = next;\n \t}\ndiff --git a/tree.c b/tree.c\nindex 1e76d9c..ba8742c 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -8,7 +8,7 @@ #include <stdlib.h>\n \n const char *tree_type = \"tree\";\n \n-static int read_one_entry(unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)\n+static int read_one_entry(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage)\n {\n \tint len;\n \tunsigned int size;\n@@ -89,7 +89,7 @@ int read_tree_recursive(struct tree *tre\n \t\t\t\t      current->mode, match))\n \t\t\tcontinue;\n \n-\t\tswitch (fn(current->item.any->sha1, base, baselen,\n+\t\tswitch (fn(current->sha1, base, baselen,\n \t\t\t   current->name, current->mode, stage)) {\n \t\tcase 0:\n \t\t\tcontinue;\n@@ -107,7 +107,7 @@ int read_tree_recursive(struct tree *tre\n \t\t\tmemcpy(newbase, base, baselen);\n \t\t\tmemcpy(newbase + baselen, current->name, pathlen);\n \t\t\tnewbase[baselen + pathlen] = '/';\n-\t\t\tretval = read_tree_recursive(current->item.tree,\n+\t\t\tretval = read_tree_recursive(lookup_tree(current->sha1),\n \t\t\t\t\t\t     newbase,\n \t\t\t\t\t\t     baselen + pathlen + 1,\n \t\t\t\t\t\t     stage, match, fn);\n@@ -170,6 +170,7 @@ int parse_tree_buffer(struct tree *item,\n \n \t\tentry = xmalloc(sizeof(struct tree_entry_list));\n \t\tentry->name = path;\n+\t\tentry->sha1 = sha1;\n \t\tentry->mode = mode;\n \t\tentry->directory = S_ISDIR(mode) != 0;\n \t\tentry->executable = (mode & S_IXUSR) != 0;\n@@ -178,12 +179,6 @@ int parse_tree_buffer(struct tree *item,\n \t\tentry->next = NULL;\n \n \t\tupdate_tree_entry(&desc);\n-\n-\t\tif (entry->directory) {\n-\t\t\tentry->item.tree = lookup_tree(sha1);\n-\t\t} else {\n-\t\t\tentry->item.blob = lookup_blob(sha1);\n-\t\t}\n \t\tn_refs++;\n \t\t*list_p = entry;\n \t\tlist_p = &entry->next;\n@@ -193,8 +188,16 @@ int parse_tree_buffer(struct tree *item,\n \t\tstruct tree_entry_list *entry;\n \t\tunsigned i = 0;\n \t\tstruct object_refs *refs = alloc_object_refs(n_refs);\n-\t\tfor (entry = item->entries; entry; entry = entry->next)\n-\t\t\trefs->ref[i++] = entry->item.any;\n+\t\tfor (entry = item->entries; entry; entry = entry->next) {\n+\t\t\tstruct object *obj;\n+\n+\t\t\tif (entry->directory)\n+\t\t\t\tobj = &lookup_tree(entry->sha1)->object;\n+\t\t\telse\n+\t\t\t\tobj = &lookup_blob(entry->sha1)->object;\n+\t\t\trefs->ref[i++] = obj;\n+\t\t}\n+\t\t\t\t\n \t\tset_object_refs(&item->object, refs);\n \t}\n \ndiff --git a/tree.h b/tree.h\nindex 066ac5d..a27bae4 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -13,11 +13,7 @@ struct tree_entry_list {\n \tunsigned zeropad : 1;\n \tunsigned int mode;\n \tconst char *name;\n-\tunion {\n-\t\tstruct object *any;\n-\t\tstruct tree *tree;\n-\t\tstruct blob *blob;\n-\t} item;\n+\tconst unsigned char *sha1;\n };\n \n struct tree {\n@@ -37,7 +33,7 @@ int parse_tree(struct tree *tree);\n struct tree *parse_tree_indirect(const unsigned char *sha1);\n \n #define READ_TREE_RECURSIVE 1\n-typedef int (*read_tree_fn_t)(unsigned char *, const char *, int, const char *, unsigned int, int);\n+typedef int (*read_tree_fn_t)(const unsigned char *, const char *, int, const char *, unsigned int, int);\n \n extern int read_tree_recursive(struct tree *tree,\n \t\t\t       const char *base, int baselen,\n-- \n1.3.3.gcd01d\n"},{"id":"20900","messageId":"Pine.LNX.4.64.0605291216500.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 3/10] Switch \"read_tree_recursive()\" over to tree-walk functionality","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:17:28Z","receivedAt":"2006-05-29T19:17:28Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nDon't use the tree_entry list any more.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n tree.c |   33 ++++++++++++++++++++-------------\n 1 files changed, 20 insertions(+), 13 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex ba8742c..8a7fdd4 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -78,19 +78,26 @@ int read_tree_recursive(struct tree *tre\n \t\t\tint stage, const char **match,\n \t\t\tread_tree_fn_t fn)\n {\n-\tstruct tree_entry_list *list;\n+\tstruct tree_desc desc;\n+\n \tif (parse_tree(tree))\n \t\treturn -1;\n-\tlist = tree->entries;\n-\twhile (list) {\n-\t\tstruct tree_entry_list *current = list;\n-\t\tlist = list->next;\n-\t\tif (!match_tree_entry(base, baselen, current->name,\n-\t\t\t\t      current->mode, match))\n+\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n+\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\n+\t\tif (!match_tree_entry(base, baselen, name, mode, match))\n \t\t\tcontinue;\n \n-\t\tswitch (fn(current->sha1, base, baselen,\n-\t\t\t   current->name, current->mode, stage)) {\n+\t\tswitch (fn(sha1, base, baselen, name, mode, stage)) {\n \t\tcase 0:\n \t\t\tcontinue;\n \t\tcase READ_TREE_RECURSIVE:\n@@ -98,16 +105,16 @@ int read_tree_recursive(struct tree *tre\n \t\tdefault:\n \t\t\treturn -1;\n \t\t}\n-\t\tif (current->directory) {\n+\t\tif (S_ISDIR(mode)) {\n \t\t\tint retval;\n-\t\t\tint pathlen = strlen(current->name);\n+\t\t\tint pathlen = strlen(name);\n \t\t\tchar *newbase;\n \n \t\t\tnewbase = xmalloc(baselen + 1 + pathlen);\n \t\t\tmemcpy(newbase, base, baselen);\n-\t\t\tmemcpy(newbase + baselen, current->name, pathlen);\n+\t\t\tmemcpy(newbase + baselen, name, pathlen);\n \t\t\tnewbase[baselen + pathlen] = '/';\n-\t\t\tretval = read_tree_recursive(lookup_tree(current->sha1),\n+\t\t\tretval = read_tree_recursive(lookup_tree(sha1),\n \t\t\t\t\t\t     newbase,\n \t\t\t\t\t\t     baselen + pathlen + 1,\n \t\t\t\t\t\t     stage, match, fn);\n-- \n1.3.3.gcd01d\n"},{"id":"20901","messageId":"Pine.LNX.4.64.0605291217360.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 4/10] builtin-read-tree.c: avoid tree_entry_list in prime_cache_tree_rec()","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:18:00Z","receivedAt":"2006-05-29T19:18:00Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nUse the raw tree walker instead.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n builtin-read-tree.c |   20 +++++++++++++++-----\n 1 files changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 5e513c8..67492bf 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -9,6 +9,7 @@ #include \"cache.h\"\n \n #include \"object.h\"\n #include \"tree.h\"\n+#include \"tree-walk.h\"\n #include \"cache-tree.h\"\n #include <sys/time.h>\n #include <signal.h>\n@@ -775,19 +776,28 @@ static int read_cache_unmerged(void)\n \n static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)\n {\n-\tstruct tree_entry_list *ent;\n+\tstruct tree_desc desc;\n \tint cnt;\n \n \tmemcpy(it->sha1, tree->object.sha1, 20);\n-\tfor (cnt = 0, ent = tree->entries; ent; ent = ent->next) {\n-\t\tif (!ent->directory)\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n+\tcnt = 0;\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\t\tif (!S_ISDIR(mode))\n \t\t\tcnt++;\n \t\telse {\n \t\t\tstruct cache_tree_sub *sub;\n-\t\t\tstruct tree *subtree = lookup_tree(ent->sha1);\n+\t\t\tstruct tree *subtree = lookup_tree(sha1);\n \t\t\tif (!subtree->object.parsed)\n \t\t\t\tparse_tree(subtree);\n-\t\t\tsub = cache_tree_sub(it, ent->name);\n+\t\t\tsub = cache_tree_sub(it, name);\n \t\t\tsub->cache_tree = cache_tree();\n \t\t\tprime_cache_tree_rec(sub->cache_tree, subtree);\n \t\t\tcnt += sub->cache_tree->entry_count;\n-- \n1.3.3.gcd01d\n"},{"id":"20902","messageId":"Pine.LNX.4.64.0605291218060.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 5/10] Remove \"tree->entries\" tree-entry list from tree parser","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:18:33Z","receivedAt":"2006-05-29T19:18:33Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nInstead, just use the tree buffer directly, and use the tree-walk\ninfrastructure to walk the buffers instead of the tree-entry list.\n\nThe tree-entry list is inefficient, and generates tons of small\nallocations for no good reason. The tree-walk infrastructure is\ngenerally no harder to use than following a linked list, and allows\nus to do most tree parsing in-place.\n\nSome programs still use the old tree-entry lists, and are a bit\npainful to convert without major surgery. For them we have a helper\nfunction that creates a temporary tree-entry list on demand.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n builtin-ls-tree.c   |    2 +\n builtin-read-tree.c |    4 +--\n builtin-rev-list.c  |   26 ++++++++++------\n fetch.c             |   16 +++++++---\n fsck-objects.c      |    7 +++-\n http-push.c         |   30 +++++++++++++------\n revision.c          |    3 +-\n tree.c              |   81 ++++++++++++++++++++++++++++++++++++---------------\n tree.h              |    4 ++-\n 9 files changed, 116 insertions(+), 57 deletions(-)\n\ndiff --git a/builtin-ls-tree.c b/builtin-ls-tree.c\nindex 48385d5..b8d0d88 100644\n--- a/builtin-ls-tree.c\n+++ b/builtin-ls-tree.c\n@@ -53,7 +53,7 @@ static int show_recursive(const char *ba\n \t}\n }\n \n-static int show_tree(unsigned char *sha1, const char *base, int baselen,\n+static int show_tree(const unsigned char *sha1, const char *base, int baselen,\n \t\t     const char *pathname, unsigned mode, int stage)\n {\n \tint retval = 0;\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 67492bf..480e6ed 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -165,7 +165,7 @@ #endif\n \t\t\t\tstruct tree *tree = lookup_tree(posns[i]->sha1);\n \t\t\t\tany_dirs = 1;\n \t\t\t\tparse_tree(tree);\n-\t\t\t\tsubposns[i] = tree->entries;\n+\t\t\t\tsubposns[i] = create_tree_entry_list(tree);\n \t\t\t\tposns[i] = posns[i]->next;\n \t\t\t\tsrc[i + merge] = &df_conflict_entry;\n \t\t\t\tcontinue;\n@@ -370,7 +370,7 @@ static int unpack_trees(merge_fn_t fn)\n \tif (len) {\n \t\tposns = xmalloc(len * sizeof(struct tree_entry_list *));\n \t\tfor (i = 0; i < len; i++) {\n-\t\t\tposns[i] = ((struct tree *) posn->item)->entries;\n+\t\t\tposns[i] = create_tree_entry_list((struct tree *) posn->item);\n \t\t\tposn = posn->next;\n \t\t}\n \t\tif (unpack_trees_rec(posns, len, \"\", fn, &indpos))\ndiff --git a/builtin-rev-list.c b/builtin-rev-list.c\nindex 94f520b..6e2b898 100644\n--- a/builtin-rev-list.c\n+++ b/builtin-rev-list.c\n@@ -113,7 +113,7 @@ static struct object_list **process_tree\n \t\t\t\t\t const char *name)\n {\n \tstruct object *obj = &tree->object;\n-\tstruct tree_entry_list *entry;\n+\tstruct tree_desc desc;\n \tstruct name_path me;\n \n \tif (!revs.tree_objects)\n@@ -128,16 +128,22 @@ static struct object_list **process_tree\n \tme.up = path;\n \tme.elem = name;\n \tme.elem_len = strlen(name);\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\tp = process_tree(lookup_tree(entry->sha1), p, &me, entry->name);\n+\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n+\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\n+\t\tif (S_ISDIR(mode))\n+\t\t\tp = process_tree(lookup_tree(sha1), p, &me, name);\n \t\telse\n-\t\t\tp = process_blob(lookup_blob(entry->sha1), p, &me, entry->name);\n-\t\tfree(entry);\n-\t\tentry = next;\n+\t\t\tp = process_blob(lookup_blob(sha1), p, &me, name);\n \t}\n \tfree(tree->buffer);\n \ttree->buffer = NULL;\ndiff --git a/fetch.c b/fetch.c\nindex f7f8902..d9fe41f 100644\n--- a/fetch.c\n+++ b/fetch.c\n@@ -41,16 +41,22 @@ static int process_tree(struct tree *tre\n \tif (parse_tree(tree))\n \t\treturn -1;\n \n-\tentry = tree->entries;\n-\ttree->entries = NULL;\n+\tentry = create_tree_entry_list(tree);\n \twhile (entry) {\n \t\tstruct tree_entry_list *next = entry->next;\n-\t\tif (process(entry->item.any))\n-\t\t\treturn -1;\n-\t\tfree(entry->name);\n+\n+\t\tif (entry->directory) {\n+\t\t\tstruct tree *tree = lookup_tree(entry->sha1);\n+\t\t\tprocess_tree(tree);\n+\t\t} else {\n+\t\t\tstruct blob *blob = lookup_blob(entry->sha1);\n+\t\t\tprocess(&blob->object);\n+\t\t}\n \t\tfree(entry);\n \t\tentry = next;\n \t}\n+\tfree(tree->buffer);\n+\ttree->buffer = NULL;\n \treturn 0;\n }\n \ndiff --git a/fsck-objects.c b/fsck-objects.c\nindex ed2eb27..42778e8 100644\n--- a/fsck-objects.c\n+++ b/fsck-objects.c\n@@ -11,6 +11,7 @@ #include \"pack.h\"\n #include \"cache-tree.h\"\n \n #define REACHABLE 0x0001\n+#define SEEN      0x0002\n \n static int show_root = 0;\n static int show_tags = 0;\n@@ -161,7 +162,7 @@ static int fsck_tree(struct tree *item)\n \tstruct tree_entry_list *entry, *last;\n \n \tlast = NULL;\n-\tfor (entry = item->entries; entry; entry = entry->next) {\n+\tfor (entry = create_tree_entry_list(item); entry; entry = entry->next) {\n \t\tif (strchr(entry->name, '/'))\n \t\t\thas_full_path = 1;\n \t\thas_zero_pad |= entry->zeropad;\n@@ -205,7 +206,6 @@ static int fsck_tree(struct tree *item)\n \t}\n \tif (last)\n \t\tfree(last);\n-\titem->entries = NULL;\n \tfree(item->buffer);\n \titem->buffer = NULL;\n \n@@ -277,6 +277,9 @@ static int fsck_sha1(unsigned char *sha1\n \tstruct object *obj = parse_object(sha1);\n \tif (!obj)\n \t\treturn error(\"%s: object not found\", sha1_to_hex(sha1));\n+\tif (obj->flags & SEEN)\n+\t\treturn 0;\n+\tobj->flags |= SEEN;\n \tif (obj->type == blob_type)\n \t\treturn 0;\n \tif (obj->type == tree_type)\ndiff --git a/http-push.c b/http-push.c\nindex f492a5d..72ad89c 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1704,6 +1704,7 @@ static struct object_list **process_blob\n \t\treturn p;\n \n \tobj->flags |= SEEN;\n+\tname = strdup(name);\n \treturn add_object(obj, p, path, name);\n }\n \n@@ -1713,7 +1714,7 @@ static struct object_list **process_tree\n \t\t\t\t\t const char *name)\n {\n \tstruct object *obj = &tree->object;\n-\tstruct tree_entry_list *entry;\n+\tstruct tree_desc desc;\n \tstruct name_path me;\n \n \tobj->flags |= LOCAL;\n@@ -1724,21 +1725,30 @@ static struct object_list **process_tree\n \t\tdie(\"bad tree object %s\", sha1_to_hex(obj->sha1));\n \n \tobj->flags |= SEEN;\n+\tname = strdup(name);\n \tp = add_object(obj, p, NULL, name);\n \tme.up = path;\n \tme.elem = name;\n \tme.elem_len = strlen(name);\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\tp = process_tree(lookup_tree(entry->sha1), p, &me, entry->name);\n+\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n+\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\n+\t\tif (S_ISDIR(mode))\n+\t\t\tp = process_tree(lookup_tree(sha1), p, &me, name);\n \t\telse\n-\t\t\tp = process_blob(lookup_blob(entry->sha1), p, &me, entry->name);\n-\t\tfree(entry);\n-\t\tentry = next;\n+\t\t\tp = process_blob(lookup_blob(sha1), p, &me, name);\n \t}\n+\tfree(tree->buffer);\n+\ttree->buffer = NULL;\n \treturn p;\n }\n \ndiff --git a/revision.c b/revision.c\nindex 8d70a6f..c51ea83 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -63,8 +63,7 @@ void mark_tree_uninteresting(struct tree\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+\tentry = create_tree_entry_list(tree);\n \twhile (entry) {\n \t\tstruct tree_entry_list *next = entry->next;\n \t\tif (entry->directory)\ndiff --git a/tree.c b/tree.c\nindex 8a7fdd4..db6e59f 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -151,22 +151,65 @@ struct tree *lookup_tree(const unsigned \n \treturn (struct tree *) obj;\n }\n \n-int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n+static int track_tree_refs(struct tree *item)\n {\n+\tint n_refs = 0, i;\n+\tstruct object_refs *refs;\n \tstruct tree_desc desc;\n-\tstruct tree_entry_list **list_p;\n-\tint n_refs = 0;\n \n+\t/* Count how many entries there are.. */\n+\tdesc.buf = item->buffer;\n+\tdesc.size = item->size;\n+\twhile (desc.size) {\n+\t\tn_refs++;\n+\t\tupdate_tree_entry(&desc);\n+\t}\n+\n+\t/* Allocate object refs and walk it again.. */\n+\ti = 0;\n+\trefs = alloc_object_refs(n_refs);\n+\tdesc.buf = item->buffer;\n+\tdesc.size = item->size;\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n+\t\tstruct object *obj;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\t\tif (S_ISDIR(mode))\n+\t\t\tobj = &lookup_tree(sha1)->object;\n+\t\telse\n+\t\t\tobj = &lookup_blob(sha1)->object;\n+\t\trefs->ref[i++] = obj;\n+\t}\n+\tset_object_refs(&item->object, refs);\n+\treturn 0;\n+}\n+\n+int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n+{\n \tif (item->object.parsed)\n \t\treturn 0;\n \titem->object.parsed = 1;\n \titem->buffer = buffer;\n \titem->size = size;\n \n-\tdesc.buf = buffer;\n-\tdesc.size = size;\n+\tif (track_object_refs)\n+\t\ttrack_tree_refs(item);\n+\treturn 0;\n+}\n+\n+struct tree_entry_list *create_tree_entry_list(struct tree *tree)\n+{\n+\tstruct tree_desc desc;\n+\tstruct tree_entry_list *ret = NULL;\n+\tstruct tree_entry_list **list_p = &ret;\n+\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n \n-\tlist_p = &item->entries;\n \twhile (desc.size) {\n \t\tunsigned mode;\n \t\tconst char *path;\n@@ -186,29 +229,19 @@ int parse_tree_buffer(struct tree *item,\n \t\tentry->next = NULL;\n \n \t\tupdate_tree_entry(&desc);\n-\t\tn_refs++;\n \t\t*list_p = entry;\n \t\tlist_p = &entry->next;\n \t}\n+\treturn ret;\n+}\n \n-\tif (track_object_refs) {\n-\t\tstruct tree_entry_list *entry;\n-\t\tunsigned i = 0;\n-\t\tstruct object_refs *refs = alloc_object_refs(n_refs);\n-\t\tfor (entry = item->entries; entry; entry = entry->next) {\n-\t\t\tstruct object *obj;\n-\n-\t\t\tif (entry->directory)\n-\t\t\t\tobj = &lookup_tree(entry->sha1)->object;\n-\t\t\telse\n-\t\t\t\tobj = &lookup_blob(entry->sha1)->object;\n-\t\t\trefs->ref[i++] = obj;\n-\t\t}\n-\t\t\t\t\n-\t\tset_object_refs(&item->object, refs);\n+void free_tree_entry_list(struct tree_entry_list *list)\n+{\n+\twhile (list) {\n+\t\tstruct tree_entry_list *next = list->next;\n+\t\tfree(list);\n+\t\tlist = next;\n \t}\n-\n-\treturn 0;\n }\n \n int parse_tree(struct tree *item)\ndiff --git a/tree.h b/tree.h\nindex a27bae4..c7b5248 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -20,9 +20,11 @@ struct tree {\n \tstruct object object;\n \tvoid *buffer;\n \tunsigned long size;\n-\tstruct tree_entry_list *entries;\n };\n \n+struct tree_entry_list *create_tree_entry_list(struct tree *);\n+void free_tree_entry_list(struct tree_entry_list *);\n+\n struct tree *lookup_tree(const unsigned char *sha1);\n \n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);\n-- \n1.3.3.gcd01d\n"},{"id":"20903","messageId":"Pine.LNX.4.64.0605291218390.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 6/10] fsck-objects: avoid unnecessary tree_entry_list usage","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:19:02Z","receivedAt":"2006-05-29T19:19:02Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nPrime example of where the raw tree parser is easier for everybody.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n fsck-objects.c |   55 +++++++++++++++++++++++++++++++++++--------------------\n 1 files changed, 35 insertions(+), 20 deletions(-)\n\ndiff --git a/fsck-objects.c b/fsck-objects.c\nindex 42778e8..a9680dc 100644\n--- a/fsck-objects.c\n+++ b/fsck-objects.c\n@@ -9,6 +9,7 @@ #include \"tag.h\"\n #include \"refs.h\"\n #include \"pack.h\"\n #include \"cache-tree.h\"\n+#include \"tree-walk.h\"\n \n #define REACHABLE 0x0001\n #define SEEN      0x0002\n@@ -116,15 +117,15 @@ static void check_connectivity(void)\n #define TREE_UNORDERED (-1)\n #define TREE_HAS_DUPS  (-2)\n \n-static int verify_ordered(struct tree_entry_list *a, struct tree_entry_list *b)\n+static int verify_ordered(unsigned mode1, const char *name1, unsigned mode2, const char *name2)\n {\n-\tint len1 = strlen(a->name);\n-\tint len2 = strlen(b->name);\n+\tint len1 = strlen(name1);\n+\tint len2 = strlen(name2);\n \tint len = len1 < len2 ? len1 : len2;\n \tunsigned char c1, c2;\n \tint cmp;\n \n-\tcmp = memcmp(a->name, b->name, len);\n+\tcmp = memcmp(name1, name2, len);\n \tif (cmp < 0)\n \t\treturn 0;\n \tif (cmp > 0)\n@@ -135,8 +136,8 @@ static int verify_ordered(struct tree_en\n \t * Now we need to order the next one, but turn\n \t * a '\\0' into a '/' for a directory entry.\n \t */\n-\tc1 = a->name[len];\n-\tc2 = b->name[len];\n+\tc1 = name1[len];\n+\tc2 = name2[len];\n \tif (!c1 && !c2)\n \t\t/*\n \t\t * git-write-tree used to write out a nonsense tree that has\n@@ -144,9 +145,9 @@ static int verify_ordered(struct tree_en\n \t\t * sure we do not have duplicate entries.\n \t\t */\n \t\treturn TREE_HAS_DUPS;\n-\tif (!c1 && a->directory)\n+\tif (!c1 && S_ISDIR(mode1))\n \t\tc1 = '/';\n-\tif (!c2 && b->directory)\n+\tif (!c2 && S_ISDIR(mode2))\n \t\tc2 = '/';\n \treturn c1 < c2 ? 0 : TREE_UNORDERED;\n }\n@@ -159,15 +160,30 @@ static int fsck_tree(struct tree *item)\n \tint has_bad_modes = 0;\n \tint has_dup_entries = 0;\n \tint not_properly_sorted = 0;\n-\tstruct tree_entry_list *entry, *last;\n+\tstruct tree_desc desc;\n+\tunsigned o_mode;\n+\tconst char *o_name;\n+\tconst unsigned char *o_sha1;\n \n-\tlast = NULL;\n-\tfor (entry = create_tree_entry_list(item); entry; entry = entry->next) {\n-\t\tif (strchr(entry->name, '/'))\n+\tdesc.buf = item->buffer;\n+\tdesc.size = item->size;\n+\n+\to_mode = 0;\n+\to_name = NULL;\n+\to_sha1 = NULL;\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\n+\t\tif (strchr(name, '/'))\n \t\t\thas_full_path = 1;\n-\t\thas_zero_pad |= entry->zeropad;\n+\t\thas_zero_pad |= *(char *)desc.buf = '0';\n+\t\tupdate_tree_entry(&desc);\n \n-\t\tswitch (entry->mode) {\n+\t\tswitch (mode) {\n \t\t/*\n \t\t * Standard modes.. \n \t\t */\n@@ -188,8 +204,8 @@ static int fsck_tree(struct tree *item)\n \t\t\thas_bad_modes = 1;\n \t\t}\n \n-\t\tif (last) {\n-\t\t\tswitch (verify_ordered(last, entry)) {\n+\t\tif (o_name) {\n+\t\t\tswitch (verify_ordered(o_mode, o_name, mode, name)) {\n \t\t\tcase TREE_UNORDERED:\n \t\t\t\tnot_properly_sorted = 1;\n \t\t\t\tbreak;\n@@ -199,13 +215,12 @@ static int fsck_tree(struct tree *item)\n \t\t\tdefault:\n \t\t\t\tbreak;\n \t\t\t}\n-\t\t\tfree(last);\n \t\t}\n \n-\t\tlast = entry;\n+\t\to_mode = mode;\n+\t\to_name = name;\n+\t\to_sha1 = sha1;\n \t}\n-\tif (last)\n-\t\tfree(last);\n \tfree(item->buffer);\n \titem->buffer = NULL;\n \n-- \n1.3.3.gcd01d\n"},{"id":"20904","messageId":"Pine.LNX.4.64.0605291219120.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 7/10] Remove unused \"zeropad\" entry from tree_list_entry","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:19:37Z","receivedAt":"2006-05-29T19:19:37Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThat was a hack, only needed because 'git fsck-objects' didn't look at\nthe raw tree format.  Now that fsck traverses the tree itself, we can\ndrop it.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n tree.c |    3 +--\n tree.h |    1 -\n 2 files changed, 1 insertions(+), 3 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex db6e59f..47318ef 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -217,6 +217,7 @@ struct tree_entry_list *create_tree_entr\n \t\tstruct tree_entry_list *entry;\n \n \t\tsha1 = tree_entry_extract(&desc, &path, &mode);\n+\t\tupdate_tree_entry(&desc);\n \n \t\tentry = xmalloc(sizeof(struct tree_entry_list));\n \t\tentry->name = path;\n@@ -225,10 +226,8 @@ struct tree_entry_list *create_tree_entr\n \t\tentry->directory = S_ISDIR(mode) != 0;\n \t\tentry->executable = (mode & S_IXUSR) != 0;\n \t\tentry->symlink = S_ISLNK(mode) != 0;\n-\t\tentry->zeropad = *(const char *)(desc.buf) == '0';\n \t\tentry->next = NULL;\n \n-\t\tupdate_tree_entry(&desc);\n \t\t*list_p = entry;\n \t\tlist_p = &entry->next;\n \t}\ndiff --git a/tree.h b/tree.h\nindex c7b5248..6a87546 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -10,7 +10,6 @@ struct tree_entry_list {\n \tunsigned directory : 1;\n \tunsigned executable : 1;\n \tunsigned symlink : 1;\n-\tunsigned zeropad : 1;\n \tunsigned int mode;\n \tconst char *name;\n \tconst unsigned char *sha1;\n-- \n1.3.3.gcd01d\n"},{"id":"20905","messageId":"Pine.LNX.4.64.0605291219490.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 8/10] Convert \"mark_tree_uninteresting()\" to raw tree walker","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:20:14Z","receivedAt":"2006-05-29T19:20:14Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nNot very many users to go..\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n revision.c |   31 ++++++++++++++++++++++---------\n 1 files changed, 22 insertions(+), 9 deletions(-)\n\ndiff --git a/revision.c b/revision.c\nindex c51ea83..8e93e40 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -53,8 +53,8 @@ static void mark_blob_uninteresting(stru\n \n void mark_tree_uninteresting(struct tree *tree)\n {\n+\tstruct tree_desc desc;\n \tstruct object *obj = &tree->object;\n-\tstruct tree_entry_list *entry;\n \n \tif (obj->flags & UNINTERESTING)\n \t\treturn;\n@@ -63,16 +63,29 @@ void mark_tree_uninteresting(struct tree\n \t\treturn;\n \tif (parse_tree(tree) < 0)\n \t\tdie(\"bad tree %s\", sha1_to_hex(obj->sha1));\n-\tentry = create_tree_entry_list(tree);\n-\twhile (entry) {\n-\t\tstruct tree_entry_list *next = entry->next;\n-\t\tif (entry->directory)\n-\t\t\tmark_tree_uninteresting(lookup_tree(entry->sha1));\n+\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\n+\t\tif (S_ISDIR(mode))\n+\t\t\tmark_tree_uninteresting(lookup_tree(sha1));\n \t\telse\n-\t\t\tmark_blob_uninteresting(lookup_blob(entry->sha1));\n-\t\tfree(entry);\n-\t\tentry = next;\n+\t\t\tmark_blob_uninteresting(lookup_blob(sha1));\n \t}\n+\n+\t/*\n+\t * We don't care about the tree any more\n+\t * after it has been marked uninteresting.\n+\t */\n+\tfree(tree->buffer);\n+\ttree->buffer = NULL;\n }\n \n void mark_parents_uninteresting(struct commit *commit)\n-- \n1.3.3.gcd01d\n"},{"id":"20906","messageId":"Pine.LNX.4.64.0605291220240.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 9/10] Convert fetch.c: process_tree() to raw tree walker","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:20:48Z","receivedAt":"2006-05-29T19:20:48Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThis leaves only the horrid code in builtin-read-tree.c using the old\ninterface. Some day I will gather the strength to tackle that one too.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n fetch.c |   24 +++++++++++++++---------\n 1 files changed, 15 insertions(+), 9 deletions(-)\n\ndiff --git a/fetch.c b/fetch.c\nindex d9fe41f..976a5a4 100644\n--- a/fetch.c\n+++ b/fetch.c\n@@ -3,6 +3,7 @@ #include \"fetch.h\"\n #include \"cache.h\"\n #include \"commit.h\"\n #include \"tree.h\"\n+#include \"tree-walk.h\"\n #include \"tag.h\"\n #include \"blob.h\"\n #include \"refs.h\"\n@@ -36,27 +37,32 @@ static int process(struct object *obj);\n \n static int process_tree(struct tree *tree)\n {\n-\tstruct tree_entry_list *entry;\n+\tstruct tree_desc desc;\n \n \tif (parse_tree(tree))\n \t\treturn -1;\n \n-\tentry = create_tree_entry_list(tree);\n-\twhile (entry) {\n-\t\tstruct tree_entry_list *next = entry->next;\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *name;\n+\t\tconst unsigned char *sha1;\n \n-\t\tif (entry->directory) {\n-\t\t\tstruct tree *tree = lookup_tree(entry->sha1);\n+\t\tsha1 = tree_entry_extract(&desc, &name, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\n+\t\tif (S_ISDIR(mode)) {\n+\t\t\tstruct tree *tree = lookup_tree(sha1);\n \t\t\tprocess_tree(tree);\n \t\t} else {\n-\t\t\tstruct blob *blob = lookup_blob(entry->sha1);\n+\t\t\tstruct blob *blob = lookup_blob(sha1);\n \t\t\tprocess(&blob->object);\n \t\t}\n-\t\tfree(entry);\n-\t\tentry = next;\n \t}\n \tfree(tree->buffer);\n \ttree->buffer = NULL;\n+\ttree->size = 0;\n \treturn 0;\n }\n \n-- \n1.3.3.gcd01d\n"},{"id":"20907","messageId":"Pine.LNX.4.64.0605291220550.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"[PATCH 10/10] Remove last vestiges of generic tree_entry_list","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:21:28Z","receivedAt":"2006-05-29T19:21:28Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\nThe old tree_entry_list is dead, long live the unified single tree\nparser.\n\nYes, we now still have a compatibility function to create a bogus\ntree_entry_list in builtin-read-tree.c, but that is now entirely local\nto that very messy piece of code.\n\nI'd love to clean read-tree.c up too, but I'm too scared right now, so\nthe best I can do is to just contain the damage, and try to make sure\nthat no new users of the tree_entry_list sprout up by not having it as\nan exported interface any more.\n\nSigned-off-by: Linus Torvalds <torvalds@osdl.org>\n---\n builtin-read-tree.c |   43 +++++++++++++++++++++++++++++++++++++++++++\n tree.c              |   42 ------------------------------------------\n tree.h              |   13 -------------\n 3 files changed, 43 insertions(+), 55 deletions(-)\n\ndiff --git a/builtin-read-tree.c b/builtin-read-tree.c\nindex 480e6ed..b413e91 100644\n--- a/builtin-read-tree.c\n+++ b/builtin-read-tree.c\n@@ -33,6 +33,16 @@ static struct object_list *trees = NULL;\n static struct cache_entry df_conflict_entry = { \n };\n \n+struct tree_entry_list {\n+\tstruct tree_entry_list *next;\n+\tunsigned directory : 1;\n+\tunsigned executable : 1;\n+\tunsigned symlink : 1;\n+\tunsigned int mode;\n+\tconst char *name;\n+\tconst unsigned char *sha1;\n+};\n+\n static struct tree_entry_list df_conflict_list = {\n \t.name = NULL,\n \t.next = &df_conflict_list\n@@ -40,6 +50,39 @@ static struct tree_entry_list df_conflic\n \n typedef int (*merge_fn_t)(struct cache_entry **src);\n \n+static struct tree_entry_list *create_tree_entry_list(struct tree *tree)\n+{\n+\tstruct tree_desc desc;\n+\tstruct tree_entry_list *ret = NULL;\n+\tstruct tree_entry_list **list_p = &ret;\n+\n+\tdesc.buf = tree->buffer;\n+\tdesc.size = tree->size;\n+\n+\twhile (desc.size) {\n+\t\tunsigned mode;\n+\t\tconst char *path;\n+\t\tconst unsigned char *sha1;\n+\t\tstruct tree_entry_list *entry;\n+\n+\t\tsha1 = tree_entry_extract(&desc, &path, &mode);\n+\t\tupdate_tree_entry(&desc);\n+\n+\t\tentry = xmalloc(sizeof(struct tree_entry_list));\n+\t\tentry->name = path;\n+\t\tentry->sha1 = sha1;\n+\t\tentry->mode = mode;\n+\t\tentry->directory = S_ISDIR(mode) != 0;\n+\t\tentry->executable = (mode & S_IXUSR) != 0;\n+\t\tentry->symlink = S_ISLNK(mode) != 0;\n+\t\tentry->next = NULL;\n+\n+\t\t*list_p = entry;\n+\t\tlist_p = &entry->next;\n+\t}\n+\treturn ret;\n+}\n+\n static int entcmp(const char *name1, int dir1, const char *name2, int dir2)\n {\n \tint len1 = strlen(name1);\ndiff --git a/tree.c b/tree.c\nindex 47318ef..fb18724 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -201,48 +201,6 @@ int parse_tree_buffer(struct tree *item,\n \treturn 0;\n }\n \n-struct tree_entry_list *create_tree_entry_list(struct tree *tree)\n-{\n-\tstruct tree_desc desc;\n-\tstruct tree_entry_list *ret = NULL;\n-\tstruct tree_entry_list **list_p = &ret;\n-\n-\tdesc.buf = tree->buffer;\n-\tdesc.size = tree->size;\n-\n-\twhile (desc.size) {\n-\t\tunsigned mode;\n-\t\tconst char *path;\n-\t\tconst unsigned char *sha1;\n-\t\tstruct tree_entry_list *entry;\n-\n-\t\tsha1 = tree_entry_extract(&desc, &path, &mode);\n-\t\tupdate_tree_entry(&desc);\n-\n-\t\tentry = xmalloc(sizeof(struct tree_entry_list));\n-\t\tentry->name = path;\n-\t\tentry->sha1 = sha1;\n-\t\tentry->mode = mode;\n-\t\tentry->directory = S_ISDIR(mode) != 0;\n-\t\tentry->executable = (mode & S_IXUSR) != 0;\n-\t\tentry->symlink = S_ISLNK(mode) != 0;\n-\t\tentry->next = NULL;\n-\n-\t\t*list_p = entry;\n-\t\tlist_p = &entry->next;\n-\t}\n-\treturn ret;\n-}\n-\n-void free_tree_entry_list(struct tree_entry_list *list)\n-{\n-\twhile (list) {\n-\t\tstruct tree_entry_list *next = list->next;\n-\t\tfree(list);\n-\t\tlist = next;\n-\t}\n-}\n-\n int parse_tree(struct tree *item)\n {\n \t char type[20];\ndiff --git a/tree.h b/tree.h\nindex 6a87546..dd25c53 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -5,25 +5,12 @@ #include \"object.h\"\n \n extern const char *tree_type;\n \n-struct tree_entry_list {\n-\tstruct tree_entry_list *next;\n-\tunsigned directory : 1;\n-\tunsigned executable : 1;\n-\tunsigned symlink : 1;\n-\tunsigned int mode;\n-\tconst char *name;\n-\tconst unsigned char *sha1;\n-};\n-\n struct tree {\n \tstruct object object;\n \tvoid *buffer;\n \tunsigned long size;\n };\n \n-struct tree_entry_list *create_tree_entry_list(struct tree *);\n-void free_tree_entry_list(struct tree_entry_list *);\n-\n struct tree *lookup_tree(const unsigned char *sha1);\n \n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);\n-- \n1.3.3.gcd01d\n"},{"id":"20908","messageId":"Pine.LNX.4.64.0605291226250.5623@g5.osdl.org","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291218390.5623@g5.osdl.org","subject":"Re: [PATCH 6/10] fsck-objects: avoid unnecessary tree_entry_list usage","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-29T19:29:44Z","receivedAt":"2006-05-29T19:29:44Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 29 May 2006, Linus Torvalds wrote:\n> -\t\thas_zero_pad |= entry->zeropad;\n> +\t\thas_zero_pad |= *(char *)desc.buf = '0';\n\nAieee.\n\nI fixed that once in my tree already, and then broke it again when \nre-doing the series with cherry-picking but didn't notice, because the \ntests don't pick up the totally bogus warnings that it causes.\n\nThat \"= '0'\" should obviously be \"== '0'\"\n\n\t\tLinus\n"},{"id":"20932","messageId":"7virno79a7.fsf@assigned-by-dhcp.cox.net","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291145360.5623@g5.osdl.org","subject":"Re: [PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-29T22:31:28Z","receivedAt":"2006-05-29T22:31:28Z","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> Ok, this is largely the same series as the previous 1..4 patches, but \n> rebased on top of the current master tree because the cache-tree patches \n> added some tree_entry_list walkers (which accounts for one extra patch in \n> the series, and some trivial merge fixups).\n>\n> Two new patches then clean up fsck-objects, which really didn't want the \n> old tree_entry_list at all (and had added some hacks to the list entry \n> just because fsck actually needed to check the raw data).\n>\n> Another two new patches convert the last remnant of tree_entry_list in \n> revision.c and fetch.c respectively to the new world order.\n>\n> And the final patch then moves the \"tree_entry_list\" crud into the only \n> remaining user, namely builtin-read-tree.c. That file is pretty messy and \n> hard to convert, and I don't want to touch it right now, so I left it with \n> the nasty compatibility functions. But now that's at least well-contained.\n>\n> I think the series is all good, and should replace the old one in \"next\" \n> (and cook there for a while just to make sure it's ok).\n\nSorry for having you have done this -- last night I've merged\nthe series without rebasing and have the result in \"next\".  I'll\ncompare to see if you have spotted my mismerges there tonight.\n\nThis reminds me of one issue.\n\n        From: Junio C Hamano <junkio@cox.net>\n        Subject: Necessity of \"evil\" merge and topic branches\n        Cc: git@vger.kernel.org\n        Date: Wed, 17 May 2006 23:25:55 -0700\n        Message-ID: <7vy7wz6e8c.fsf@assigned-by-dhcp.cox.net>\n\nI have such an evil-merge branch merged in \"next\" to deal with\nnecessarily adjustments; it is 0a2586c, which is the tip of its\nown branch.  I was hoping this way I can merge it in to \"master\"\nwhen I want to pull your yesterday's series.\n"},{"id":"293891","messageId":"Pine.LNX.4.64.0605291739430.5623@g5.osdl.org","threadId":"4343","inReplyTo":"7virno79a7.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-30T00:42:42Z","receivedAt":"2006-05-30T00:42:42Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 29 May 2006, Junio C Hamano wrote:\n> \n> Sorry for having you have done this -- last night I've merged\n> the series without rebasing and have the result in \"next\".  I'll\n> compare to see if you have spotted my mismerges there tonight.\n\nIt was interesting. I cleaned up the series and switched the order of some \ncommits in my tree by doing first a \"git rebase\" and then cherry-picking \nthem into another branch, and using \"git commit --amend\" to fix up some of \nthe things I had missed.\n\nPretty powerful, although at one point I was wondering about having a \"git \nrebase\" that could switch commits around or drop unwanted ones (ie let the \nuser edit the cherry-picking list before the actual rebase).\n\n"},{"id":"20949","messageId":"7vmzd05i25.fsf@assigned-by-dhcp.cox.net","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605291739430.5623@g5.osdl.org","subject":"Re: [PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-30T03:04:50Z","receivedAt":"2006-05-30T03:04:50Z","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 Mon, 29 May 2006, Junio C Hamano wrote:\n>> \n>> Sorry for having you have done this -- last night I've merged\n>> the series without rebasing and have the result in \"next\".  I'll\n>> compare to see if you have spotted my mismerges there tonight.\n>\n> It was interesting. I cleaned up the series and switched the order of some \n> commits in my tree by doing first a \"git rebase\" and then cherry-picking \n> them into another branch, and using \"git commit --amend\" to fix up some of \n> the things I had missed.\n\nI just did this (readers on the list needs to disect \"next\" if\nthey are interested to reproduce this, since I do not publish\nindividual topic heads, but each of the merge commits on \"next\"\ntells which topics are merged, so that should be trivial):\n\n\t$ git checkout -b lt/tree-2 master\n        $ apply your 10-patch series\n\t$ git show-branch lt/tree lt/tree-2 jc/lt-tree-n-cache-tree next\n\nYour yesterday's series is on lt/tree, and jc/lt-tree-n-cache-tree\nis my \"evil merge\" branch to adjust it to the cache-tree that I had\nin \"next\".  It's tip has cache-tree and lt/tree merged, so\nit should match the early parts of today's 10-patch series.  I\nused show-branch to find that lt/tree-2~5 is the one to match\nyesterday's series:\n\n\t$ git diff --name-only lt/tree~4..lt/tree |\n\t  xargs git diff lt/tree-2~5 jc/lt-tree-n-cache-tree --\n\nThis shows only cosmetic differences, which is good.\n\n> Pretty powerful, although at one point I was wondering about having a \"git \n> rebase\" that could switch commits around or drop unwanted ones (ie let the \n> user edit the cherry-picking list before the actual rebase).\n\nI think true power users would just do the last two lines of\ngit-rebase.sh by hand in two steps.  By stashing away the\nformat-patch output, and using git-am interactively, you can\neasily drop unwanted ones, and then re-run git-am on the same\nformat-patch output to apply the ones you dropped on the first\nrun practically amounts to reordering the patches ;-).\n"},{"id":"20950","messageId":"Pine.LNX.4.64.0605292112530.5623@g5.osdl.org","threadId":"4343","inReplyTo":"7vmzd05i25.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Linus Torvalds","fromEmail":"torvalds@osdl.org","sentAt":"2006-05-30T04:17:06Z","receivedAt":"2006-05-30T04:17:06Z","isPatch":true,"sender":{"key":"torvalds@linux-foundation.org","avatar":"https://avatars.githubusercontent.com/u/1024025?v=4"},"body":"\n\nOn Mon, 29 May 2006, Junio C Hamano wrote:\n>\n> > Pretty powerful, although at one point I was wondering about having a \"git \n> > rebase\" that could switch commits around or drop unwanted ones (ie let the \n> > user edit the cherry-picking list before the actual rebase).\n> \n> I think true power users would just do the last two lines of\n> git-rebase.sh by hand in two steps.  By stashing away the\n> format-patch output, and using git-am interactively, you can\n> easily drop unwanted ones, and then re-run git-am on the same\n> format-patch output to apply the ones you dropped on the first\n> run practically amounts to reordering the patches ;-).\n\nHaving to move around whole patches in the editor is not what you want to \ndo. I was thinking more along the lines of\n\n (a) git-rev-list --pretty=oneline \"$upstream\"..ORIG_HEAD > rev-list\n\n (b) edit the rev-list, moving the single lines around, deleting them, etc\n\n (c) cat rev-list |\n     git-format-patch -k --stdout --stdin --full_index |\n     git-am\n\nbecause the \"--pretty=oneline\" format is actually very nice as a way to \nre-order things and select single commits to be deleted or whatever..\n\n\t\tLinus\n"},{"id":"20951","messageId":"7vslms3zos.fsf@assigned-by-dhcp.cox.net","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605292112530.5623@g5.osdl.org","subject":"Re: [PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-30T04:26:59Z","receivedAt":"2006-05-30T04:26:59Z","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> Having to move around whole patches in the editor is not what you want to \n> do.\n\nI know.  What I meant was:\n\n\t$ format-patch >those-patches\n        $ am -i those-patches\n\t.. say no to the first two and yes to the third one\n        $ am -i those-patches ;# again!!\n        .. say yes to the first two\n\n> I was thinking more along the lines of\n>\n>  (a) git-rev-list --pretty=oneline \"$upstream\"..ORIG_HEAD > rev-list\n>\n>  (b) edit the rev-list, moving the single lines around, deleting them, etc\n>\n>  (c) cat rev-list |\n>      git-format-patch -k --stdout --stdin --full_index |\n>      git-am\n>\n> because the \"--pretty=oneline\" format is actually very nice as a way to \n> re-order things and select single commits to be deleted or whatever..\n\nI like this approach as well.\n"},{"id":"21037","messageId":"7vpshtyffk.fsf@assigned-by-dhcp.cox.net","threadId":"4343","inReplyTo":"Pine.LNX.4.64.0605292112530.5623@g5.osdl.org","subject":"Re: [PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-05-31T22:53:19Z","receivedAt":"2006-05-31T22:53:19Z","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>  (a) git-rev-list --pretty=oneline \"$upstream\"..ORIG_HEAD > rev-list\n>\n>  (b) edit the rev-list, moving the single lines around, deleting them, etc\n>\n>  (c) cat rev-list |\n>      git-format-patch -k --stdout --stdin --full_index |\n>      git-am\n>\n> because the \"--pretty=oneline\" format is actually very nice as a way to \n> re-order things and select single commits to be deleted or whatever..\n\nI am thinking about doing \"format-patch --stdin\" while I am\nfutzing with it for other reasons, and one issue is where to\n\"tac\" the revision list.\n\nWe could internally reverse topo-sort what we read from --stdin\ninside format-patch, but that would defeat the reordering that\nis done in the step (b) above, so that is not a useful thing to\ndo.\n\nIf we wanted to make rev-list piped straight to format-patch\nequilvalent to giving the arguments you would have given rev-list\ndirectly to format-patch, then format-patch should read --stdin\nand reverse the list before emitting them out.\n\nHowever, that would mean in the step (b) above the user needs to\nbe conscious that the list being edited is in the reverse order,\nso if the list of commits needs to be reordered (and that is one\nof the reasons the user is doing this step) what comes earlier\nin the edited list will be output later in the result.\n\nTentatively my feeling is that we should make it known that the\nlist format-patch takes from --stdin is supposed to be _not_\nreversed, and do nothing in format-patch.  In other words, the\nlist fed is a moral equivalent to quilt \"series\" file.\n\nWhat this means is:\n\n\tgit-format-patch $revargs\n\nis not equivalent to\n\n\tgit-rev-list $revargs | git-format-patch --stdin\n\nbut is equivalent to\n\n\tgit-rev-list $revargs | tac | git-format-patch --stdin\n\n\nThoughts from the list?\n"},{"id":"21043","messageId":"20060601031143.GA13392@spearce.org","threadId":"4343","inReplyTo":"7vpshtyffk.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 0/10] re-based and expanded tree-walker cleanup patches","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-06-01T03:11:43Z","receivedAt":"2006-06-01T03:11:43Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Linus Torvalds <torvalds@osdl.org> writes:\n> \n> >  (a) git-rev-list --pretty=oneline \"$upstream\"..ORIG_HEAD > rev-list\n> >\n> >  (b) edit the rev-list, moving the single lines around, deleting them, etc\n> >\n> >  (c) cat rev-list |\n> >      git-format-patch -k --stdout --stdin --full_index |\n> >      git-am\n> >\n[snip]\n> What this means is:\n> \n> \tgit-format-patch $revargs\n> \n> is not equivalent to\n> \n> \tgit-rev-list $revargs | git-format-patch --stdin\n> \n> but is equivalent to\n> \n> \tgit-rev-list $revargs | tac | git-format-patch --stdin\n> \n> \n> Thoughts from the list?\n\nAside from not knowing what tac is I agree with the latter.\nIt is what the user would expect to happen.  Except maybe add a\n--ancestors-first option to git-rev-list to do what tac does before\noutputting the revisions?\n\n\tgit-rev-list --ancestors-first $revargs | git-format-patch --stdin\n\n-- \nShawn.\n"},{"id":"22342","messageId":"m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com","threadId":"4343","inReplyTo":"7vpshtyffk.fsf@assigned-by-dhcp.cox.net","subject":"A series file for git?","fromName":"Eric W. Biederman","fromEmail":"ebiederm@xmission.com","sentAt":"2006-06-23T11:37:34Z","receivedAt":"2006-06-23T11:37:34Z","isPatch":false,"sender":{"key":"ebiederm@xmission.com","avatar":"https://avatars.githubusercontent.com/u/7477136?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> Linus Torvalds <torvalds@osdl.org> writes:\n>\n>>  (a) git-rev-list --pretty=oneline \"$upstream\"..ORIG_HEAD > rev-list\n>>\n>>  (b) edit the rev-list, moving the single lines around, deleting them, etc\n>>\n>>  (c) cat rev-list |\n>>      git-format-patch -k --stdout --stdin --full_index |\n>>      git-am\n>>\n\n> Tentatively my feeling is that we should make it known that the\n> list format-patch takes from --stdin is supposed to be _not_\n> reversed, and do nothing in format-patch.  In other words, the\n> list fed is a moral equivalent to quilt \"series\" file.\n\nAgreed that seem to make a lot of sense.\n\n> What this means is:\n>\n> \tgit-format-patch $revargs\n>\n> is not equivalent to\n>\n> \tgit-rev-list $revargs | git-format-patch --stdin\n>\n> but is equivalent to\n>\n> \tgit-rev-list $revargs | tac | git-format-patch --stdin\n\nAt least for now the using tac is fine.  Longer term I think\nhaving some reverse arguments to rev-list or even better\ngit-log so we can review patches in order instead backwards\nwould be very interesting.\n\n> Thoughts from the list?\n\nSo I have played with this some and a bit of feedback.\n\nI was using:\n\tgit-rev-list $revargs | tac > list\n\n\tfor sha1 in $(cat list); do git-cherry-pick -r $sha1 ; done\n\nIs there any real difference between using git-format-patch | git-am\nand using git-am to apply patches.  I was using git-cherry-pick simply\nbecause it was easier to sha1 too.\n\n- When you reorder patches minor merge conflicts are common\n  so a big pipe won't work very often in practice.  So you\n  need a way to handle failures in the middle.\n\n- Keeping patches in git and just remembering their sha1 is nice\n  but it has the downside that it can be really easy to loose\n  the sha1, and thus the patch.  So some sort of history mechanism\n  so you can get back to where you were would be nice.\n\n- This is a similar technique to topic branches.  However in some\n  of the more interesting cases a topic branch can't be used because\n  you have a whole series of little changes, that allow depend on\n  each other.  So topic branches need not apply.\n\n- One of the places where we currently uses series files\n  (patch-scripts && quilt), and heavy cherry picking is for patch\n  aging.  That is letting patches sit in a testing branch for \n  a while so people have a chance to test and look at them.\n\n  The important pieces there are the ability to reorder the changes\n  to put the patches with the highest confidence first.\n\n  The ability to comment on the patches so that it is possible\n  to record groups of patches and information about their relative\n  stability.  As once a patch series gets large without at least\n  a few comments it is too much for a person to remember what\n  is happening with each patch without a few clues.\n\n- The other place where we use series files is in pure development\n  where we are breaking up or otherwise creating the needed changes\n  in a set of simple obviously correct changes.\n\n....\n\nSo I think it could be very interesting to have a series file\nas something the base git porcelain helps to deal with.\n\nIf we create a meta data branch with just the series file\nwe can remove the risk of loosing things, as we always\nhave a path back to the old history if we want it.\n\nWe can keep track of the series file with a SERIES_HEAD\nsimilar to FETCH_HEAD.  This fairly easily allows editing\nin different places in the patch stack that normally happens\nwith  quilt or patch-scripts.\n\nWe can put comments in a series file to keep track of probationary\npatches.\n\nThe two tricky pieces I see with this idea are:\n- teaching git-fsck-objects that we have a sha1 in a blob objects.\n\n- Where to put the active checkout series file when we are working,\n  so we don't stumble on it.\n\n...\n\nI'm trying to sort out a sane work flow for developing with a large\nnumber of highly related patches on the development side.  I care\nbecause the way I think I usually fix the root cause of problems.\n\nIt took me nearly 25 patches to decouple the brain damage the msi\ncode imposed on x86 irq handling.   In the development of that\nI had to reorder and edit things extensively as I broke the\nwork up, and created a sane patch flow.\n\nThe trick with rev-list | tac to create a series file for reordering\nchanges was very useful but it wasn't enough to say it solve the\nproblem.  \n\nOne trivial issue was that git-cherry-pick -r always does the full\ngit-commit so it is much more I/O bound than necessary, because\ngit-commit does git-status.  Which is just silly if you are applying\na bunch of changes that apply without errors.\n\nEric\n"},{"id":"22374","messageId":"7v64ira69y.fsf@assigned-by-dhcp.cox.net","threadId":"4343","inReplyTo":"m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com","subject":"Re: A series file for git?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-23T21:52:57Z","receivedAt":"2006-06-23T21:52:57Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"ebiederm@xmission.com (Eric W. Biederman) writes:\n\n> Is there any real difference between using git-format-patch | git-am\n> and using git-am to apply patches.  I was using git-cherry-pick simply\n> because it was easier to sha1 too.\n>\n> - When you reorder patches minor merge conflicts are common\n>   so a big pipe won't work very often in practice.  So you\n>   need a way to handle failures in the middle.\n\nTrue.  The big pipe's answer to that question is that git-am\nstashes what is fed to it just like when it is applying multiple\npatches in .dotest/ and lets you continue from where a breakage\nhappened.  Also the way rebase (without the new --merge flag)\nworked was to produce format-patch with full blob SHA1's on the\nindex lines and run git-am with --3way, so it can fall back on\nthree-way merge when the patch does not apply.  This often\nresulted in \"git-am --3way\" detecting a patch that does not\napply, falling back to do a three way to notice that the patch\nhas already been applied.\n\nI have to think about the rest of your message on \"series\" file.\n"},{"id":"22428","messageId":"7vac83ylk6.fsf@assigned-by-dhcp.cox.net","threadId":"4343","inReplyTo":"m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com","subject":"Re: A series file for git?","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-24T09:01:13Z","receivedAt":"2006-06-24T09:01:13Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"ebiederm@xmission.com (Eric W. Biederman) writes:\n\n> I was using:\n> \tgit-rev-list $revargs | tac > list\n> \tfor sha1 in $(cat list); do git-cherry-pick -r $sha1 ; done\n>...\n> - Keeping patches in git and just remembering their sha1 is nice\n>   but it has the downside that it can be really easy to loose\n>   the sha1, and thus the patch.  So some sort of history mechanism\n>   so you can get back to where you were would be nice.\n\nActually, the $revargs above is composed of your branch names\n(e.g. \"^master this-topic that-topic\"), so as long as you do not\nlose these branches they are protected.\n>\n> - This is a similar technique to topic branches.  However in some\n>   of the more interesting cases a topic branch can't be used because\n>   you have a whole series of little changes, that allow depend on\n>   each other.  So topic branches need not apply.\n\nSorry I fail to see why.  A series of little changes that depend\non each other would be a string of pearls on a topic branch in\nthe simplest case, or a handful of topic branches that\noccasionally merge with each other if you want to get fancier.\nCherry-picking from a DAG of the latter kind with your rev-list\npiped to tac is no different than cherry-picking from a simple\nstraight line of the former kind, isn't it?\n\n> - One of the places where we currently uses series files\n>   (patch-scripts && quilt), and heavy cherry picking is for patch\n>   aging.  That is letting patches sit in a testing branch for \n>   a while so people have a chance to test and look at them.\n\nI agree that patch aging and updating does not mesh well with\nhow git inherently works, as git regards commits immutable\nobjects.  Even then, I use my \"pu\" branch (and topics that\nhasn't merged to \"next\" but in \"pu\") pretty much as patch aging\narea and I regularly do \"git commit --amend\" to update them.\nThis however is cumbersome with core git tools alone, and I\nsuspect is better done with StGIT.\n\n> If we create a meta data branch with just the series file\n> we can remove the risk of loosing things, as we always\n> have a path back to the old history if we want it.\n\nI am not sure about that.  What does the series file contain,\nand what other things the meta data branch contain?  If you are\nlisting commit SHA1 in the series file, you _do_ have the risk\nof losing things -- git-fsck-objects needs to look at such blob\nobject and consider that as the root of reachability chain; to\nme that seems too specialized hack.\n\nI have a feeling that I really should study how well StGIT does\nthings before talking about this further.  It may suit your\nneeds perfectly.  What do you feel is lacking in StGIT that you\nneed?\n"},{"id":"22467","messageId":"m1r71exww5.fsf@ebiederm.dsl.xmission.com","threadId":"4343","inReplyTo":"7vac83ylk6.fsf@assigned-by-dhcp.cox.net","subject":"Re: A series file for git?","fromName":"Eric W. Biederman","fromEmail":"ebiederm@xmission.com","sentAt":"2006-06-24T17:54:02Z","receivedAt":"2006-06-24T17:54:02Z","isPatch":false,"sender":{"key":"ebiederm@xmission.com","avatar":"https://avatars.githubusercontent.com/u/7477136?v=4"},"body":"Junio C Hamano <junkio@cox.net> writes:\n\n> ebiederm@xmission.com (Eric W. Biederman) writes:\n>\n>> I was using:\n>> \tgit-rev-list $revargs | tac > list\n>> \tfor sha1 in $(cat list); do git-cherry-pick -r $sha1 ; done\n>>...\n>> - Keeping patches in git and just remembering their sha1 is nice\n>>   but it has the downside that it can be really easy to loose\n>>   the sha1, and thus the patch.  So some sort of history mechanism\n>>   so you can get back to where you were would be nice.\n>\n> Actually, the $revargs above is composed of your branch names\n> (e.g. \"^master this-topic that-topic\"), so as long as you do not\n> lose these branches they are protected.\n\nRight but typically I have something that looks like.\n\"git-rev-list --pretty=oneline 2.6.17-rc6-mm2..HEAD | tac > list\"\nand HEAD changes.\n\nI could be careful and before I do each operation save a branch\nname.\n\n>> - This is a similar technique to topic branches.  However in some\n>>   of the more interesting cases a topic branch can't be used because\n>>   you have a whole series of little changes, that allow depend on\n>>   each other.  So topic branches need not apply.\n>\n> Sorry I fail to see why.  A series of little changes that depend\n> on each other would be a string of pearls on a topic branch in\n> the simplest case, or a handful of topic branches that\n> occasionally merge with each other if you want to get fancier.\n> Cherry-picking from a DAG of the latter kind with your rev-list\n> piped to tac is no different than cherry-picking from a simple\n> straight line of the former kind, isn't it?\n\nIt is exactly a string of perls on a topic branch.  My point\nis that when things are sufficiently interrelated that you\ncan't use more than one topic branch. \n\nWith topic branches when you find a small fix to an existing\nperl you just commit it to that branch, and it works\nbecause each branch really is composed of a single pearl.\n(At least that is my intuition).  \n\nWhen you have multiple highly interrelated pearls and you\nare testing you can easily put the fix for a pearl at\nthe end of the branch.  But before you push your changes\nupstream that fix needs to be merged with the original\npearl that it fixes.  Which is fundamentally a history\nediting kind of action.\n\n>> - One of the places where we currently uses series files\n>>   (patch-scripts && quilt), and heavy cherry picking is for patch\n>>   aging.  That is letting patches sit in a testing branch for \n>>   a while so people have a chance to test and look at them.\n>\n> I agree that patch aging and updating does not mesh well with\n> how git inherently works, as git regards commits immutable\n> objects.  Even then, I use my \"pu\" branch (and topics that\n> hasn't merged to \"next\" but in \"pu\") pretty much as patch aging\n> area and I regularly do \"git commit --amend\" to update them.\n> This however is cumbersome with core git tools alone, and I\n> suspect is better done with StGIT.\n\nI have a similar suspicion.  I am glad we pretty much see\nthe same problem.\n\n>> If we create a meta data branch with just the series file\n>> we can remove the risk of loosing things, as we always\n>> have a path back to the old history if we want it.\n>\n> I am not sure about that.  What does the series file contain,\n> and what other things the meta data branch contain?  If you are\n> listing commit SHA1 in the series file, you _do_ have the risk\n> of losing things -- git-fsck-objects needs to look at such blob\n> object and consider that as the root of reachability chain; to\n> me that seems too specialized hack.\n\nWhen described that way I agree.   The best I can imagine\nis to list those commits as ancestors of the current commit.\nHmm.  Or possibly I could collect up tag objects and work\nwith them.  In any case representing this in a non-hackish\nway is my goal.\n\n> I have a feeling that I really should study how well StGIT does\n> things before talking about this further.  It may suit your\n> needs perfectly.  What do you feel is lacking in StGIT that you\n> need?\n\nWhat I want and what I see lacking in the git and StGit is\nthe ability to record the history of editing the history\nof a branch. \n\nA mundane example.  It would be nice if I rebased a branch if\nI could record in some fashion what that branch was before\nI rebased it.\n\nSo I am trying to figure out how to construct a meta branch\nthat records that kind of information about a branch.\n\nIntuitively this feels like the history of a series file\nto me.  Did I add commits?  Did I remove commits?  Did\nI reorder commits?  Did I merge commits?\n\nAndrew in his patch-scripts documentation recommends using\nCVS to record this information (The documentation predates\ngit).  I think this is something that got lost with quilt when Andrews\npatch-scripts were cleaned up and made more general.\n\nI need to look some more but I don't think recording the history\nof editing a branch is problem that has been solved in any of\nthe git flavors.\n\nI will certainly look at StGit more and at the core git data\nstructures some more and see if I can come up with a creative\nway of representing the history of branch edit operations\nthat will not break existing tools.\n\nEric\n"},{"id":"22585","messageId":"20060626004426.GA7193@spearce.org","threadId":"4343","inReplyTo":"m1r71exww5.fsf@ebiederm.dsl.xmission.com","subject":"Re: A series file for git?","fromName":"Shawn Pearce","fromEmail":"spearce@spearce.org","sentAt":"2006-06-26T00:44:26Z","receivedAt":"2006-06-26T00:44:26Z","isPatch":false,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"\"Eric W. Biederman\" <ebiederm@xmission.com> wrote:\n> Junio C Hamano <junkio@cox.net> writes:\n[snip]\n> > I am not sure about that.  What does the series file contain,\n> > and what other things the meta data branch contain?  If you are\n> > listing commit SHA1 in the series file, you _do_ have the risk\n> > of losing things -- git-fsck-objects needs to look at such blob\n> > object and consider that as the root of reachability chain; to\n> > me that seems too specialized hack.\n> \n> When described that way I agree.   The best I can imagine\n> is to list those commits as ancestors of the current commit.\n> Hmm.  Or possibly I could collect up tag objects and work\n> with them.  In any case representing this in a non-hackish\n> way is my goal.\n\nI did this in pg.  It didn't work out very well as the GIT diff\ntools (e.g. the diff in gitk) show the diff in a very odd way.\nIt did not work out as well as I had hoped.\n\n> > I have a feeling that I really should study how well StGIT does\n> > things before talking about this further.  It may suit your\n> > needs perfectly.  What do you feel is lacking in StGIT that you\n> > need?\n> \n> What I want and what I see lacking in the git and StGit is\n> the ability to record the history of editing the history\n> of a branch. \n> \n> A mundane example.  It would be nice if I rebased a branch if\n> I could record in some fashion what that branch was before\n> I rebased it.\n\nUse the new reflog code.  Its in 1.4.  Check the documentation for\ngit-update-ref for some details.  git-commit, git-rebase and git-am\nshould track history on a ref in the reflog.  However a reflog\nwon't anchor a commit into your repository and thus a prune may\nremove it if no other commit/ref/tag mentions it.\n\n-- \nShawn.\n"}]}