{"thread":{"id":"1003","subject":"[PATCH 0/2] Pull objects of various types","startedAt":"2005-06-22T00:33:19Z","lastAt":"2021-04-29T12:05:45Z","messageCount":142,"participants":["Daniel Barkalow","Ævar Arnfjörð Bjarmason","Taylor Blau","Junio C Hamano","Jeff King","Ramsay Jones","Jonathan Tan","Josh Steadmon","Felipe Contreras"],"isPatch":true,"patchVersion":1,"patchTotal":2},"messages":[{"id":"5108","messageId":"Pine.LNX.4.21.0506212029190.30848-100000@iabervon.org","threadId":"1003","inReplyTo":null,"subject":"[PATCH 0/2] Pull objects of various types","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-06-22T00:33:19Z","receivedAt":"2005-06-22T00:33:19Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This series handles pulling objects of various types, rather than just\ncommits. In order to support pulling tags (the interesting case), it is\nnecessary to support getting the struct object for the tagged object when\nthe tagged object isn't available.\n\n 1: Support getting a valid struct object for the absent object tagged by\n    a tag file.\n 2: Support processing objects of unknown type in pull.c\n\n\t-Daniel\n*This .sig left intentionally blank*\n\n"},{"id":"5109","messageId":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212029190.30848-100000@iabervon.org","subject":"[PATCH 1/2] Parse tags for absent objects","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-06-22T00:35:10Z","receivedAt":"2005-06-22T00:35:10Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"Handle parsing a tag for a non-present object. This adds a function to lookup\nan object with lookup_* for * in a string, so that it can get the right storage\nbased on the \"type\" line in the tag.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n\nIndex: object.c\n===================================================================\n--- 5760644db3f9cb044c99aa0f9ce4fc8d4eb76da1/object.c  (mode:100644 sha1:5e8378857028afeb4d1cd91c0de26c8414e137de)\n+++ d0df139324abdbf701ffcae26e43bcb0350c270e/object.c  (mode:100644 sha1:21f872ee163e9eeff1a52854791c5b96a2ec2ceb)\n@@ -98,6 +98,22 @@\n \t}\n }\n \n+struct object *lookup_object_type(const unsigned char *sha1, const char *type)\n+{\n+\tif (!strcmp(type, blob_type)) {\n+\t\treturn &lookup_blob(sha1)->object;\n+\t} else if (!strcmp(type, tree_type)) {\n+\t\treturn &lookup_tree(sha1)->object;\n+\t} else if (!strcmp(type, commit_type)) {\n+\t\treturn &lookup_commit(sha1)->object;\n+\t} else if (!strcmp(type, tag_type)) {\n+\t\treturn &lookup_tag(sha1)->object;\n+\t} else {\n+\t\terror(\"Unknown type %s\", type);\n+\t\treturn NULL;\n+\t}\n+}\n+\n struct object *parse_object(const unsigned char *sha1)\n {\n \tunsigned long mapsize;\nIndex: object.h\n===================================================================\n--- 5760644db3f9cb044c99aa0f9ce4fc8d4eb76da1/object.h  (mode:100644 sha1:ca455d57117af5f15e83b791a336351b43af6716)\n+++ d0df139324abdbf701ffcae26e43bcb0350c270e/object.h  (mode:100644 sha1:1bd59ac6fcf7798e02c2474e630c282f022eff10)\n@@ -21,8 +21,12 @@\n extern int nr_objs;\n extern struct object **objs;\n \n+/** Internal only **/\n struct object *lookup_object(const unsigned char *sha1);\n \n+/** Returns the object, having looked it up as being the given type. **/\n+struct object *lookup_object_type(const unsigned char *sha1, const char *type);\n+\n void created_object(const unsigned char *sha1, struct object *obj);\n \n /** Returns the object, having parsed it to find out what it is. **/\nIndex: tag.c\n===================================================================\n--- 5760644db3f9cb044c99aa0f9ce4fc8d4eb76da1/tag.c  (mode:100644 sha1:4041af2572a4427a03bc8955137b7d2211f9d770)\n+++ d0df139324abdbf701ffcae26e43bcb0350c270e/tag.c  (mode:100644 sha1:2b25fc0e1dc53234e38e8ed8fdc1cb99fa4fd84a)\n@@ -28,6 +28,7 @@\n \tint typelen, taglen;\n \tunsigned char object[20];\n \tconst char *type_line, *tag_line, *sig_line;\n+\tchar type[20];\n \n         if (item->object.parsed)\n                 return 0;\n@@ -38,10 +39,6 @@\n \tif (memcmp(\"object \", data, 7) || get_sha1_hex(data + 7, object))\n \t\treturn -1;\n \n-\titem->tagged = parse_object(object);\n-\tif (item->tagged)\n-\t\tadd_ref(&item->object, item->tagged);\n-\n \ttype_line = data + 48;\n \tif (memcmp(\"\\ntype \", type_line-1, 6))\n \t\treturn -1;\n@@ -58,11 +55,17 @@\n \ttypelen = tag_line - type_line - strlen(\"type \\n\");\n \tif (typelen >= 20)\n \t\treturn -1;\n+\tmemcpy(type, type_line + 5, typelen);\n+\ttype[typelen] = '\\0';\n \ttaglen = sig_line - tag_line - strlen(\"tag \\n\");\n \titem->tag = xmalloc(taglen + 1);\n \tmemcpy(item->tag, tag_line + 4, taglen);\n \titem->tag[taglen] = '\\0';\n \n+\titem->tagged = lookup_object_type(object, type);\n+\tif (item->tagged)\n+\t\tadd_ref(&item->object, item->tagged);\n+\n \treturn 0;\n }\n \n\n"},{"id":"5110","messageId":"Pine.LNX.4.21.0506212035140.30848-100000@iabervon.org","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212029190.30848-100000@iabervon.org","subject":"[PATCH 2/2] Pull misc objects","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2005-06-22T00:35:53Z","receivedAt":"2005-06-22T00:35:53Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"Make pull fetch whatever is specified, parse it to figure out what it is, and\nthen process it appropriately. This also supports getting tag objects, and\ngetting whatever they tag.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\nIndex: pull.c\n===================================================================\n--- d0df139324abdbf701ffcae26e43bcb0350c270e/pull.c  (mode:100644 sha1:e70fc02f3bf5b6c626a138d6d76d819fab76f0c8)\n+++ b6a510708036fe29a19c33472f5c0b746e2d26d7/pull.c  (mode:100644 sha1:91d9db6c7b1be84e7a5fe21c5194fbf22dadc8cb)\n@@ -3,6 +3,8 @@\n #include \"cache.h\"\n #include \"commit.h\"\n #include \"tree.h\"\n+#include \"tag.h\"\n+#include \"blob.h\"\n #include \"refs.h\"\n \n const char *write_ref = NULL;\n@@ -57,6 +59,8 @@\n \treturn status;\n }\n \n+static int process_unknown(unsigned char *sha1);\n+\n static int process_tree(unsigned char *sha1)\n {\n \tstruct tree *tree = lookup_tree(sha1);\n@@ -115,6 +119,35 @@\n \treturn 0;\n }\n \n+static int process_tag(unsigned char *sha1)\n+{\n+\tstruct tag *obj = lookup_tag(sha1);\n+\n+\tif (parse_tag(obj))\n+\t\treturn -1;\n+\treturn process_unknown(obj->tagged->sha1);\n+}\n+\n+static int process_unknown(unsigned char *sha1)\n+{\n+\tstruct object *obj;\n+\tif (make_sure_we_have_it(\"object\", sha1))\n+\t\treturn -1;\n+\tobj = parse_object(sha1);\n+\tif (!obj)\n+\t\treturn error(\"Unable to parse object %s\", sha1_to_hex(sha1));\n+\tif (obj->type == commit_type)\n+\t\treturn process_commit(sha1);\n+\tif (obj->type == tree_type)\n+\t\treturn process_tree(sha1);\n+\tif (obj->type == blob_type)\n+\t\treturn 0;\n+\tif (obj->type == tag_type)\n+\t\treturn process_tag(sha1);\n+\treturn error(\"Unable to determine requirement of type %s for %s\",\n+\t\t     obj->type, sha1_to_hex(sha1));\n+}\n+\n static int interpret_target(char *target, unsigned char *sha1)\n {\n \tif (!get_sha1_hex(target, sha1))\n@@ -142,7 +175,7 @@\n \tif (interpret_target(target, sha1))\n \t\treturn error(\"Could not interpret %s as something to pull\",\n \t\t\t     target);\n-\tif (process_commit(sha1))\n+\tif (process_unknown(sha1))\n \t\treturn -1;\n \t\n \tif (write_ref) {\n\n"},{"id":"418515","messageId":"20210308200426.21824-3-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 2/7] object.c: make type_from_string() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:21Z","receivedAt":"2021-03-08T20:05:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the type_from_string*() functions to return an \"enum\nobject_type\", and refactor their callers to check for \"== OBJ_BAD\"\ninstead of \"< 0\".\n\nThis helps to distinguish code in object.c where we really do return\n-1 from code that returns an \"enum object_type\", whose OBJ_BAD happens\nto be -1.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n fsck.c        |  2 +-\n object-file.c |  2 +-\n object.c      | 12 ++++++------\n object.h      |  4 ++--\n 4 files changed, 10 insertions(+), 10 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex 6cc4f9ea892..a6d00dfa2e6 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -958,7 +958,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n \t\tgoto done;\n \t}\n \t*tagged_type = type_from_string_gently(buffer, eol - buffer);\n-\tif (*tagged_type < 0)\n+\tif (*tagged_type == OBJ_BAD)\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, \"invalid 'type' value\");\n \tif (ret)\n \t\tgoto done;\ndiff --git a/object-file.c b/object-file.c\nindex 42bc579828d..cd30c2b5590 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1324,7 +1324,7 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,\n \t */\n \tif ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))\n \t\ttype = 0;\n-\telse if (type < 0)\n+\telse if (type == OBJ_BAD)\n \t\tdie(_(\"invalid object type\"));\n \tif (oi->typep)\n \t\t*oi->typep = type;\ndiff --git a/object.c b/object.c\nindex c7586e46727..eebacc28847 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,22 +35,22 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, ssize_t len)\n+enum object_type type_from_string_gently(const char *str, ssize_t len)\n {\n-\tint i;\n+\tenum object_type i;\n \n \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n \t\t    object_type_strings[i][len] == '\\0')\n \t\t\treturn i;\n-\treturn -1;\n+\treturn OBJ_BAD;\n }\n \n-int type_from_string(const char *str)\n+enum object_type type_from_string(const char *str)\n {\n \tsize_t len = strlen(str);\n-\tint ret = type_from_string_gently(str, len);\n-\tif (ret < 0)\n+\tenum object_type ret = type_from_string_gently(str, len);\n+\tif (ret == OBJ_BAD)\n \t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n \treturn ret;\n }\ndiff --git a/object.h b/object.h\nindex ffdc1298300..5e7a523e858 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,8 +93,8 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, ssize_t len);\n-int type_from_string(const char *str);\n+enum object_type type_from_string_gently(const char *str, ssize_t len);\n+enum object_type type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418516","messageId":"20210308200426.21824-1-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 0/7] improve reporting of unexpected objects","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:19Z","receivedAt":"2021-03-08T20:05:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"We have some errors that say \"your OID %s is not a blob\" or whatever,\nnow with 5/7 we'll say \"object %s is a %s, not a %s\" in most cases.\n\nThen 7/7 fixes a regression which AFAICT is from 2005. So it's pretty\nobscure. When you craft an invalid tag object saying an OID is a tag\ninstead of a commit, we'd buggily invert the two types when reporting\nthat error.\n\nThe solution to that in 7/7 may not be ideal, but is the best one I\ncould come up with, so feedback on that patch & this whole thing is\nmost welcome.\n\nÆvar Arnfjörð Bjarmason (7):\n  object.c: refactor type_from_string_gently()\n  object.c: make type_from_string() return \"enum object_type\"\n  oid_object_info(): return \"enum object_type\"\n  tree.c: fix misindentation in parse_tree_gently()\n  object.c: add a utility function for \"expected type X, got Y\"\n  object tests: add test for unexpected objects in tags\n  tag: don't misreport type of tagged objects in errors\n\n blob.c                                 |  16 +++-\n blob.h                                 |   3 +\n builtin/blame.c                        |   2 +-\n builtin/cat-file.c                     |   2 +-\n builtin/index-pack.c                   |  15 ++--\n builtin/mktree.c                       |   2 +-\n builtin/pack-objects.c                 |   4 +-\n builtin/replace.c                      |   2 +-\n builtin/tag.c                          |   2 +-\n builtin/unpack-objects.c               |   6 +-\n commit.c                               |  24 ++++--\n commit.h                               |   2 +\n fsck.c                                 |   4 +-\n object-file.c                          |  15 ++--\n object-name.c                          |  18 ++--\n object-store.h                         |   2 +-\n object.c                               |  62 +++++++++++---\n object.h                               |   9 +-\n packfile.c                             |   4 +-\n reachable.c                            |   5 +-\n t/t6102-rev-list-unexpected-objects.sh | 113 ++++++++++++++++++++++++-\n tag.c                                  |  14 ++-\n tag.h                                  |   2 +\n tree.c                                 |  27 ++++--\n tree.h                                 |   2 +\n 25 files changed, 282 insertions(+), 75 deletions(-)\n\n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418519","messageId":"20210308200426.21824-4-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 3/7] oid_object_info(): return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:22Z","receivedAt":"2021-03-08T20:05:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change oid_object_info() to return an \"enum object_type\", this is what\nit did anyway, except that it hardcoded -1 instead of an\nOBJ_BAD.\n\nLet's instead have it return the \"enum object_type\", at which point\ncallers will expect OBJ_BAD. This allows for refactoring code that\ne.g. expected any \"< 0\" value, but would only have to deal with\nOBJ_BAD (= -1).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/blame.c          |  2 +-\n builtin/cat-file.c       |  2 +-\n builtin/index-pack.c     |  6 +++---\n builtin/mktree.c         |  2 +-\n builtin/pack-objects.c   |  4 ++--\n builtin/replace.c        |  2 +-\n builtin/tag.c            |  2 +-\n builtin/unpack-objects.c |  6 +++++-\n object-file.c            | 11 +++++------\n object-name.c            | 18 +++++++++---------\n object-store.h           |  2 +-\n packfile.c               |  4 +---\n reachable.c              |  5 +++--\n 13 files changed, 34 insertions(+), 32 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 641523ff9af..5dd3c38a8c6 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -810,7 +810,7 @@ static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)\n \toidcpy(&oid, oid_ret);\n \twhile (1) {\n \t\tstruct object *obj;\n-\t\tint kind = oid_object_info(r, &oid, NULL);\n+\t\tenum object_type kind = oid_object_info(r, &oid, NULL);\n \t\tif (kind == OBJ_COMMIT) {\n \t\t\toidcpy(oid_ret, &oid);\n \t\t\treturn 0;\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 5ebf13359e8..1d989c62a4e 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -133,7 +133,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \n \tcase 'p':\n \t\ttype = oid_object_info(the_repository, &oid, NULL);\n-\t\tif (type < 0)\n+\t\tif (type == OBJ_BAD)\n \t\t\tdie(\"Not a valid object name %s\", obj_name);\n \n \t\t/* custom pretty-print here */\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex bad57488079..253cfb07fbd 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -236,8 +236,8 @@ static unsigned check_object(struct object *obj)\n \n \tif (!(obj->flags & FLAG_CHECKED)) {\n \t\tunsigned long size;\n-\t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n-\t\tif (type <= 0)\n+\t\tenum object_type type = oid_object_info(the_repository, &obj->oid, &size);\n+\t\tif (type == OBJ_BAD)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\n \t\tif (type != obj->type)\n@@ -820,7 +820,7 @@ static void sha1_object(const void *data, struct object_entry *obj_entry,\n \t\tunsigned long has_size;\n \t\tread_lock();\n \t\thas_type = oid_object_info(the_repository, oid, &has_size);\n-\t\tif (has_type < 0)\n+\t\tif (has_type == OBJ_BAD)\n \t\t\tdie(_(\"cannot read existing object info %s\"), oid_to_hex(oid));\n \t\tif (has_type != type || has_size != size)\n \t\t\tdie(_(\"SHA1 COLLISION FOUND WITH %s !\"), oid_to_hex(oid));\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex 891991b00d6..e6f8e0edb23 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -118,7 +118,7 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n \n \t/* Check the type of object identified by sha1 */\n \tobj_type = oid_object_info(the_repository, &oid, NULL);\n-\tif (obj_type < 0) {\n+\tif (obj_type == OBJ_BAD) {\n \t\tif (allow_missing) {\n \t\t\t; /* no problem - missing objects are presumed to be of the right type */\n \t\t} else {\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 6d62aaf59a0..e60ae4ebd9a 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2222,7 +2222,7 @@ unsigned long oe_get_size_slow(struct packing_data *pack,\n \n \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n \t\tpacking_data_lock(&to_pack);\n-\t\tif (oid_object_info(the_repository, &e->idx.oid, &size) < 0)\n+\t\tif (oid_object_info(the_repository, &e->idx.oid, &size) == OBJ_BAD)\n \t\t\tdie(_(\"unable to get size of %s\"),\n \t\t\t    oid_to_hex(&e->idx.oid));\n \t\tpacking_data_unlock(&to_pack);\n@@ -3198,7 +3198,7 @@ static int add_loose_object(const struct object_id *oid, const char *path,\n {\n \tenum object_type type = oid_object_info(the_repository, oid, NULL);\n \n-\tif (type < 0) {\n+\tif (type == OBJ_BAD) {\n \t\twarning(_(\"loose object at %s could not be examined\"), path);\n \t\treturn 0;\n \t}\ndiff --git a/builtin/replace.c b/builtin/replace.c\nindex cd487659117..e9e151ae957 100644\n--- a/builtin/replace.c\n+++ b/builtin/replace.c\n@@ -322,7 +322,7 @@ static int edit_and_replace(const char *object_ref, int force, int raw)\n \t\treturn error(_(\"not a valid object name: '%s'\"), object_ref);\n \n \ttype = oid_object_info(the_repository, &old_oid, NULL);\n-\tif (type < 0)\n+\tif (type == OBJ_BAD)\n \t\treturn error(_(\"unable to get object type for %s\"),\n \t\t\t     oid_to_hex(&old_oid));\n \ndiff --git a/builtin/tag.c b/builtin/tag.c\nindex d403417b562..18206341409 100644\n--- a/builtin/tag.c\n+++ b/builtin/tag.c\n@@ -260,7 +260,7 @@ static void create_tag(const struct object_id *object, const char *object_ref,\n \tchar *path = NULL;\n \n \ttype = oid_object_info(the_repository, object, NULL);\n-\tif (type <= OBJ_NONE)\n+\tif (type == OBJ_BAD)\n \t\tdie(_(\"bad object type.\"));\n \n \tif (type == OBJ_TAG)\ndiff --git a/builtin/unpack-objects.c b/builtin/unpack-objects.c\nindex dd4a75e030d..c88daa3a5b1 100644\n--- a/builtin/unpack-objects.c\n+++ b/builtin/unpack-objects.c\n@@ -203,7 +203,11 @@ static int check_object(struct object *obj, int type, void *data, struct fsck_op\n \tif (!(obj->flags & FLAG_OPEN)) {\n \t\tunsigned long size;\n \t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n-\t\tif (type != obj->type || type <= 0)\n+\t\tif (type == OBJ_BAD)\n+\t\t\tdie(_(\"unable to get object type for %s\"),\n+\t\t\t    oid_to_hex(&obj->oid));\n+\t\tif (type != obj->type)\n+\t\t\t/* todo to new function */\n \t\t\tdie(\"object of unexpected type\");\n \t\tobj->flags |= FLAG_WRITTEN;\n \t\treturn 0;\ndiff --git a/object-file.c b/object-file.c\nindex cd30c2b5590..8be6ce56133 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1573,10 +1573,9 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,\n }\n \n \n-/* returns enum object_type or negative */\n-int oid_object_info(struct repository *r,\n-\t\t    const struct object_id *oid,\n-\t\t    unsigned long *sizep)\n+enum object_type oid_object_info(struct repository *r,\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t unsigned long *sizep)\n {\n \tenum object_type type;\n \tstruct object_info oi = OBJECT_INFO_INIT;\n@@ -1585,7 +1584,7 @@ int oid_object_info(struct repository *r,\n \toi.sizep = sizep;\n \tif (oid_object_info_extended(r, oid, &oi,\n \t\t\t\t      OBJECT_INFO_LOOKUP_REPLACE) < 0)\n-\t\treturn -1;\n+\t\treturn OBJ_BAD;\n \treturn type;\n }\n \n@@ -2265,7 +2264,7 @@ int read_pack_header(int fd, struct pack_header *header)\n void assert_oid_type(const struct object_id *oid, enum object_type expect)\n {\n \tenum object_type type = oid_object_info(the_repository, oid, NULL);\n-\tif (type < 0)\n+\tif (type == OBJ_BAD)\n \t\tdie(_(\"%s is not a valid object\"), oid_to_hex(oid));\n \tif (type != expect)\n \t\tdie(_(\"%s is not a valid '%s' object\"), oid_to_hex(oid),\ndiff --git a/object-name.c b/object-name.c\nindex 64202de60b1..c6c3fd5228b 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -239,7 +239,7 @@ static int disambiguate_committish_only(struct repository *r,\n \t\t\t\t\tvoid *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind;\n \n \tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_COMMIT)\n@@ -258,7 +258,7 @@ static int disambiguate_tree_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_TREE;\n }\n \n@@ -267,7 +267,7 @@ static int disambiguate_treeish_only(struct repository *r,\n \t\t\t\t     void *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind;\n \n \tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_TREE || kind == OBJ_COMMIT)\n@@ -286,7 +286,7 @@ static int disambiguate_blob_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_BLOB;\n }\n \n@@ -361,7 +361,7 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n {\n \tconst struct disambiguate_state *ds = data;\n \tstruct strbuf desc = STRBUF_INIT;\n-\tint type;\n+\tenum object_type type;\n \n \tif (ds->fn && !ds->fn(ds->repo, oid, ds->cb_data))\n \t\treturn 0;\n@@ -405,10 +405,10 @@ static int repo_collect_ambiguous(struct repository *r,\n static int sort_ambiguous(const void *a, const void *b, void *ctx)\n {\n \tstruct repository *sort_ambiguous_repo = ctx;\n-\tint a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n-\tint b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n-\tint a_type_sort;\n-\tint b_type_sort;\n+\tenum object_type a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n+\tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n+\tenum object_type a_type_sort;\n+\tenum object_type b_type_sort;\n \n \t/*\n \t * Sorts by hash within the same object type, just as\ndiff --git a/object-store.h b/object-store.h\nindex 541dab08586..e9ab6aff2ab 100644\n--- a/object-store.h\n+++ b/object-store.h\n@@ -203,7 +203,7 @@ static inline void *repo_read_object_file(struct repository *r,\n #endif\n \n /* Read and unpack an object file into memory, write memory to an object file */\n-int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n+enum object_type oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n \n int hash_object_file(const struct git_hash_algo *algo, const void *buf,\n \t\t     unsigned long len, const char *type,\ndiff --git a/packfile.c b/packfile.c\nindex 1fec12ac5f4..17c8c3222eb 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1266,7 +1266,7 @@ static int retry_bad_packed_offset(struct repository *r,\n \t\t\t\t   struct packed_git *p,\n \t\t\t\t   off_t obj_offset)\n {\n-\tint type;\n+\tenum object_type type;\n \tuint32_t pos;\n \tstruct object_id oid;\n \tif (offset_to_pack_pos(p, obj_offset, &pos) < 0)\n@@ -1274,8 +1274,6 @@ static int retry_bad_packed_offset(struct repository *r,\n \tnth_packed_object_id(&oid, p, pack_pos_to_index(p, pos));\n \tmark_bad_packed_object(p, oid.hash);\n \ttype = oid_object_info(r, &oid, NULL);\n-\tif (type <= OBJ_NONE)\n-\t\treturn OBJ_BAD;\n \treturn type;\n }\n \ndiff --git a/reachable.c b/reachable.c\nindex 77a60c70a5d..85f04492ea1 100644\n--- a/reachable.c\n+++ b/reachable.c\n@@ -80,8 +80,6 @@ static void add_recent_object(const struct object_id *oid,\n \t * commits and tags to have been parsed.\n \t */\n \ttype = oid_object_info(the_repository, oid, NULL);\n-\tif (type < 0)\n-\t\tdie(\"unable to get object info for %s\", oid_to_hex(oid));\n \n \tswitch (type) {\n \tcase OBJ_TAG:\n@@ -94,6 +92,9 @@ static void add_recent_object(const struct object_id *oid,\n \tcase OBJ_BLOB:\n \t\tobj = (struct object *)lookup_blob(the_repository, oid);\n \t\tbreak;\n+\tcase OBJ_BAD:\n+\t\tdie(\"unable to get object info for %s\", oid_to_hex(oid));\n+\t\tbreak;\n \tdefault:\n \t\tdie(\"unknown object type for %s: %s\",\n \t\t    oid_to_hex(oid), type_name(type));\n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418517","messageId":"20210308200426.21824-5-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 4/7] tree.c: fix misindentation in parse_tree_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:23Z","receivedAt":"2021-03-08T20:05:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The variables declared in parse_tree_gently() had a single space after\nthe TAB. This dates back to their introduction in bd2c39f58f9 ([PATCH]\ndon't load and decompress objects twice with parse_object(),\n2005-05-06). Let's fix them to follow the style of the rest of the\nfile.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n tree.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex a52479812ce..4820d66a10c 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -216,9 +216,9 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n \n int parse_tree_gently(struct tree *item, int quiet_on_missing)\n {\n-\t enum object_type type;\n-\t void *buffer;\n-\t unsigned long size;\n+\tenum object_type type;\n+\tvoid *buffer;\n+\tunsigned long size;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418518","messageId":"20210308200426.21824-6-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 5/7] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:24Z","receivedAt":"2021-03-08T20:05:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor various \"Object X is not Y\" error messages so that they use\nthe same message as the long-standing object_as_type() error\nmessage. Now we'll consistently report e.g. that we got a commit when\nwe expected a tag, not just that the object is not a tag.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/index-pack.c |  9 +++------\n commit.c             | 10 ++++------\n object.c             | 34 +++++++++++++++++++++++++++++++++-\n object.h             |  5 +++++\n tree.c               |  7 ++++---\n 5 files changed, 49 insertions(+), 16 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 253cfb07fbd..d9082831bb2 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -217,8 +217,8 @@ static int mark_link(struct object *obj, int type, void *data, struct fsck_optio\n \tif (!obj)\n \t\treturn -1;\n \n-\tif (type != OBJ_ANY && obj->type != type)\n-\t\tdie(_(\"object type mismatch at %s\"), oid_to_hex(&obj->oid));\n+\tif (type != OBJ_ANY)\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \n \tobj->flags |= FLAG_LINK;\n \treturn 0;\n@@ -240,10 +240,7 @@ static unsigned check_object(struct object *obj)\n \t\tif (type == OBJ_BAD)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\n-\t\tif (type != obj->type)\n-\t\t\tdie(_(\"object %s: expected type %s, found %s\"),\n-\t\t\t    oid_to_hex(&obj->oid),\n-\t\t\t    type_name(obj->type), type_name(type));\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \t\tobj->flags |= FLAG_CHECKED;\n \t\treturn 1;\n \t}\ndiff --git a/commit.c b/commit.c\nindex 6ccd774841c..54627b546c3 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -299,9 +299,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \t\tif (!ret)\n \t\t\tdie(\"cannot read commit object %s\",\n \t\t\t    oid_to_hex(&commit->object.oid));\n-\t\tif (type != OBJ_COMMIT)\n-\t\t\tdie(\"expected commit for %s, got %s\",\n-\t\t\t    oid_to_hex(&commit->object.oid), type_name(type));\n+\t\toid_is_type_or_die(&commit->object.oid, OBJ_COMMIT, &type);\n \t\tif (sizep)\n \t\t\t*sizep = size;\n \t}\n@@ -489,10 +487,10 @@ int repo_parse_commit_internal(struct repository *r,\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_COMMIT) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_COMMIT, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a commit\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \n \tret = parse_commit_buffer(r, item, buffer, size, 0);\ndiff --git a/object.c b/object.c\nindex eebacc28847..819ee0faa26 100644\n--- a/object.c\n+++ b/object.c\n@@ -28,6 +28,8 @@ static const char *object_type_strings[] = {\n \t\"tag\",\t\t/* OBJ_TAG = 4 */\n };\n \n+static const char *oid_is_a_X_not_a_Y = N_(\"object %s is a %s, not a %s\");\n+\n const char *type_name(unsigned int type)\n {\n \tif (type >= ARRAY_SIZE(object_type_strings))\n@@ -159,6 +161,36 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n \treturn obj;\n }\n \n+static int oid_is_type_or(const struct object_id *oid,\n+\t\t\t  enum object_type want,\n+\t\t\t  enum object_type type,\n+\t\t\t  int err)\n+{\n+\tif (want == type)\n+\t\treturn 0;\n+\tif (err)\n+\t\treturn error(_(oid_is_a_X_not_a_Y),\n+\t\t\t     oid_to_hex(oid), type_name(type),\n+\t\t\t     type_name(want));\n+\telse\n+\t\tdie(_(oid_is_a_X_not_a_Y), oid_to_hex(oid),\n+\t\t    type_name(type), type_name(want));\n+}\n+\n+void oid_is_type_or_die(const struct object_id *oid,\n+\t\t\tenum object_type want,\n+\t\t\tenum object_type *type)\n+{\n+\toid_is_type_or(oid, want, *type, 0);\n+}\n+\n+int oid_is_type_or_error(const struct object_id *oid,\n+\t\t\t enum object_type want,\n+\t\t\t enum object_type *type)\n+{\n+\treturn oid_is_type_or(oid, want, *type, 1);\n+}\n+\n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n \tif (obj->type == type)\n@@ -172,7 +204,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n \t}\n \telse {\n \t\tif (!quiet)\n-\t\t\terror(_(\"object %s is a %s, not a %s\"),\n+\t\t\terror(_(oid_is_a_X_not_a_Y),\n \t\t\t      oid_to_hex(&obj->oid),\n \t\t\t      type_name(obj->type), type_name(type));\n \t\treturn NULL;\ndiff --git a/object.h b/object.h\nindex 5e7a523e858..d2d4a236d0e 100644\n--- a/object.h\n+++ b/object.h\n@@ -124,6 +124,11 @@ void *create_object(struct repository *r, const struct object_id *oid, void *obj\n \n void *object_as_type(struct object *obj, enum object_type type, int quiet);\n \n+void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n+\t\t\tenum object_type *type);\n+int oid_is_type_or_error(const struct object_id *oid, enum object_type want,\n+\t\t\t enum object_type *type);\n+\n /*\n  * Returns the object, having parsed it to find out what it is.\n  *\ndiff --git a/tree.c b/tree.c\nindex 4820d66a10c..d9b1c70b28a 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -219,6 +219,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \tenum object_type type;\n \tvoid *buffer;\n \tunsigned long size;\n+\tint ret;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n@@ -227,10 +228,10 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_TREE) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_TREE, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a tree\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \treturn parse_tree_buffer(item, buffer, size);\n }\n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418520","messageId":"20210308200426.21824-2-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 1/7] object.c: refactor type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:20Z","receivedAt":"2021-03-08T20:05:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Get rid of the \"gently\" argument to type_from_string_gently() to make\nit consistent with most other *_gently() functions.\n\nThis refactoring of adding a third parameter was done in\nfe8e3b71805 (Refactor type_from_string() to allow continuing after\ndetecting an error, 2014-09-10) in preparation for its use in\nfsck.c.\n\nSince then no callers of this function have passed a \"len < 0\" as was\nexpected might happen, so we can simplify its invocation by knowing\nthat it's never called like that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n fsck.c        |  2 +-\n object-file.c |  2 +-\n object.c      | 18 ++++++++++--------\n object.h      |  4 ++--\n 4 files changed, 14 insertions(+), 12 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex e3030f3b358..6cc4f9ea892 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -957,7 +957,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, \"invalid format - unexpected end after 'type' line\");\n \t\tgoto done;\n \t}\n-\t*tagged_type = type_from_string_gently(buffer, eol - buffer, 1);\n+\t*tagged_type = type_from_string_gently(buffer, eol - buffer);\n \tif (*tagged_type < 0)\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, \"invalid 'type' value\");\n \tif (ret)\ndiff --git a/object-file.c b/object-file.c\nindex 5bcfde84718..42bc579828d 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1314,7 +1314,7 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,\n \t\ttype_len++;\n \t}\n \n-\ttype = type_from_string_gently(type_buf, type_len, 1);\n+\ttype = type_from_string_gently(type_buf, type_len);\n \tif (oi->type_name)\n \t\tstrbuf_add(oi->type_name, type_buf, type_len);\n \t/*\ndiff --git a/object.c b/object.c\nindex 98017bed8ef..c7586e46727 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,22 +35,24 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, ssize_t len, int gentle)\n+int type_from_string_gently(const char *str, ssize_t len)\n {\n \tint i;\n \n-\tif (len < 0)\n-\t\tlen = strlen(str);\n-\n \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n \t\t    object_type_strings[i][len] == '\\0')\n \t\t\treturn i;\n+\treturn -1;\n+}\n \n-\tif (gentle)\n-\t\treturn -1;\n-\n-\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n+int type_from_string(const char *str)\n+{\n+\tsize_t len = strlen(str);\n+\tint ret = type_from_string_gently(str, len);\n+\tif (ret < 0)\n+\t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n+\treturn ret;\n }\n \n /*\ndiff --git a/object.h b/object.h\nindex 59daadce214..ffdc1298300 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,8 +93,8 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, ssize_t, int gentle);\n-#define type_from_string(str) type_from_string_gently(str, -1, 0)\n+int type_from_string_gently(const char *str, ssize_t len);\n+int type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418521","messageId":"20210308200426.21824-7-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 6/7] object tests: add test for unexpected objects in tags","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:25Z","receivedAt":"2021-03-08T20:05:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a blind spot in the tests added in 0616617c7e1 (t: introduce tests\nfor unexpected object types, 2019-04-09), there were no meaningful\ntests for checking how we reported on finding the incorrect object\ntype in a tag, i.e. one that broke the \"type\" promise in the tag\nheader.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6102-rev-list-unexpected-objects.sh | 113 ++++++++++++++++++++++++-\n 1 file changed, 112 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 52cde097dd5..2ea1982b9ed 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -31,7 +31,8 @@ test_expect_success 'setup unexpected non-tree entry' '\n '\n \n test_expect_success 'traverse unexpected non-tree entry (lone)' '\n-\ttest_must_fail git rev-list --objects $broken_tree\n+\ttest_must_fail git rev-list --objects $broken_tree >output 2>&1 &&\n+\ttest_i18ngrep \"not a tree\" output\n '\n \n test_expect_success 'traverse unexpected non-tree entry (seen)' '\n@@ -124,4 +125,114 @@ test_expect_success 'traverse unexpected non-blob tag (seen)' '\n \ttest_i18ngrep \"not a blob\" output\n '\n \n+test_expect_success 'setup unexpected non-tag tag' '\n+\ttest_when_finished \"git tag -d tag-commit tag-tag\" &&\n+\n+\tgit tag -a -m\"tagged commit\" tag-commit $commit &&\n+\ttag_commit=$(git rev-parse tag-commit) &&\n+\tgit tag -a -m\"tagged tag\" tag-tag tag-commit &&\n+\ttag_tag=$(git rev-parse tag-tag) &&\n+\n+\tgit cat-file tag tag-tag >good-tag-tag &&\n+\tgit cat-file tag tag-commit >good-commit-tag &&\n+\n+\tsed -e \"s/$tag_commit/$commit/\" <good-tag-tag >broken-tag-tag-commit &&\n+\tsed -e \"s/$tag_commit/$tree/\" <good-tag-tag >broken-tag-tag-tree &&\n+\tsed -e \"s/$tag_commit/$blob/\" <good-tag-tag >broken-tag-tag-blob &&\n+\n+\tsed -e \"s/$commit/$tag_commit/\" <good-commit-tag >broken-commit-tag-tag &&\n+\tsed -e \"s/$commit/$tree/\" <good-commit-tag >broken-commit-tag-tree &&\n+\tsed -e \"s/$commit/$blob/\" <good-commit-tag >broken-commit-tag-blob &&\n+\n+\ttag_tag_commit=$(git hash-object -w -t tag broken-tag-tag-commit) &&\n+\ttag_tag_tree=$(git hash-object -w -t tag broken-tag-tag-tree) &&\n+\ttag_tag_blob=$(git hash-object -w -t tag broken-tag-tag-blob) &&\n+\n+\tcommit_tag_tag=$(git hash-object -w -t tag broken-commit-tag-tag) &&\n+\tcommit_tag_tree=$(git hash-object -w -t tag broken-commit-tag-tree) &&\n+\tcommit_tag_blob=$(git hash-object -w -t tag broken-commit-tag-blob)\n+'\n+\n+test_expect_success 'traverse unexpected incorrectly typed tag (to commit & tag)' '\n+\ttest_must_fail git rev-list --objects $tag_tag_commit 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $commit is a tag, not a commit\n+\tfatal: bad object $commit\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $commit_tag_tag 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $tag_commit is a commit, not a tag\n+\tfatal: bad object $tag_commit\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected incorrectly typed tag (to tree)' '\n+\ttest_must_fail git rev-list --objects $tag_tag_tree 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $tree is a tag, not a tree\n+\tfatal: bad object $tree\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $commit_tag_tree 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $tree is a commit, not a tree\n+\tfatal: bad object $tree\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected incorrectly typed tag (to blob)' '\n+\ttest_must_fail git rev-list --objects $tag_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a tag, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $commit_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a commit, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected non-tag tag (tree seen to blob)' '\n+\ttest_must_fail git rev-list --objects $tree $commit_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a commit, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $tree $tag_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a tag, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected non-tag tag (blob seen to blob)' '\n+\ttest_must_fail git rev-list --objects $blob $commit_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a blob, not a commit\n+\terror: bad tag pointer to $blob in $commit_tag_blob\n+\tfatal: bad object $commit_tag_blob\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $blob $tag_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a blob, not a tag\n+\terror: bad tag pointer to $blob in $tag_tag_blob\n+\tfatal: bad object $tag_tag_blob\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n test_done\n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418522","messageId":"20210308200426.21824-8-avarab@gmail.com","threadId":"1003","inReplyTo":"Pine.LNX.4.21.0506212033590.30848-100000@iabervon.org","subject":"[PATCH 7/7] tag: don't misreport type of tagged objects in errors","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-08T20:04:26Z","receivedAt":"2021-03-08T20:05:47Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a regression in 89e4202f982 ([PATCH] Parse tags for absent\nobjects, 2005-06-21) (yes, that ancient!) and correctly report an\nerror on a tag like:\n\n    object <a tree hash>\n    type commit\n\nAs:\n\n    error: object <a tree hash> is tree, not a commit\n\nInstead of our long-standing misbehavior of inverting the two, and\nreporting:\n\n    error: object <a tree hash> is commit, not a tree\n\nWhich, as can be trivially seen with 'git cat-file -t <a tree hash>'\nis incorrect.\n\nThe reason for this misreporting is that in parse_tag_buffer() we end\nup doing a lookup_{blob,commit,tag,tree}() depending on what we read\nout of the \"type\" line.\n\nIf we haven't parsed that object before we end up dispatching to the\ntype-specific lookup functions, e.g. this for commit.c in\nlookup_commit_type():\n\n\tstruct object *obj = lookup_object(r, oid);\n\tif (!obj)\n\t\treturn create_object(r, oid, alloc_commit_node(r));\n\nIts allocation will then set the obj->type according to what the tag\ntold us the type was, but which we've never validated. At this point\nwe've got an object in memory that hasn't been parsed, and whose type\nis incorrect, since we mistrusted a tag to tell us the type.\n\nThen when we actually load the object with parse_object() we read it\nand find that it's a \"tree\". See 8ff226a9d5e (add object_as_type\nhelper for casting objects, 2014-07-13) for that behavior (that's just\na refactoring commit, but shows all the code involved).\n\nWhich explains why we inverted the error report. Normally when\nobject_as_type() is called it's by the lookup_{blob,commit,tag,tree}()\nfunctions via parse_object(). At that point we can trust the\nobj->type.\n\nIn the case of parsing objects we've learned about via a tag with an\nincorrect type it's the opposite, the obj->type isn't correct and\nholds the mislabeled type, but we're parsing the object and know for\nsure what object type we're dealing with.\n\nHence the non-intuitive solution of adding a\nlookup_{blob,commit,tag,tree}_type() function. It's to distinguish\nparse_object_buffer() where we actually know the type from\nparse_tag_buffer() where we're just guessing about the type.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n blob.c                                 | 16 +++++++++++++++-\n blob.h                                 |  3 +++\n commit.c                               | 14 +++++++++++++-\n commit.h                               |  2 ++\n object.c                               |  8 ++++----\n t/t6102-rev-list-unexpected-objects.sh | 16 ++++++++--------\n tag.c                                  | 14 +++++++++++++-\n tag.h                                  |  2 ++\n tree.c                                 | 14 +++++++++++++-\n tree.h                                 |  2 ++\n 10 files changed, 75 insertions(+), 16 deletions(-)\n\ndiff --git a/blob.c b/blob.c\nindex 182718aba9f..b233e0daa2f 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -2,17 +2,31 @@\n #include \"blob.h\"\n #include \"repository.h\"\n #include \"alloc.h\"\n+#include \"object-store.h\"\n \n const char *blob_type = \"blob\";\n \n-struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n+struct blob *lookup_blob_type(struct repository *r,\n+\t\t\t      const struct object_id *oid,\n+\t\t\t      enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_blob_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_BLOB;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_BLOB, 0);\n }\n \n+struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_blob_type(r, oid, OBJ_NONE);\n+}\n+\n int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n {\n \titem->object.parsed = 1;\ndiff --git a/blob.h b/blob.h\nindex 16648720557..066a2effcbf 100644\n--- a/blob.h\n+++ b/blob.h\n@@ -10,6 +10,9 @@ struct blob {\n };\n \n struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n+struct blob *lookup_blob_type(struct repository *r,\n+\t\t\t      const struct object_id *oid,\n+\t\t\t      enum object_type type);\n \n int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n \ndiff --git a/commit.c b/commit.c\nindex 54627b546c3..30cc990d003 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -57,14 +57,26 @@ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref\n \treturn c;\n }\n \n-struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n+struct commit *lookup_commit_type(struct repository *r, const struct object_id *oid,\n+\t\t\t\t  enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_commit_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_COMMIT;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_COMMIT, 0);\n }\n \n+struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_commit_type(r, oid, OBJ_NONE);\n+}\n+\n struct commit *lookup_commit_reference_by_name(const char *name)\n {\n \tstruct object_id oid;\ndiff --git a/commit.h b/commit.h\nindex 49c0f503964..9b92f661836 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -64,6 +64,8 @@ void add_name_decoration(enum decoration_type type, const char *name, struct obj\n const struct name_decoration *get_name_decoration(const struct object *obj);\n \n struct commit *lookup_commit(struct repository *r, const struct object_id *oid);\n+struct commit *lookup_commit_type(struct repository *r, const struct object_id *oid,\n+\t\t\t\t  enum object_type type);\n struct commit *lookup_commit_reference(struct repository *r,\n \t\t\t\t       const struct object_id *oid);\n struct commit *lookup_commit_reference_gently(struct repository *r,\ndiff --git a/object.c b/object.c\nindex 819ee0faa26..1a45b149e08 100644\n--- a/object.c\n+++ b/object.c\n@@ -227,14 +227,14 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \n \tobj = NULL;\n \tif (type == OBJ_BLOB) {\n-\t\tstruct blob *blob = lookup_blob(r, oid);\n+\t\tstruct blob *blob = lookup_blob_type(r, oid, type);\n \t\tif (blob) {\n \t\t\tif (parse_blob_buffer(blob, buffer, size))\n \t\t\t\treturn NULL;\n \t\t\tobj = &blob->object;\n \t\t}\n \t} else if (type == OBJ_TREE) {\n-\t\tstruct tree *tree = lookup_tree(r, oid);\n+\t\tstruct tree *tree = lookup_tree_type(r, oid, type);\n \t\tif (tree) {\n \t\t\tobj = &tree->object;\n \t\t\tif (!tree->buffer)\n@@ -246,7 +246,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \t\t\t}\n \t\t}\n \t} else if (type == OBJ_COMMIT) {\n-\t\tstruct commit *commit = lookup_commit(r, oid);\n+\t\tstruct commit *commit = lookup_commit_type(r, oid, type);\n \t\tif (commit) {\n \t\t\tif (parse_commit_buffer(r, commit, buffer, size, 1))\n \t\t\t\treturn NULL;\n@@ -257,7 +257,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \t\t\tobj = &commit->object;\n \t\t}\n \t} else if (type == OBJ_TAG) {\n-\t\tstruct tag *tag = lookup_tag(r, oid);\n+\t\tstruct tag *tag = lookup_tag_type(r, oid, type);\n \t\tif (tag) {\n \t\t\tif (parse_tag_buffer(r, tag, buffer, size))\n \t\t\t       return NULL;\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 2ea1982b9ed..4a6b3cc3b01 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -156,14 +156,14 @@ test_expect_success 'setup unexpected non-tag tag' '\n test_expect_success 'traverse unexpected incorrectly typed tag (to commit & tag)' '\n \ttest_must_fail git rev-list --objects $tag_tag_commit 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $commit is a tag, not a commit\n+\terror: object $commit is a commit, not a tag\n \tfatal: bad object $commit\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $commit_tag_tag 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $tag_commit is a commit, not a tag\n+\terror: object $tag_commit is a tag, not a commit\n \tfatal: bad object $tag_commit\n \tEOF\n \ttest_cmp expected err\n@@ -172,14 +172,14 @@ test_expect_success 'traverse unexpected incorrectly typed tag (to commit & tag)\n test_expect_success 'traverse unexpected incorrectly typed tag (to tree)' '\n \ttest_must_fail git rev-list --objects $tag_tag_tree 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $tree is a tag, not a tree\n+\terror: object $tree is a tree, not a tag\n \tfatal: bad object $tree\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $commit_tag_tree 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $tree is a commit, not a tree\n+\terror: object $tree is a tree, not a commit\n \tfatal: bad object $tree\n \tEOF\n \ttest_cmp expected err\n@@ -188,14 +188,14 @@ test_expect_success 'traverse unexpected incorrectly typed tag (to tree)' '\n test_expect_success 'traverse unexpected incorrectly typed tag (to blob)' '\n \ttest_must_fail git rev-list --objects $tag_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a tag, not a blob\n+\terror: object $blob is a blob, not a tag\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $commit_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a commit, not a blob\n+\terror: object $blob is a blob, not a commit\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err\n@@ -204,14 +204,14 @@ test_expect_success 'traverse unexpected incorrectly typed tag (to blob)' '\n test_expect_success 'traverse unexpected non-tag tag (tree seen to blob)' '\n \ttest_must_fail git rev-list --objects $tree $commit_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a commit, not a blob\n+\terror: object $blob is a blob, not a commit\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $tree $tag_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a tag, not a blob\n+\terror: object $blob is a blob, not a tag\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err\ndiff --git a/tag.c b/tag.c\nindex 3e18a418414..0ef87897b29 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -99,14 +99,26 @@ struct object *deref_tag_noverify(struct object *o)\n \treturn o;\n }\n \n-struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n+struct tag *lookup_tag_type(struct repository *r, const struct object_id *oid,\n+\t\t\t    enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_tag_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_TAG;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n+struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_tag_type(r, oid, OBJ_NONE);\n+}\n+\n static timestamp_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\ndiff --git a/tag.h b/tag.h\nindex 3ce8e721924..42bd3e64011 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -12,6 +12,8 @@ struct tag {\n \ttimestamp_t date;\n };\n struct tag *lookup_tag(struct repository *r, const struct object_id *oid);\n+struct tag *lookup_tag_type(struct repository *r, const struct object_id *oid,\n+\t\t\t    enum object_type type);\n int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size);\n int parse_tag(struct tag *item);\n void release_tag_memory(struct tag *t);\ndiff --git a/tree.c b/tree.c\nindex d9b1c70b28a..895c66420e8 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -195,14 +195,26 @@ int read_tree(struct repository *r, struct tree *tree, int stage,\n \treturn 0;\n }\n \n-struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n+struct tree *lookup_tree_type(struct repository *r, const struct object_id *oid,\n+\t\t\t      enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_tree_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_TREE;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_TREE, 0);\n }\n \n+struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_tree_type(r, oid, OBJ_NONE);\n+}\n+\n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n {\n \tif (item->object.parsed)\ndiff --git a/tree.h b/tree.h\nindex 3eb0484cbf2..49bd44f79b3 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -15,6 +15,8 @@ struct tree {\n extern const char *tree_type;\n \n struct tree *lookup_tree(struct repository *r, const struct object_id *oid);\n+struct tree *lookup_tree_type(struct repository *r, const struct object_id *oid,\n+\t\t\t      enum object_type type);\n \n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);\n \n-- \n2.31.0.rc1.210.g0f8085a843c\n\n"},{"id":"418529","messageId":"YEaOeK96r2oo7cbS@nand.local","threadId":"1003","inReplyTo":"20210308200426.21824-2-avarab@gmail.com","subject":"Re: [PATCH 1/7] object.c: refactor type_from_string_gently()","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-03-08T20:52:08Z","receivedAt":"2021-03-08T20:53:06Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Mar 08, 2021 at 09:04:20PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> Get rid of the \"gently\" argument to type_from_string_gently() to make\n> it consistent with most other *_gently() functions.\n>\n> This refactoring of adding a third parameter was done in\n> fe8e3b71805 (Refactor type_from_string() to allow continuing after\n> detecting an error, 2014-09-10) in preparation for its use in\n> fsck.c.\n\nMakes sense. I don't think it hurts to mention that fe8e3b71805 also\nwrote the implementation of type_from_string() as:\n\n  #define type_from_string(str) type_from_string_gently(str, -1, 0)\n\nmaking it the only caller to pass '0' for the 'gentle' parameter. So by\nimplementing it as a function in terms of type_from_string_gently()\nwhich checks for a negative return value, we can drop the 'gentle'\nparameter entirely.\n\nMakes sense.\n\nThanks,\nTaylor\n"},{"id":"418532","messageId":"YEaPcFTenqbUGC2C@nand.local","threadId":"1003","inReplyTo":"20210308200426.21824-3-avarab@gmail.com","subject":"Re: [PATCH 2/7] object.c: make type_from_string() return \"enum object_type\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-03-08T20:56:57Z","receivedAt":"2021-03-08T20:57:56Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Mar 08, 2021 at 09:04:21PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> Change the type_from_string*() functions to return an \"enum\n> object_type\", and refactor their callers to check for \"== OBJ_BAD\"\n> instead of \"< 0\".\n>\n> This helps to distinguish code in object.c where we really do return\n> -1 from code that returns an \"enum object_type\", whose OBJ_BAD happens\n> to be -1.\n\nI'm not sure I understand the intention of this and the following few\npatches. I could imagine that you eventually want to use other negative\nreturn values for a different purpose, but OBJ_BAD _is_ '-1' (as you\nnote), and we use 'int' and 'enum object_type' interchangeably in other\nparts of the code.\n\nThat's not to say that I'm necessarily opposed to picking up these few\npatches, but rather that I don't fully understand their purpose.\n\nThe patch below looks good.\n\nThanks,\nTaylor\n"},{"id":"418534","messageId":"YEaQTK2BWrf1/cpY@nand.local","threadId":"1003","inReplyTo":"20210308200426.21824-6-avarab@gmail.com","subject":"Re: [PATCH 5/7] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2021-03-08T20:59:56Z","receivedAt":"2021-03-08T21:00:56Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Mar 08, 2021 at 09:04:24PM +0100, Ævar Arnfjörð Bjarmason wrote:\n> Refactor various \"Object X is not Y\" error messages so that they use\n> the same message as the long-standing object_as_type() error\n> message. Now we'll consistently report e.g. that we got a commit when\n> we expected a tag, not just that the object is not a tag.\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  builtin/index-pack.c |  9 +++------\n>  commit.c             | 10 ++++------\n>  object.c             | 34 +++++++++++++++++++++++++++++++++-\n>  object.h             |  5 +++++\n>  tree.c               |  7 ++++---\n>  5 files changed, 49 insertions(+), 16 deletions(-)\n>\n> diff --git a/builtin/index-pack.c b/builtin/index-pack.c\n> index 253cfb07fbd..d9082831bb2 100644\n> --- a/builtin/index-pack.c\n> +++ b/builtin/index-pack.c\n> @@ -217,8 +217,8 @@ static int mark_link(struct object *obj, int type, void *data, struct fsck_optio\n>  \tif (!obj)\n>  \t\treturn -1;\n>\n> -\tif (type != OBJ_ANY && obj->type != type)\n> -\t\tdie(_(\"object type mismatch at %s\"), oid_to_hex(&obj->oid));\n> +\tif (type != OBJ_ANY)\n> +\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n\nNice. This is definitely an improvement over the existing code.\n\n> +static const char *oid_is_a_X_not_a_Y = N_(\"object %s is a %s, not a %s\");\n> +\n\nThis name is a little verbose. I'm nitpicking, of course, but would you\nconsider \"object_type_mismatch_msg\" instead?\n\n>  const char *type_name(unsigned int type)\n>  {\n>  \tif (type >= ARRAY_SIZE(object_type_strings))\n> @@ -159,6 +161,36 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n>  \treturn obj;\n>  }\n>\n> +static int oid_is_type_or(const struct object_id *oid,\n> +\t\t\t  enum object_type want,\n> +\t\t\t  enum object_type type,\n> +\t\t\t  int err)\n> +{\n> +\tif (want == type)\n> +\t\treturn 0;\n> +\tif (err)\n> +\t\treturn error(_(oid_is_a_X_not_a_Y),\n> +\t\t\t     oid_to_hex(oid), type_name(type),\n> +\t\t\t     type_name(want));\n> +\telse\n> +\t\tdie(_(oid_is_a_X_not_a_Y), oid_to_hex(oid),\n> +\t\t    type_name(type), type_name(want));\n> +}\n> +\n> +void oid_is_type_or_die(const struct object_id *oid,\n> +\t\t\tenum object_type want,\n> +\t\t\tenum object_type *type)\n> +{\n> +\toid_is_type_or(oid, want, *type, 0);\n> +}\n> +\n> +int oid_is_type_or_error(const struct object_id *oid,\n> +\t\t\t enum object_type want,\n> +\t\t\t enum object_type *type)\n> +{\n> +\treturn oid_is_type_or(oid, want, *type, 1);\n> +}\n> +\n\nI'm not sure that this oid_is_type_or() is really doing all that much.\nIt allows you to share the 'if (want == type)' conditional between the\nother two functions, but the rest of the function is a conditional\nitself that behaves differently depending on whether you called the\n_die() or _error() variant.\n\nWhy not duplicate the 'if (want == type)' between the two functions, and\nthen remove 'oid_is_type_or()' altogether?\n\nThanks,\nTaylor\n"},{"id":"418538","messageId":"xmqq1rcp5nbk.fsf@gitster.c.googlers.com","threadId":"1003","inReplyTo":"20210308200426.21824-3-avarab@gmail.com","subject":"Re: [PATCH 2/7] object.c: make type_from_string() return \"enum object_type\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-08T21:48:31Z","receivedAt":"2021-03-08T21:49:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the type_from_string*() functions to return an \"enum\n> object_type\", and refactor their callers to check for \"== OBJ_BAD\"\n> instead of \"< 0\".\n>\n> This helps to distinguish code in object.c where we really do return\n> -1 from code that returns an \"enum object_type\", whose OBJ_BAD happens\n> to be -1.\n\n\"We will be adding different error modes and the plan is to signal\nthem by returning negative values other than -1\" would make sense\n(if that is what we are going to see in the remainder of the\nseries), but not the above.\n\nTo the callees, what comes back from a function is -1 either way,\nand they cannot tell -1 resulting from OBJ_BAD and -1 resulting from\nerror() apart, can they?\n\n"},{"id":"418540","messageId":"xmqqwnuh48gd.fsf@gitster.c.googlers.com","threadId":"1003","inReplyTo":"20210308200426.21824-4-avarab@gmail.com","subject":"Re: [PATCH 3/7] oid_object_info(): return \"enum object_type\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-08T21:54:58Z","receivedAt":"2021-03-08T21:55:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change oid_object_info() to return an \"enum object_type\", this is what\n> it did anyway, except that it hardcoded -1 instead of an\n> OBJ_BAD.\n>\n> Let's instead have it return the \"enum object_type\", at which point\n> callers will expect OBJ_BAD. This allows for refactoring code that\n> e.g. expected any \"< 0\" value, but would only have to deal with\n> OBJ_BAD (= -1).\n\nHmph, I have a mixed feeling about this.\n\n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index 5ebf13359e8..1d989c62a4e 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -133,7 +133,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \n>  \tcase 'p':\n>  \t\ttype = oid_object_info(the_repository, &oid, NULL);\n> -\t\tif (type < 0)\n> +\t\tif (type == OBJ_BAD)\n>  \t\t\tdie(\"Not a valid object name %s\", obj_name);\n\nSo, when oid_object_info() starts to return different negative value\nto signal new kinds of errors, this codepath need to be changed, or\nthe control falls through to the rest of the case arm, which would\nbe worse than what the current code does (which is to die with less\nspecific error message).\n\n> -\t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n> -\t\tif (type <= 0)\n> +\t\tenum object_type type = oid_object_info(the_repository, &obj->oid, &size);\n> +\t\tif (type == OBJ_BAD)\n>  \t\t\tdie(_(\"did not receive expected object %s\"),\n>  \t\t\t      oid_to_hex(&obj->oid));\n\nDitto.\n\nAnd the issue is the same for all the other explicit comparison with\nOBJ_BAD.  If we do it the other way around, i.e. leave these callers\nas they are and add new negative return values to the function first,\nand then convert \"if negative, say error\" to \"if OBJ_BAD, say so,\nelse if we have this new type of error, say so\", then the risk of\nmistake becomes smaller.\n\nBut hopefully any such potential issue will be resolved by the end\nof this short series, so as long as it won't be left as technical\ndebt, I am OK.\n"},{"id":"418543","messageId":"xmqqsg5547iu.fsf@gitster.c.googlers.com","threadId":"1003","inReplyTo":"20210308200426.21824-6-avarab@gmail.com","subject":"Re: [PATCH 5/7] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-08T22:15:05Z","receivedAt":"2021-03-08T22:15:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Refactor various \"Object X is not Y\" error messages so that they use\n> the same message as the long-standing object_as_type() error\n> message. Now we'll consistently report e.g. that we got a commit when\n> we expected a tag, not just that the object is not a tag.\n\nThis one is quite nice.  There might be some i18n fallout to do this\nat this low layer, but everything should be manageable (i.e. we can\njust tell the users \"don't parse the die() message---they are meant\nfor humans\") immediately, and in the longer term, we probably would\nwant to move away from dying at this low level anyway and instead\nreturn an error for the higher layer to deal with.\n\n> +static const char *oid_is_a_X_not_a_Y = N_(\"object %s is a %s, not a %s\");\n> +\n>  const char *type_name(unsigned int type)\n>  {\n>  \tif (type >= ARRAY_SIZE(object_type_strings))\n> @@ -159,6 +161,36 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n>  \treturn obj;\n>  }\n>  \n> +static int oid_is_type_or(const struct object_id *oid,\n> +\t\t\t  enum object_type want,\n> +\t\t\t  enum object_type type,\n> +\t\t\t  int err)\n\n\"err\" is usually called \"gently\" in this codebase, isn't it?\n\n> +{\n> +\tif (want == type)\n> +\t\treturn 0;\n> +\tif (err)\n> +\t\treturn error(_(oid_is_a_X_not_a_Y),\n> +\t\t\t     oid_to_hex(oid), type_name(type),\n> +\t\t\t     type_name(want));\n\nJust a style thing, but breaking line after oid like you did on the\nother \"!err\" side makes it a lot more readable.\n\n> +\telse\n> +\t\tdie(_(oid_is_a_X_not_a_Y), oid_to_hex(oid),\n> +\t\t    type_name(type), type_name(want));\n> +}\n"},{"id":"418545","messageId":"xmqqo8ft46pw.fsf@gitster.c.googlers.com","threadId":"1003","inReplyTo":"xmqqwnuh48gd.fsf@gitster.c.googlers.com","subject":"Re: [PATCH 3/7] oid_object_info(): return \"enum object_type\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-08T22:32:27Z","receivedAt":"2021-03-08T22:33:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> And the issue is the same for all the other explicit comparison with\n> OBJ_BAD.  If we do it the other way around, i.e. leave these callers\n> as they are and add new negative return values to the function first,\n> and then convert \"if negative, say error\" to \"if OBJ_BAD, say so,\n> else if we have this new type of error, say so\", then the risk of\n> mistake becomes smaller.\n>\n> But hopefully any such potential issue will be resolved by the end\n> of this short series, so as long as it won't be left as technical\n> debt, I am OK.\n\nAnd after reading through the topic to the end, it turns out that\nthe code did not add new error return value.  So while it probably\nis a good idea to make oid_object_info() to return the enum, I am\nnot convinced that the updates to the caller that used to check for\nthe negativeness is an improvement.  Rewriting the ones that used to\ncompare with -1 for equality to instead compare with OBJ_BAD would\nbe very much welcome, though.\n\n"},{"id":"418586","messageId":"YEdPLEgjzPT/jWxC@coredump.intra.peff.net","threadId":"1003","inReplyTo":"20210308200426.21824-4-avarab@gmail.com","subject":"Re: [PATCH 3/7] oid_object_info(): return \"enum object_type\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-09T10:34:20Z","receivedAt":"2021-03-09T10:34:57Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 08, 2021 at 09:04:22PM +0100, Ævar Arnfjörð Bjarmason wrote:\n\n> Change oid_object_info() to return an \"enum object_type\", this is what\n> it did anyway, except that it hardcoded -1 instead of an\n> OBJ_BAD.\n\nIt does return -1 in the error case, and otherwise returns the \"type\"\nfield it got from the odb-specific fields. Which presumably is always\ngreater than 0, but...\n\n> Let's instead have it return the \"enum object_type\", at which point\n> callers will expect OBJ_BAD. This allows for refactoring code that\n> e.g. expected any \"< 0\" value, but would only have to deal with\n> OBJ_BAD (= -1).\n\nSome of these conversions are not just \"< 0\", like:\n\n> diff --git a/builtin/index-pack.c b/builtin/index-pack.c\n> index bad57488079..253cfb07fbd 100644\n> --- a/builtin/index-pack.c\n> +++ b/builtin/index-pack.c\n> @@ -236,8 +236,8 @@ static unsigned check_object(struct object *obj)\n>  \n>  \tif (!(obj->flags & FLAG_CHECKED)) {\n>  \t\tunsigned long size;\n> -\t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n> -\t\tif (type <= 0)\n> +\t\tenum object_type type = oid_object_info(the_repository, &obj->oid, &size);\n> +\t\tif (type == OBJ_BAD)\n\nI kind of doubt that we could get OBJ_NONE here, but it seems like a\nmuch riskier change than just \"let's prefer OBJ_BAD to -1\".\n\nDid you trace through all of the paths that oid_object_info() can end up\nin? (I did very briefly and I _think_ it's OK, but...).\n\n-Peff\n"},{"id":"418587","messageId":"YEdRhulqevMjlrLc@coredump.intra.peff.net","threadId":"1003","inReplyTo":"20210308200426.21824-7-avarab@gmail.com","subject":"Re: [PATCH 6/7] object tests: add test for unexpected objects in tags","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-09T10:44:22Z","receivedAt":"2021-03-09T10:45:16Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 08, 2021 at 09:04:25PM +0100, Ævar Arnfjörð Bjarmason wrote:\n\n> Fix a blind spot in the tests added in 0616617c7e1 (t: introduce tests\n> for unexpected object types, 2019-04-09), there were no meaningful\n> tests for checking how we reported on finding the incorrect object\n> type in a tag, i.e. one that broke the \"type\" promise in the tag\n> header.\n\nIsn't this covered by tests 16 and 17 (\"traverse unexpected non-commit\ntag\", both \"lone\" and \"seen\")? And likewise the matching \"non-tree\" and\n\"non-blob\" variants afterwards?\n\nThe only thing we don't seem to cover is an unexpected non-tag. I don't\nmind adding that, but why wouldn't we just follow the template of the\nexisting tests?\n\n-Peff\n"},{"id":"418588","messageId":"YEdR7oAcu13F8/d5@coredump.intra.peff.net","threadId":"1003","inReplyTo":"20210308200426.21824-2-avarab@gmail.com","subject":"Re: [PATCH 1/7] object.c: refactor type_from_string_gently()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-09T10:46:06Z","receivedAt":"2021-03-09T10:46:53Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 08, 2021 at 09:04:20PM +0100, Ævar Arnfjörð Bjarmason wrote:\n\n> Get rid of the \"gently\" argument to type_from_string_gently() to make\n> it consistent with most other *_gently() functions.\n> \n> This refactoring of adding a third parameter was done in\n> fe8e3b71805 (Refactor type_from_string() to allow continuing after\n> detecting an error, 2014-09-10) in preparation for its use in\n> fsck.c.\n> \n> Since then no callers of this function have passed a \"len < 0\" as was\n> expected might happen, so we can simplify its invocation by knowing\n> that it's never called like that.\n\nThis final paragraph confused me. What does \"len < 0\" have to do with\n\"gently\"?\n\nI think the answer is just that the non-gentle form never bothered to\ntake a \"len\" parameter, so you are doing both simplifications at once.\nIMHO it would be easier to understand broken into two commits (but not\nnecessarily worth re-rolling).\n\n-Peff\n"},{"id":"420327","messageId":"87h7kwnjpp.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"YEdRhulqevMjlrLc@coredump.intra.peff.net","subject":"Re: [PATCH 6/7] object tests: add test for unexpected objects in tags","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T01:35:46Z","receivedAt":"2021-03-28T01:36:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, Mar 09 2021, Jeff King wrote:\n\n> On Mon, Mar 08, 2021 at 09:04:25PM +0100, Ævar Arnfjörð Bjarmason wrote:\n>\n>> Fix a blind spot in the tests added in 0616617c7e1 (t: introduce tests\n>> for unexpected object types, 2019-04-09), there were no meaningful\n>> tests for checking how we reported on finding the incorrect object\n>> type in a tag, i.e. one that broke the \"type\" promise in the tag\n>> header.\n>\n> Isn't this covered by tests 16 and 17 (\"traverse unexpected non-commit\n> tag\", both \"lone\" and \"seen\")? And likewise the matching \"non-tree\" and\n> \"non-blob\" variants afterwards?\n\nBarely, those tests are mainly testing that rev-list doesn't die, and\nonly do a very fuzzy match on the output. E.g. checking `grep \"not a\ncommit\" err`, not a full test_cmp that'll check what OID is reported\netc.\n\n> The only thing we don't seem to cover is an unexpected non-tag. I don't\n> mind adding that, but why wouldn't we just follow the template of the\n> existing tests?\n\nI am following that template to some extent, e.g. using\n${commit,tree,blob}. It just didn't seem worth it to refactor an earlier\ntest in the file just to re-use a single hash-object invocation, those\ntests e.g. clobber the $tag variable, so bending over backwards to\nre-use anything set up in them would mean some refactoring.\n\nI think it's much clearer just do do all the different kinds of setup in\nthe new setup function.\n"},{"id":"420332","messageId":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"20210308200426.21824-1-avarab@gmail.com","subject":"[PATCH v2 00/10] improve reporting of unexpected objects","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:30Z","receivedAt":"2021-03-28T02:14:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As noted in v1[1] this is some s/int/enum object_type/ refactoring,\nand finally fixing an issue with our error reporting about corrupt\ntags being wrong.\n\nThis should address all the feedback I got about the v1. Thanks\neveryone, and sorry about the time it took to re-roll this.\n\n1. http://lore.kernel.org/git/20210308200426.21824-1-avarab@gmail.com\n\n*** BLURB HERE ***\n\nÆvar Arnfjörð Bjarmason (10):\n  object.c: stop supporting len == -1 in type_from_string_gently()\n  object.c: refactor type_from_string_gently()\n  object.c: make type_from_string() return \"enum object_type\"\n  object-file.c: make oid_object_info() return \"enum object_type\"\n  object-name.c: make dependency on object_type order more obvious\n  tree.c: fix misindentation in parse_tree_gently()\n  object.c: add a utility function for \"expected type X, got Y\"\n  object.c: add and use oid_is_type_or_die_msg() function\n  object tests: add test for unexpected objects in tags\n  tag: don't misreport type of tagged objects in errors\n\n blob.c                                 |  16 +++-\n blob.h                                 |   3 +\n builtin/blame.c                        |   2 +-\n builtin/index-pack.c                   |  11 +--\n combine-diff.c                         |   3 +-\n commit.c                               |  24 ++++--\n commit.h                               |   2 +\n fsck.c                                 |   2 +-\n merge-recursive.c                      |   5 +-\n object-file.c                          |  10 +--\n object-name.c                          |  25 +++---\n object-store.h                         |   4 +-\n object.c                               |  65 +++++++++++---\n object.h                               |  12 ++-\n packfile.c                             |   2 +-\n t/t6102-rev-list-unexpected-objects.sh | 113 ++++++++++++++++++++++++-\n tag.c                                  |  14 ++-\n tag.h                                  |   2 +\n tree.c                                 |  27 ++++--\n tree.h                                 |   2 +\n 20 files changed, 279 insertions(+), 65 deletions(-)\n\nRange-diff:\n -:  ----------- >  1:  e51c860a65d object.c: stop supporting len == -1 in type_from_string_gently()\n 1:  1f50a33ab5c !  2:  3e3979b6b35 object.c: refactor type_from_string_gently()\n    @@ Commit message\n         detecting an error, 2014-09-10) in preparation for its use in\n         fsck.c.\n     \n    -    Since then no callers of this function have passed a \"len < 0\" as was\n    -    expected might happen, so we can simplify its invocation by knowing\n    -    that it's never called like that.\n    +    Simplifying this means we can move the die() into the simpler\n    +    type_from_string() function.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ object.c: const char *type_name(unsigned int type)\n      {\n      \tint i;\n      \n    --\tif (len < 0)\n    --\t\tlen = strlen(str);\n    --\n    - \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n    +@@ object.c: int type_from_string_gently(const char *str, ssize_t len, int gentle)\n      \t\tif (!strncmp(str, object_type_strings[i], len) &&\n      \t\t    object_type_strings[i][len] == '\\0')\n      \t\t\treturn i;\n    -+\treturn -1;\n    -+}\n    - \n    +-\n     -\tif (gentle)\n     -\t\treturn -1;\n     -\n     -\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n    -+int type_from_string(const char *str)\n    -+{\n    -+\tsize_t len = strlen(str);\n    ++\treturn -1;\n    + }\n    + \n    + int type_from_string(const char *str)\n    + {\n    + \tsize_t len = strlen(str);\n    +-\tint ret = type_from_string_gently(str, len, 0);\n     +\tint ret = type_from_string_gently(str, len);\n     +\tif (ret < 0)\n     +\t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n    -+\treturn ret;\n    + \treturn ret;\n      }\n      \n    - /*\n     \n      ## object.h ##\n     @@ object.h: struct object {\n    @@ object.h: struct object {\n      \n      const char *type_name(unsigned int type);\n     -int type_from_string_gently(const char *str, ssize_t, int gentle);\n    --#define type_from_string(str) type_from_string_gently(str, -1, 0)\n     +int type_from_string_gently(const char *str, ssize_t len);\n    -+int type_from_string(const char *str);\n    + int type_from_string(const char *str);\n      \n      /*\n    -  * Return the current number of buckets in the object hashmap.\n 2:  a4e444f9274 !  3:  5615730f023 object.c: make type_from_string() return \"enum object_type\"\n    @@ Commit message\n         object.c: make type_from_string() return \"enum object_type\"\n     \n         Change the type_from_string*() functions to return an \"enum\n    -    object_type\", and refactor their callers to check for \"== OBJ_BAD\"\n    -    instead of \"< 0\".\n    +    object_type\", but don't refactor their callers to check for \"==\n    +    OBJ_BAD\" instead of \"< 0\".\n     \n    -    This helps to distinguish code in object.c where we really do return\n    -    -1 from code that returns an \"enum object_type\", whose OBJ_BAD happens\n    -    to be -1.\n    +    Refactoring the check of the return value to check == OBJ_BAD would\n    +    now be equivalent to \"ret < 0\", but the consensus on an earlier\n    +    version of this patch was to not do that, and to instead use -1\n    +    consistently as a return value. It just so happens that OBJ_BAD == -1,\n    +    but let's not put a hard reliance on that.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## fsck.c ##\n    -@@ fsck.c: int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n    - \t\tgoto done;\n    - \t}\n    - \t*tagged_type = type_from_string_gently(buffer, eol - buffer);\n    --\tif (*tagged_type < 0)\n    -+\tif (*tagged_type == OBJ_BAD)\n    - \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, \"invalid 'type' value\");\n    - \tif (ret)\n    - \t\tgoto done;\n    -\n    - ## object-file.c ##\n    -@@ object-file.c: static int parse_loose_header_extended(const char *hdr, struct object_info *oi,\n    - \t */\n    - \tif ((flags & OBJECT_INFO_ALLOW_UNKNOWN_TYPE) && (type < 0))\n    - \t\ttype = 0;\n    --\telse if (type < 0)\n    -+\telse if (type == OBJ_BAD)\n    - \t\tdie(_(\"invalid object type\"));\n    - \tif (oi->typep)\n    - \t\t*oi->typep = type;\n    -\n      ## object.c ##\n     @@ object.c: const char *type_name(unsigned int type)\n      \treturn object_type_strings[type];\n    @@ object.c: const char *type_name(unsigned int type)\n      \n      \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n      \t\tif (!strncmp(str, object_type_strings[i], len) &&\n    - \t\t    object_type_strings[i][len] == '\\0')\n    - \t\t\treturn i;\n    --\treturn -1;\n    -+\treturn OBJ_BAD;\n    +@@ object.c: int type_from_string_gently(const char *str, ssize_t len)\n    + \treturn -1;\n      }\n      \n     -int type_from_string(const char *str)\n    @@ object.c: const char *type_name(unsigned int type)\n      {\n      \tsize_t len = strlen(str);\n     -\tint ret = type_from_string_gently(str, len);\n    --\tif (ret < 0)\n     +\tenum object_type ret = type_from_string_gently(str, len);\n    -+\tif (ret == OBJ_BAD)\n    + \tif (ret < 0)\n      \t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n      \treturn ret;\n    - }\n     \n      ## object.h ##\n     @@ object.h: struct object {\n 3:  309fb7b71e7 !  4:  c10082f4fac oid_object_info(): return \"enum object_type\"\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    oid_object_info(): return \"enum object_type\"\n    +    object-file.c: make oid_object_info() return \"enum object_type\"\n     \n    -    Change oid_object_info() to return an \"enum object_type\", this is what\n    -    it did anyway, except that it hardcoded -1 instead of an\n    -    OBJ_BAD.\n    -\n    -    Let's instead have it return the \"enum object_type\", at which point\n    -    callers will expect OBJ_BAD. This allows for refactoring code that\n    -    e.g. expected any \"< 0\" value, but would only have to deal with\n    -    OBJ_BAD (= -1).\n    +    Change oid_object_info() to return an \"enum object_type\". Unlike\n    +    oid_object_info_extended() function the simpler oid_object_info()\n    +    explicitly returns the oi.typep member, which is itself an \"enum\n    +    object_type\".\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    @@ builtin/blame.c: static int peel_to_commit_oid(struct object_id *oid_ret, void *\n      \t\t\toidcpy(oid_ret, &oid);\n      \t\t\treturn 0;\n     \n    - ## builtin/cat-file.c ##\n    -@@ builtin/cat-file.c: static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n    - \n    - \tcase 'p':\n    - \t\ttype = oid_object_info(the_repository, &oid, NULL);\n    --\t\tif (type < 0)\n    -+\t\tif (type == OBJ_BAD)\n    - \t\t\tdie(\"Not a valid object name %s\", obj_name);\n    - \n    - \t\t/* custom pretty-print here */\n    -\n      ## builtin/index-pack.c ##\n     @@ builtin/index-pack.c: static unsigned check_object(struct object *obj)\n      \n      \tif (!(obj->flags & FLAG_CHECKED)) {\n      \t\tunsigned long size;\n     -\t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n    --\t\tif (type <= 0)\n     +\t\tenum object_type type = oid_object_info(the_repository, &obj->oid, &size);\n    -+\t\tif (type == OBJ_BAD)\n    + \t\tif (type <= 0)\n      \t\t\tdie(_(\"did not receive expected object %s\"),\n      \t\t\t      oid_to_hex(&obj->oid));\n    - \t\tif (type != obj->type)\n    -@@ builtin/index-pack.c: static void sha1_object(const void *data, struct object_entry *obj_entry,\n    - \t\tunsigned long has_size;\n    - \t\tread_lock();\n    - \t\thas_type = oid_object_info(the_repository, oid, &has_size);\n    --\t\tif (has_type < 0)\n    -+\t\tif (has_type == OBJ_BAD)\n    - \t\t\tdie(_(\"cannot read existing object info %s\"), oid_to_hex(oid));\n    - \t\tif (has_type != type || has_size != size)\n    - \t\t\tdie(_(\"SHA1 COLLISION FOUND WITH %s !\"), oid_to_hex(oid));\n    -\n    - ## builtin/mktree.c ##\n    -@@ builtin/mktree.c: static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n    - \n    - \t/* Check the type of object identified by sha1 */\n    - \tobj_type = oid_object_info(the_repository, &oid, NULL);\n    --\tif (obj_type < 0) {\n    -+\tif (obj_type == OBJ_BAD) {\n    - \t\tif (allow_missing) {\n    - \t\t\t; /* no problem - missing objects are presumed to be of the right type */\n    - \t\t} else {\n    -\n    - ## builtin/pack-objects.c ##\n    -@@ builtin/pack-objects.c: unsigned long oe_get_size_slow(struct packing_data *pack,\n    - \n    - \tif (e->type_ != OBJ_OFS_DELTA && e->type_ != OBJ_REF_DELTA) {\n    - \t\tpacking_data_lock(&to_pack);\n    --\t\tif (oid_object_info(the_repository, &e->idx.oid, &size) < 0)\n    -+\t\tif (oid_object_info(the_repository, &e->idx.oid, &size) == OBJ_BAD)\n    - \t\t\tdie(_(\"unable to get size of %s\"),\n    - \t\t\t    oid_to_hex(&e->idx.oid));\n    - \t\tpacking_data_unlock(&to_pack);\n    -@@ builtin/pack-objects.c: static int add_loose_object(const struct object_id *oid, const char *path,\n    - {\n    - \tenum object_type type = oid_object_info(the_repository, oid, NULL);\n    - \n    --\tif (type < 0) {\n    -+\tif (type == OBJ_BAD) {\n    - \t\twarning(_(\"loose object at %s could not be examined\"), path);\n    - \t\treturn 0;\n    - \t}\n    -\n    - ## builtin/replace.c ##\n    -@@ builtin/replace.c: static int edit_and_replace(const char *object_ref, int force, int raw)\n    - \t\treturn error(_(\"not a valid object name: '%s'\"), object_ref);\n    - \n    - \ttype = oid_object_info(the_repository, &old_oid, NULL);\n    --\tif (type < 0)\n    -+\tif (type == OBJ_BAD)\n    - \t\treturn error(_(\"unable to get object type for %s\"),\n    - \t\t\t     oid_to_hex(&old_oid));\n    - \n    -\n    - ## builtin/tag.c ##\n    -@@ builtin/tag.c: static void create_tag(const struct object_id *object, const char *object_ref,\n    - \tchar *path = NULL;\n    - \n    - \ttype = oid_object_info(the_repository, object, NULL);\n    --\tif (type <= OBJ_NONE)\n    -+\tif (type == OBJ_BAD)\n    - \t\tdie(_(\"bad object type.\"));\n    - \n    - \tif (type == OBJ_TAG)\n    -\n    - ## builtin/unpack-objects.c ##\n    -@@ builtin/unpack-objects.c: static int check_object(struct object *obj, int type, void *data, struct fsck_op\n    - \tif (!(obj->flags & FLAG_OPEN)) {\n    - \t\tunsigned long size;\n    - \t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n    --\t\tif (type != obj->type || type <= 0)\n    -+\t\tif (type == OBJ_BAD)\n    -+\t\t\tdie(_(\"unable to get object type for %s\"),\n    -+\t\t\t    oid_to_hex(&obj->oid));\n    -+\t\tif (type != obj->type)\n    -+\t\t\t/* todo to new function */\n    - \t\t\tdie(\"object of unexpected type\");\n    - \t\tobj->flags |= FLAG_WRITTEN;\n    - \t\treturn 0;\n     \n      ## object-file.c ##\n     @@ object-file.c: int oid_object_info_extended(struct repository *r, const struct object_id *oid,\n    + \treturn ret;\n      }\n      \n    - \n    +-\n     -/* returns enum object_type or negative */\n     -int oid_object_info(struct repository *r,\n     -\t\t    const struct object_id *oid,\n    @@ object-file.c: int oid_object_info_extended(struct repository *r, const struct o\n      {\n      \tenum object_type type;\n      \tstruct object_info oi = OBJECT_INFO_INIT;\n    -@@ object-file.c: int oid_object_info(struct repository *r,\n    - \toi.sizep = sizep;\n    - \tif (oid_object_info_extended(r, oid, &oi,\n    - \t\t\t\t      OBJECT_INFO_LOOKUP_REPLACE) < 0)\n    --\t\treturn -1;\n    -+\t\treturn OBJ_BAD;\n    - \treturn type;\n    - }\n    - \n    -@@ object-file.c: int read_pack_header(int fd, struct pack_header *header)\n    - void assert_oid_type(const struct object_id *oid, enum object_type expect)\n    - {\n    - \tenum object_type type = oid_object_info(the_repository, oid, NULL);\n    --\tif (type < 0)\n    -+\tif (type == OBJ_BAD)\n    - \t\tdie(_(\"%s is not a valid object\"), oid_to_hex(oid));\n    - \tif (type != expect)\n    - \t\tdie(_(\"%s is not a valid '%s' object\"), oid_to_hex(oid),\n     \n      ## object-name.c ##\n     @@ object-name.c: static int disambiguate_committish_only(struct repository *r,\n    @@ object-name.c: static int disambiguate_committish_only(struct repository *r,\n      {\n      \tstruct object *obj;\n     -\tint kind;\n    -+\tenum object_type kind;\n    ++\tenum object_type kind = oid_object_info(r, oid, NULL);\n      \n    - \tkind = oid_object_info(r, oid, NULL);\n    +-\tkind = oid_object_info(r, oid, NULL);\n      \tif (kind == OBJ_COMMIT)\n    + \t\treturn 1;\n    + \tif (kind != OBJ_TAG)\n     @@ object-name.c: static int disambiguate_tree_only(struct repository *r,\n      \t\t\t\t  const struct object_id *oid,\n      \t\t\t\t  void *cb_data_unused)\n    @@ object-store.h: static inline void *repo_read_object_file(struct repository *r,\n      \n      /* Read and unpack an object file into memory, write memory to an object file */\n     -int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n    -+enum object_type oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n    ++enum object_type oid_object_info(struct repository *r,\n    ++\t\t\t\t const struct object_id *,\n    ++\t\t\t\t unsigned long *);\n      \n      int hash_object_file(const struct git_hash_algo *algo, const void *buf,\n      \t\t     unsigned long len, const char *type,\n    @@ packfile.c: static int retry_bad_packed_offset(struct repository *r,\n      \tuint32_t pos;\n      \tstruct object_id oid;\n      \tif (offset_to_pack_pos(p, obj_offset, &pos) < 0)\n    -@@ packfile.c: static int retry_bad_packed_offset(struct repository *r,\n    - \tnth_packed_object_id(&oid, p, pack_pos_to_index(p, pos));\n    - \tmark_bad_packed_object(p, oid.hash);\n    - \ttype = oid_object_info(r, &oid, NULL);\n    --\tif (type <= OBJ_NONE)\n    --\t\treturn OBJ_BAD;\n    - \treturn type;\n    - }\n    - \n    -\n    - ## reachable.c ##\n    -@@ reachable.c: static void add_recent_object(const struct object_id *oid,\n    - \t * commits and tags to have been parsed.\n    - \t */\n    - \ttype = oid_object_info(the_repository, oid, NULL);\n    --\tif (type < 0)\n    --\t\tdie(\"unable to get object info for %s\", oid_to_hex(oid));\n    - \n    - \tswitch (type) {\n    - \tcase OBJ_TAG:\n    -@@ reachable.c: static void add_recent_object(const struct object_id *oid,\n    - \tcase OBJ_BLOB:\n    - \t\tobj = (struct object *)lookup_blob(the_repository, oid);\n    - \t\tbreak;\n    -+\tcase OBJ_BAD:\n    -+\t\tdie(\"unable to get object info for %s\", oid_to_hex(oid));\n    -+\t\tbreak;\n    - \tdefault:\n    - \t\tdie(\"unknown object type for %s: %s\",\n    - \t\t    oid_to_hex(oid), type_name(type));\n -:  ----------- >  5:  1ebcf1416b8 object-name.c: make dependency on object_type order more obvious\n 4:  e93881ed264 =  6:  464c9e35256 tree.c: fix misindentation in parse_tree_gently()\n 5:  bed81215646 !  7:  4bf29cbb383 object.c: add a utility function for \"expected type X, got Y\"\n    @@ builtin/index-pack.c: static int mark_link(struct object *obj, int type, void *d\n      \tobj->flags |= FLAG_LINK;\n      \treturn 0;\n     @@ builtin/index-pack.c: static unsigned check_object(struct object *obj)\n    - \t\tif (type == OBJ_BAD)\n    + \t\tif (type <= 0)\n      \t\t\tdie(_(\"did not receive expected object %s\"),\n      \t\t\t      oid_to_hex(&obj->oid));\n     -\t\tif (type != obj->type)\n    @@ builtin/index-pack.c: static unsigned check_object(struct object *obj)\n      \t\treturn 1;\n      \t}\n     \n    + ## combine-diff.c ##\n    +@@ combine-diff.c: static char *grab_blob(struct repository *r,\n    + \t\tfree_filespec(df);\n    + \t} else {\n    + \t\tblob = read_object_file(oid, &type, size);\n    +-\t\tif (type != OBJ_BLOB)\n    +-\t\t\tdie(\"object '%s' is not a blob!\", oid_to_hex(oid));\n    ++\t\toid_is_type_or_die(oid, OBJ_BLOB, &type);\n    + \t}\n    + \treturn blob;\n    + }\n    +\n      ## commit.c ##\n     @@ commit.c: const void *repo_get_commit_buffer(struct repository *r,\n      \t\tif (!ret)\n    @@ commit.c: int repo_parse_commit_internal(struct repository *r,\n      \n      \tret = parse_commit_buffer(r, item, buffer, size, 0);\n     \n    + ## merge-recursive.c ##\n    +@@ merge-recursive.c: static int read_oid_strbuf(struct merge_options *opt,\n    + \tif (!buf)\n    + \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n    + \tif (type != OBJ_BLOB) {\n    ++\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n    + \t\tfree(buf);\n    + \t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n    + \t}\n    +\n      ## object.c ##\n    -@@ object.c: static const char *object_type_strings[] = {\n    - \t\"tag\",\t\t/* OBJ_TAG = 4 */\n    - };\n    - \n    -+static const char *oid_is_a_X_not_a_Y = N_(\"object %s is a %s, not a %s\");\n    -+\n    - const char *type_name(unsigned int type)\n    - {\n    - \tif (type >= ARRAY_SIZE(object_type_strings))\n     @@ object.c: void *create_object(struct repository *r, const struct object_id *oid, void *o)\n      \treturn obj;\n      }\n      \n    -+static int oid_is_type_or(const struct object_id *oid,\n    -+\t\t\t  enum object_type want,\n    -+\t\t\t  enum object_type type,\n    -+\t\t\t  int err)\n    -+{\n    -+\tif (want == type)\n    -+\t\treturn 0;\n    -+\tif (err)\n    -+\t\treturn error(_(oid_is_a_X_not_a_Y),\n    -+\t\t\t     oid_to_hex(oid), type_name(type),\n    -+\t\t\t     type_name(want));\n    -+\telse\n    -+\t\tdie(_(oid_is_a_X_not_a_Y), oid_to_hex(oid),\n    -+\t\t    type_name(type), type_name(want));\n    -+}\n    ++static const char *object_type_mismatch_msg = N_(\"object %s is a %s, not a %s\");\n     +\n     +void oid_is_type_or_die(const struct object_id *oid,\n     +\t\t\tenum object_type want,\n     +\t\t\tenum object_type *type)\n     +{\n    -+\toid_is_type_or(oid, want, *type, 0);\n    ++\tif (want == *type)\n    ++\t\treturn;\n    ++\tdie(_(object_type_mismatch_msg), oid_to_hex(oid),\n    ++\t    type_name(*type), type_name(want));\n     +}\n     +\n     +int oid_is_type_or_error(const struct object_id *oid,\n     +\t\t\t enum object_type want,\n     +\t\t\t enum object_type *type)\n     +{\n    -+\treturn oid_is_type_or(oid, want, *type, 1);\n    ++\tif (want == *type)\n    ++\t\treturn 0;\n    ++\treturn error(_(object_type_mismatch_msg),\n    ++\t\t     oid_to_hex(oid), type_name(*type),\n    ++\t\t     type_name(want));\n     +}\n     +\n      void *object_as_type(struct object *obj, enum object_type type, int quiet)\n    @@ object.c: void *object_as_type(struct object *obj, enum object_type type, int qu\n      \telse {\n      \t\tif (!quiet)\n     -\t\t\terror(_(\"object %s is a %s, not a %s\"),\n    -+\t\t\terror(_(oid_is_a_X_not_a_Y),\n    ++\t\t\terror(_(object_type_mismatch_msg),\n      \t\t\t      oid_to_hex(&obj->oid),\n      \t\t\t      type_name(obj->type), type_name(type));\n      \t\treturn NULL;\n -:  ----------- >  8:  351a8ec79c8 object.c: add and use oid_is_type_or_die_msg() function\n 6:  6d34b2b80db =  9:  6a43bf897ae object tests: add test for unexpected objects in tags\n 7:  f93236c25fd ! 10:  a84f670ac24 tag: don't misreport type of tagged objects in errors\n    @@ Commit message\n     \n         Hence the non-intuitive solution of adding a\n         lookup_{blob,commit,tag,tree}_type() function. It's to distinguish\n    -    parse_object_buffer() where we actually know the type from\n    -    parse_tag_buffer() where we're just guessing about the type.\n    +    calls from parse_object_buffer() where we actually know the type, from\n    +    a parse_tag_buffer() where we're just guessing about the type.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420333","messageId":"patch-03.11-5615730f023-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 03/10] object.c: make type_from_string() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:33Z","receivedAt":"2021-03-28T02:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the type_from_string*() functions to return an \"enum\nobject_type\", but don't refactor their callers to check for \"==\nOBJ_BAD\" instead of \"< 0\".\n\nRefactoring the check of the return value to check == OBJ_BAD would\nnow be equivalent to \"ret < 0\", but the consensus on an earlier\nversion of this patch was to not do that, and to instead use -1\nconsistently as a return value. It just so happens that OBJ_BAD == -1,\nbut let's not put a hard reliance on that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 8 ++++----\n object.h | 4 ++--\n 2 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 1c36ea606f2..c0e68d4bbf6 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,9 +35,9 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, ssize_t len)\n+enum object_type type_from_string_gently(const char *str, ssize_t len)\n {\n-\tint i;\n+\tenum object_type i;\n \n \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n@@ -46,10 +46,10 @@ int type_from_string_gently(const char *str, ssize_t len)\n \treturn -1;\n }\n \n-int type_from_string(const char *str)\n+enum object_type type_from_string(const char *str)\n {\n \tsize_t len = strlen(str);\n-\tint ret = type_from_string_gently(str, len);\n+\tenum object_type ret = type_from_string_gently(str, len);\n \tif (ret < 0)\n \t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n \treturn ret;\ndiff --git a/object.h b/object.h\nindex ffdc1298300..5e7a523e858 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,8 +93,8 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, ssize_t len);\n-int type_from_string(const char *str);\n+enum object_type type_from_string_gently(const char *str, ssize_t len);\n+enum object_type type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420334","messageId":"patch-01.11-e51c860a65d-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 01/10] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:31Z","receivedAt":"2021-03-28T02:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the type_from_string() macro into a function and drop the\nsupport for passing len < 0.\n\nSupport for len < 0 was added in fe8e3b71805 (Refactor\ntype_from_string() to allow continuing after detecting an error,\n2014-09-10), but no callers use that form. Let's drop it to simplify\nthis, and in preparation for simplifying these even further.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 10 +++++++---\n object.h |  2 +-\n 2 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 78343781ae7..65446172172 100644\n--- a/object.c\n+++ b/object.c\n@@ -39,9 +39,6 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n {\n \tint i;\n \n-\tif (len < 0)\n-\t\tlen = strlen(str);\n-\n \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n \t\t    object_type_strings[i][len] == '\\0')\n@@ -53,6 +50,13 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n \tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n }\n \n+int type_from_string(const char *str)\n+{\n+\tsize_t len = strlen(str);\n+\tint ret = type_from_string_gently(str, len, 0);\n+\treturn ret;\n+}\n+\n /*\n  * Return a numerical hash value between 0 and n-1 for the object with\n  * the specified sha1.  n must be a power of 2.  Please note that the\ndiff --git a/object.h b/object.h\nindex 59daadce214..3ab3eb193d3 100644\n--- a/object.h\n+++ b/object.h\n@@ -94,7 +94,7 @@ struct object {\n \n const char *type_name(unsigned int type);\n int type_from_string_gently(const char *str, ssize_t, int gentle);\n-#define type_from_string(str) type_from_string_gently(str, -1, 0)\n+int type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420335","messageId":"patch-04.11-c10082f4fac-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 04/10] object-file.c: make oid_object_info() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:34Z","receivedAt":"2021-03-28T02:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change oid_object_info() to return an \"enum object_type\". Unlike\noid_object_info_extended() function the simpler oid_object_info()\nexplicitly returns the oi.typep member, which is itself an \"enum\nobject_type\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/blame.c      |  2 +-\n builtin/index-pack.c |  2 +-\n object-file.c        |  8 +++-----\n object-name.c        | 19 +++++++++----------\n object-store.h       |  4 +++-\n packfile.c           |  2 +-\n 6 files changed, 18 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 641523ff9af..5dd3c38a8c6 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -810,7 +810,7 @@ static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)\n \toidcpy(&oid, oid_ret);\n \twhile (1) {\n \t\tstruct object *obj;\n-\t\tint kind = oid_object_info(r, &oid, NULL);\n+\t\tenum object_type kind = oid_object_info(r, &oid, NULL);\n \t\tif (kind == OBJ_COMMIT) {\n \t\t\toidcpy(oid_ret, &oid);\n \t\t\treturn 0;\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 21899687e2c..17376db1e39 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -236,7 +236,7 @@ static unsigned check_object(struct object *obj)\n \n \tif (!(obj->flags & FLAG_CHECKED)) {\n \t\tunsigned long size;\n-\t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n+\t\tenum object_type type = oid_object_info(the_repository, &obj->oid, &size);\n \t\tif (type <= 0)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\ndiff --git a/object-file.c b/object-file.c\nindex b7c26b67355..8ed54d6f621 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1572,11 +1572,9 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,\n \treturn ret;\n }\n \n-\n-/* returns enum object_type or negative */\n-int oid_object_info(struct repository *r,\n-\t\t    const struct object_id *oid,\n-\t\t    unsigned long *sizep)\n+enum object_type oid_object_info(struct repository *r,\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t unsigned long *sizep)\n {\n \tenum object_type type;\n \tstruct object_info oi = OBJECT_INFO_INIT;\ndiff --git a/object-name.c b/object-name.c\nindex 64202de60b1..4d7f0c66cf2 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -239,9 +239,8 @@ static int disambiguate_committish_only(struct repository *r,\n \t\t\t\t\tvoid *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \n-\tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_COMMIT)\n \t\treturn 1;\n \tif (kind != OBJ_TAG)\n@@ -258,7 +257,7 @@ static int disambiguate_tree_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_TREE;\n }\n \n@@ -267,7 +266,7 @@ static int disambiguate_treeish_only(struct repository *r,\n \t\t\t\t     void *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind;\n \n \tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_TREE || kind == OBJ_COMMIT)\n@@ -286,7 +285,7 @@ static int disambiguate_blob_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_BLOB;\n }\n \n@@ -361,7 +360,7 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n {\n \tconst struct disambiguate_state *ds = data;\n \tstruct strbuf desc = STRBUF_INIT;\n-\tint type;\n+\tenum object_type type;\n \n \tif (ds->fn && !ds->fn(ds->repo, oid, ds->cb_data))\n \t\treturn 0;\n@@ -405,10 +404,10 @@ static int repo_collect_ambiguous(struct repository *r,\n static int sort_ambiguous(const void *a, const void *b, void *ctx)\n {\n \tstruct repository *sort_ambiguous_repo = ctx;\n-\tint a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n-\tint b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n-\tint a_type_sort;\n-\tint b_type_sort;\n+\tenum object_type a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n+\tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n+\tenum object_type a_type_sort;\n+\tenum object_type b_type_sort;\n \n \t/*\n \t * Sorts by hash within the same object type, just as\ndiff --git a/object-store.h b/object-store.h\nindex ec32c23dcb5..eab9674d085 100644\n--- a/object-store.h\n+++ b/object-store.h\n@@ -208,7 +208,9 @@ static inline void *repo_read_object_file(struct repository *r,\n #endif\n \n /* Read and unpack an object file into memory, write memory to an object file */\n-int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n+enum object_type oid_object_info(struct repository *r,\n+\t\t\t\t const struct object_id *,\n+\t\t\t\t unsigned long *);\n \n int hash_object_file(const struct git_hash_algo *algo, const void *buf,\n \t\t     unsigned long len, const char *type,\ndiff --git a/packfile.c b/packfile.c\nindex 6661f3325a4..3ee01ea7323 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1266,7 +1266,7 @@ static int retry_bad_packed_offset(struct repository *r,\n \t\t\t\t   struct packed_git *p,\n \t\t\t\t   off_t obj_offset)\n {\n-\tint type;\n+\tenum object_type type;\n \tuint32_t pos;\n \tstruct object_id oid;\n \tif (offset_to_pack_pos(p, obj_offset, &pos) < 0)\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420336","messageId":"patch-06.11-464c9e35256-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 06/10] tree.c: fix misindentation in parse_tree_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:36Z","receivedAt":"2021-03-28T02:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The variables declared in parse_tree_gently() had a single space after\nthe TAB. This dates back to their introduction in bd2c39f58f9 ([PATCH]\ndon't load and decompress objects twice with parse_object(),\n2005-05-06). Let's fix them to follow the style of the rest of the\nfile.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n tree.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex a52479812ce..4820d66a10c 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -216,9 +216,9 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n \n int parse_tree_gently(struct tree *item, int quiet_on_missing)\n {\n-\t enum object_type type;\n-\t void *buffer;\n-\t unsigned long size;\n+\tenum object_type type;\n+\tvoid *buffer;\n+\tunsigned long size;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420337","messageId":"patch-05.11-1ebcf1416b8-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 05/10] object-name.c: make dependency on object_type order more obvious","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:35Z","receivedAt":"2021-03-28T02:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add an assert to make it more obvious that we were effectively\nhardcoding OBJ_TAG in sort_ambiguous() as \"4\".\n\nI wrote this code in 5cc044e0257 (get_short_oid: sort ambiguous\nobjects by type, then SHA-1, 2018-05-10), there was already a comment\nabout this magic, but let's make sure that someone doing a potential\nreordering of \"enum object_type\" in the future would notice it\nbreaking this function (and probably a bunch of other things...).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object-name.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 4d7f0c66cf2..b6a7328b7a7 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -408,6 +408,8 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)\n \tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n \tenum object_type a_type_sort;\n \tenum object_type b_type_sort;\n+\tconst enum object_type tag_type_offs = OBJ_TAG - OBJ_NONE;\n+\tassert(tag_type_offs == 4);\n \n \t/*\n \t * Sorts by hash within the same object type, just as\n@@ -425,8 +427,8 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)\n \t * cleverly) do that with modulus, since the enum assigns 1 to\n \t * commit, so tag becomes 0.\n \t */\n-\ta_type_sort = a_type % 4;\n-\tb_type_sort = b_type % 4;\n+\ta_type_sort = a_type % tag_type_offs;\n+\tb_type_sort = b_type % tag_type_offs;\n \treturn a_type_sort > b_type_sort ? 1 : -1;\n }\n \n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420339","messageId":"patch-07.11-4bf29cbb383-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 07/10] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:37Z","receivedAt":"2021-03-28T02:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor various \"Object X is not Y\" error messages so that they use\nthe same message as the long-standing object_as_type() error\nmessage. Now we'll consistently report e.g. that we got a commit when\nwe expected a tag, not just that the object is not a tag.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/index-pack.c |  9 +++------\n combine-diff.c       |  3 +--\n commit.c             | 10 ++++------\n merge-recursive.c    |  1 +\n object.c             | 25 ++++++++++++++++++++++++-\n object.h             |  5 +++++\n tree.c               |  7 ++++---\n 7 files changed, 42 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 17376db1e39..2a7a4df5f16 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -217,8 +217,8 @@ static int mark_link(struct object *obj, int type, void *data, struct fsck_optio\n \tif (!obj)\n \t\treturn -1;\n \n-\tif (type != OBJ_ANY && obj->type != type)\n-\t\tdie(_(\"object type mismatch at %s\"), oid_to_hex(&obj->oid));\n+\tif (type != OBJ_ANY)\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \n \tobj->flags |= FLAG_LINK;\n \treturn 0;\n@@ -240,10 +240,7 @@ static unsigned check_object(struct object *obj)\n \t\tif (type <= 0)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\n-\t\tif (type != obj->type)\n-\t\t\tdie(_(\"object %s: expected type %s, found %s\"),\n-\t\t\t    oid_to_hex(&obj->oid),\n-\t\t\t    type_name(obj->type), type_name(type));\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \t\tobj->flags |= FLAG_CHECKED;\n \t\treturn 1;\n \t}\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 06635f91bc2..aa767dbb8ea 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -333,8 +333,7 @@ static char *grab_blob(struct repository *r,\n \t\tfree_filespec(df);\n \t} else {\n \t\tblob = read_object_file(oid, &type, size);\n-\t\tif (type != OBJ_BLOB)\n-\t\t\tdie(\"object '%s' is not a blob!\", oid_to_hex(oid));\n+\t\toid_is_type_or_die(oid, OBJ_BLOB, &type);\n \t}\n \treturn blob;\n }\ndiff --git a/commit.c b/commit.c\nindex 8ea55a447fa..b3701003678 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -299,9 +299,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \t\tif (!ret)\n \t\t\tdie(\"cannot read commit object %s\",\n \t\t\t    oid_to_hex(&commit->object.oid));\n-\t\tif (type != OBJ_COMMIT)\n-\t\t\tdie(\"expected commit for %s, got %s\",\n-\t\t\t    oid_to_hex(&commit->object.oid), type_name(type));\n+\t\toid_is_type_or_die(&commit->object.oid, OBJ_COMMIT, &type);\n \t\tif (sizep)\n \t\t\t*sizep = size;\n \t}\n@@ -489,10 +487,10 @@ int repo_parse_commit_internal(struct repository *r,\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_COMMIT) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_COMMIT, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a commit\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \n \tret = parse_commit_buffer(r, item, buffer, size, 0);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex b69e694d986..feb9bfeb8af 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2971,6 +2971,7 @@ static int read_oid_strbuf(struct merge_options *opt,\n \tif (!buf)\n \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n \tif (type != OBJ_BLOB) {\n+\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n \t\tfree(buf);\n \t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n \t}\ndiff --git a/object.c b/object.c\nindex c0e68d4bbf6..fa18b243280 100644\n--- a/object.c\n+++ b/object.c\n@@ -159,6 +159,29 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n \treturn obj;\n }\n \n+static const char *object_type_mismatch_msg = N_(\"object %s is a %s, not a %s\");\n+\n+void oid_is_type_or_die(const struct object_id *oid,\n+\t\t\tenum object_type want,\n+\t\t\tenum object_type *type)\n+{\n+\tif (want == *type)\n+\t\treturn;\n+\tdie(_(object_type_mismatch_msg), oid_to_hex(oid),\n+\t    type_name(*type), type_name(want));\n+}\n+\n+int oid_is_type_or_error(const struct object_id *oid,\n+\t\t\t enum object_type want,\n+\t\t\t enum object_type *type)\n+{\n+\tif (want == *type)\n+\t\treturn 0;\n+\treturn error(_(object_type_mismatch_msg),\n+\t\t     oid_to_hex(oid), type_name(*type),\n+\t\t     type_name(want));\n+}\n+\n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n \tif (obj->type == type)\n@@ -172,7 +195,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n \t}\n \telse {\n \t\tif (!quiet)\n-\t\t\terror(_(\"object %s is a %s, not a %s\"),\n+\t\t\terror(_(object_type_mismatch_msg),\n \t\t\t      oid_to_hex(&obj->oid),\n \t\t\t      type_name(obj->type), type_name(type));\n \t\treturn NULL;\ndiff --git a/object.h b/object.h\nindex 5e7a523e858..d2d4a236d0e 100644\n--- a/object.h\n+++ b/object.h\n@@ -124,6 +124,11 @@ void *create_object(struct repository *r, const struct object_id *oid, void *obj\n \n void *object_as_type(struct object *obj, enum object_type type, int quiet);\n \n+void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n+\t\t\tenum object_type *type);\n+int oid_is_type_or_error(const struct object_id *oid, enum object_type want,\n+\t\t\t enum object_type *type);\n+\n /*\n  * Returns the object, having parsed it to find out what it is.\n  *\ndiff --git a/tree.c b/tree.c\nindex 4820d66a10c..d9b1c70b28a 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -219,6 +219,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \tenum object_type type;\n \tvoid *buffer;\n \tunsigned long size;\n+\tint ret;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n@@ -227,10 +228,10 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_TREE) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_TREE, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a tree\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \treturn parse_tree_buffer(item, buffer, size);\n }\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420340","messageId":"patch-02.11-3e3979b6b35-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 02/10] object.c: refactor type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:32Z","receivedAt":"2021-03-28T02:15:24Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Get rid of the \"gently\" argument to type_from_string_gently() to make\nit consistent with most other *_gently() functions.\n\nThis refactoring of adding a third parameter was done in\nfe8e3b71805 (Refactor type_from_string() to allow continuing after\ndetecting an error, 2014-09-10) in preparation for its use in\nfsck.c.\n\nSimplifying this means we can move the die() into the simpler\ntype_from_string() function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n fsck.c        |  2 +-\n object-file.c |  2 +-\n object.c      | 12 +++++-------\n object.h      |  2 +-\n 4 files changed, 8 insertions(+), 10 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex e3030f3b358..6cc4f9ea892 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -957,7 +957,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, \"invalid format - unexpected end after 'type' line\");\n \t\tgoto done;\n \t}\n-\t*tagged_type = type_from_string_gently(buffer, eol - buffer, 1);\n+\t*tagged_type = type_from_string_gently(buffer, eol - buffer);\n \tif (*tagged_type < 0)\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, \"invalid 'type' value\");\n \tif (ret)\ndiff --git a/object-file.c b/object-file.c\nindex 624af408cdc..b7c26b67355 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1314,7 +1314,7 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,\n \t\ttype_len++;\n \t}\n \n-\ttype = type_from_string_gently(type_buf, type_len, 1);\n+\ttype = type_from_string_gently(type_buf, type_len);\n \tif (oi->type_name)\n \t\tstrbuf_add(oi->type_name, type_buf, type_len);\n \t/*\ndiff --git a/object.c b/object.c\nindex 65446172172..1c36ea606f2 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,7 +35,7 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, ssize_t len, int gentle)\n+int type_from_string_gently(const char *str, ssize_t len)\n {\n \tint i;\n \n@@ -43,17 +43,15 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n \t\t    object_type_strings[i][len] == '\\0')\n \t\t\treturn i;\n-\n-\tif (gentle)\n-\t\treturn -1;\n-\n-\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n+\treturn -1;\n }\n \n int type_from_string(const char *str)\n {\n \tsize_t len = strlen(str);\n-\tint ret = type_from_string_gently(str, len, 0);\n+\tint ret = type_from_string_gently(str, len);\n+\tif (ret < 0)\n+\t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n \treturn ret;\n }\n \ndiff --git a/object.h b/object.h\nindex 3ab3eb193d3..ffdc1298300 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,7 +93,7 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, ssize_t, int gentle);\n+int type_from_string_gently(const char *str, ssize_t len);\n int type_from_string(const char *str);\n \n /*\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420338","messageId":"patch-08.11-351a8ec79c8-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 08/10] object.c: add and use oid_is_type_or_die_msg() function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:38Z","receivedAt":"2021-03-28T02:15:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a oid_is_type_or_die_msg() function to go with the \"error\" and\n\"die\" forms for emitting \"expected type X, got Y\" messages. This is\nuseful for callers that want the message itself as a char *.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n merge-recursive.c |  6 ++++--\n object.c          | 12 ++++++++++++\n object.h          |  3 +++\n 3 files changed, 19 insertions(+), 2 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex feb9bfeb8af..152e63e4436 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2971,9 +2971,11 @@ static int read_oid_strbuf(struct merge_options *opt,\n \tif (!buf)\n \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n \tif (type != OBJ_BLOB) {\n-\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n+\t\tchar *msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n+\t\tint ret = err(opt, msg);\n \t\tfree(buf);\n-\t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n+\t\tfree(msg);\n+\t\treturn ret;\n \t}\n \tstrbuf_attach(dst, buf, size, size + 1);\n \treturn 0;\ndiff --git a/object.c b/object.c\nindex fa18b243280..0f60743e61f 100644\n--- a/object.c\n+++ b/object.c\n@@ -182,6 +182,18 @@ int oid_is_type_or_error(const struct object_id *oid,\n \t\t     type_name(want));\n }\n \n+char* oid_is_type_or_die_msg(const struct object_id *oid,\n+\t\t\t\t   enum object_type want,\n+\t\t\t\t   enum object_type *type)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tif (want == *type)\n+\t\tBUG(\"call this just to get the message!\");\n+\tstrbuf_addf(&sb, _(object_type_mismatch_msg), oid_to_hex(oid),\n+\t\t    type_name(*type), type_name(want));\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n \tif (obj->type == type)\ndiff --git a/object.h b/object.h\nindex d2d4a236d0e..cdc3242a128 100644\n--- a/object.h\n+++ b/object.h\n@@ -128,6 +128,9 @@ void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n \t\t\tenum object_type *type);\n int oid_is_type_or_error(const struct object_id *oid, enum object_type want,\n \t\t\t enum object_type *type);\n+char* oid_is_type_or_die_msg(const struct object_id *oid,\n+\t\t\t     enum object_type want,\n+\t\t\t     enum object_type *type);\n \n /*\n  * Returns the object, having parsed it to find out what it is.\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420341","messageId":"patch-10.11-a84f670ac24-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:40Z","receivedAt":"2021-03-28T02:15:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a regression in 89e4202f982 ([PATCH] Parse tags for absent\nobjects, 2005-06-21) (yes, that ancient!) and correctly report an\nerror on a tag like:\n\n    object <a tree hash>\n    type commit\n\nAs:\n\n    error: object <a tree hash> is tree, not a commit\n\nInstead of our long-standing misbehavior of inverting the two, and\nreporting:\n\n    error: object <a tree hash> is commit, not a tree\n\nWhich, as can be trivially seen with 'git cat-file -t <a tree hash>'\nis incorrect.\n\nThe reason for this misreporting is that in parse_tag_buffer() we end\nup doing a lookup_{blob,commit,tag,tree}() depending on what we read\nout of the \"type\" line.\n\nIf we haven't parsed that object before we end up dispatching to the\ntype-specific lookup functions, e.g. this for commit.c in\nlookup_commit_type():\n\n\tstruct object *obj = lookup_object(r, oid);\n\tif (!obj)\n\t\treturn create_object(r, oid, alloc_commit_node(r));\n\nIts allocation will then set the obj->type according to what the tag\ntold us the type was, but which we've never validated. At this point\nwe've got an object in memory that hasn't been parsed, and whose type\nis incorrect, since we mistrusted a tag to tell us the type.\n\nThen when we actually load the object with parse_object() we read it\nand find that it's a \"tree\". See 8ff226a9d5e (add object_as_type\nhelper for casting objects, 2014-07-13) for that behavior (that's just\na refactoring commit, but shows all the code involved).\n\nWhich explains why we inverted the error report. Normally when\nobject_as_type() is called it's by the lookup_{blob,commit,tag,tree}()\nfunctions via parse_object(). At that point we can trust the\nobj->type.\n\nIn the case of parsing objects we've learned about via a tag with an\nincorrect type it's the opposite, the obj->type isn't correct and\nholds the mislabeled type, but we're parsing the object and know for\nsure what object type we're dealing with.\n\nHence the non-intuitive solution of adding a\nlookup_{blob,commit,tag,tree}_type() function. It's to distinguish\ncalls from parse_object_buffer() where we actually know the type, from\na parse_tag_buffer() where we're just guessing about the type.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n blob.c                                 | 16 +++++++++++++++-\n blob.h                                 |  3 +++\n commit.c                               | 14 +++++++++++++-\n commit.h                               |  2 ++\n object.c                               |  8 ++++----\n t/t6102-rev-list-unexpected-objects.sh | 16 ++++++++--------\n tag.c                                  | 14 +++++++++++++-\n tag.h                                  |  2 ++\n tree.c                                 | 14 +++++++++++++-\n tree.h                                 |  2 ++\n 10 files changed, 75 insertions(+), 16 deletions(-)\n\ndiff --git a/blob.c b/blob.c\nindex 182718aba9f..b233e0daa2f 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -2,17 +2,31 @@\n #include \"blob.h\"\n #include \"repository.h\"\n #include \"alloc.h\"\n+#include \"object-store.h\"\n \n const char *blob_type = \"blob\";\n \n-struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n+struct blob *lookup_blob_type(struct repository *r,\n+\t\t\t      const struct object_id *oid,\n+\t\t\t      enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_blob_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_BLOB;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_BLOB, 0);\n }\n \n+struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_blob_type(r, oid, OBJ_NONE);\n+}\n+\n int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n {\n \titem->object.parsed = 1;\ndiff --git a/blob.h b/blob.h\nindex 16648720557..066a2effcbf 100644\n--- a/blob.h\n+++ b/blob.h\n@@ -10,6 +10,9 @@ struct blob {\n };\n \n struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n+struct blob *lookup_blob_type(struct repository *r,\n+\t\t\t      const struct object_id *oid,\n+\t\t\t      enum object_type type);\n \n int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n \ndiff --git a/commit.c b/commit.c\nindex b3701003678..ab6cee1e8c3 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -57,14 +57,26 @@ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref\n \treturn c;\n }\n \n-struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n+struct commit *lookup_commit_type(struct repository *r, const struct object_id *oid,\n+\t\t\t\t  enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_commit_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_COMMIT;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_COMMIT, 0);\n }\n \n+struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_commit_type(r, oid, OBJ_NONE);\n+}\n+\n struct commit *lookup_commit_reference_by_name(const char *name)\n {\n \tstruct object_id oid;\ndiff --git a/commit.h b/commit.h\nindex df42eb434f3..9def4f3f19d 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -64,6 +64,8 @@ void add_name_decoration(enum decoration_type type, const char *name, struct obj\n const struct name_decoration *get_name_decoration(const struct object *obj);\n \n struct commit *lookup_commit(struct repository *r, const struct object_id *oid);\n+struct commit *lookup_commit_type(struct repository *r, const struct object_id *oid,\n+\t\t\t\t  enum object_type type);\n struct commit *lookup_commit_reference(struct repository *r,\n \t\t\t\t       const struct object_id *oid);\n struct commit *lookup_commit_reference_gently(struct repository *r,\ndiff --git a/object.c b/object.c\nindex 0f60743e61f..60037422488 100644\n--- a/object.c\n+++ b/object.c\n@@ -230,14 +230,14 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \n \tobj = NULL;\n \tif (type == OBJ_BLOB) {\n-\t\tstruct blob *blob = lookup_blob(r, oid);\n+\t\tstruct blob *blob = lookup_blob_type(r, oid, type);\n \t\tif (blob) {\n \t\t\tif (parse_blob_buffer(blob, buffer, size))\n \t\t\t\treturn NULL;\n \t\t\tobj = &blob->object;\n \t\t}\n \t} else if (type == OBJ_TREE) {\n-\t\tstruct tree *tree = lookup_tree(r, oid);\n+\t\tstruct tree *tree = lookup_tree_type(r, oid, type);\n \t\tif (tree) {\n \t\t\tobj = &tree->object;\n \t\t\tif (!tree->buffer)\n@@ -249,7 +249,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \t\t\t}\n \t\t}\n \t} else if (type == OBJ_COMMIT) {\n-\t\tstruct commit *commit = lookup_commit(r, oid);\n+\t\tstruct commit *commit = lookup_commit_type(r, oid, type);\n \t\tif (commit) {\n \t\t\tif (parse_commit_buffer(r, commit, buffer, size, 1))\n \t\t\t\treturn NULL;\n@@ -260,7 +260,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \t\t\tobj = &commit->object;\n \t\t}\n \t} else if (type == OBJ_TAG) {\n-\t\tstruct tag *tag = lookup_tag(r, oid);\n+\t\tstruct tag *tag = lookup_tag_type(r, oid, type);\n \t\tif (tag) {\n \t\t\tif (parse_tag_buffer(r, tag, buffer, size))\n \t\t\t       return NULL;\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 2ea1982b9ed..4a6b3cc3b01 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -156,14 +156,14 @@ test_expect_success 'setup unexpected non-tag tag' '\n test_expect_success 'traverse unexpected incorrectly typed tag (to commit & tag)' '\n \ttest_must_fail git rev-list --objects $tag_tag_commit 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $commit is a tag, not a commit\n+\terror: object $commit is a commit, not a tag\n \tfatal: bad object $commit\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $commit_tag_tag 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $tag_commit is a commit, not a tag\n+\terror: object $tag_commit is a tag, not a commit\n \tfatal: bad object $tag_commit\n \tEOF\n \ttest_cmp expected err\n@@ -172,14 +172,14 @@ test_expect_success 'traverse unexpected incorrectly typed tag (to commit & tag)\n test_expect_success 'traverse unexpected incorrectly typed tag (to tree)' '\n \ttest_must_fail git rev-list --objects $tag_tag_tree 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $tree is a tag, not a tree\n+\terror: object $tree is a tree, not a tag\n \tfatal: bad object $tree\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $commit_tag_tree 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $tree is a commit, not a tree\n+\terror: object $tree is a tree, not a commit\n \tfatal: bad object $tree\n \tEOF\n \ttest_cmp expected err\n@@ -188,14 +188,14 @@ test_expect_success 'traverse unexpected incorrectly typed tag (to tree)' '\n test_expect_success 'traverse unexpected incorrectly typed tag (to blob)' '\n \ttest_must_fail git rev-list --objects $tag_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a tag, not a blob\n+\terror: object $blob is a blob, not a tag\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $commit_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a commit, not a blob\n+\terror: object $blob is a blob, not a commit\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err\n@@ -204,14 +204,14 @@ test_expect_success 'traverse unexpected incorrectly typed tag (to blob)' '\n test_expect_success 'traverse unexpected non-tag tag (tree seen to blob)' '\n \ttest_must_fail git rev-list --objects $tree $commit_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a commit, not a blob\n+\terror: object $blob is a blob, not a commit\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err &&\n \n \ttest_must_fail git rev-list --objects $tree $tag_tag_blob 2>err &&\n \tcat >expected <<-EOF &&\n-\terror: object $blob is a tag, not a blob\n+\terror: object $blob is a blob, not a tag\n \tfatal: bad object $blob\n \tEOF\n \ttest_cmp expected err\ndiff --git a/tag.c b/tag.c\nindex 3e18a418414..0ef87897b29 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -99,14 +99,26 @@ struct object *deref_tag_noverify(struct object *o)\n \treturn o;\n }\n \n-struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n+struct tag *lookup_tag_type(struct repository *r, const struct object_id *oid,\n+\t\t\t    enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_tag_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_TAG;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \n+struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_tag_type(r, oid, OBJ_NONE);\n+}\n+\n static timestamp_t parse_tag_date(const char *buf, const char *tail)\n {\n \tconst char *dateptr;\ndiff --git a/tag.h b/tag.h\nindex 3ce8e721924..42bd3e64011 100644\n--- a/tag.h\n+++ b/tag.h\n@@ -12,6 +12,8 @@ struct tag {\n \ttimestamp_t date;\n };\n struct tag *lookup_tag(struct repository *r, const struct object_id *oid);\n+struct tag *lookup_tag_type(struct repository *r, const struct object_id *oid,\n+\t\t\t    enum object_type type);\n int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size);\n int parse_tag(struct tag *item);\n void release_tag_memory(struct tag *t);\ndiff --git a/tree.c b/tree.c\nindex d9b1c70b28a..895c66420e8 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -195,14 +195,26 @@ int read_tree(struct repository *r, struct tree *tree, int stage,\n \treturn 0;\n }\n \n-struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n+struct tree *lookup_tree_type(struct repository *r, const struct object_id *oid,\n+\t\t\t      enum object_type type)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_tree_node(r));\n+\tif (type != OBJ_NONE &&\n+\t    obj->type != OBJ_NONE) {\n+\t\tenum object_type want = OBJ_TREE;\n+\t\tif (oid_is_type_or_error(oid, obj->type, &want))\n+\t\t\treturn NULL;\n+\t}\n \treturn object_as_type(obj, OBJ_TREE, 0);\n }\n \n+struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n+{\n+\treturn lookup_tree_type(r, oid, OBJ_NONE);\n+}\n+\n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n {\n \tif (item->object.parsed)\ndiff --git a/tree.h b/tree.h\nindex 3eb0484cbf2..49bd44f79b3 100644\n--- a/tree.h\n+++ b/tree.h\n@@ -15,6 +15,8 @@ struct tree {\n extern const char *tree_type;\n \n struct tree *lookup_tree(struct repository *r, const struct object_id *oid);\n+struct tree *lookup_tree_type(struct repository *r, const struct object_id *oid,\n+\t\t\t      enum object_type type);\n \n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);\n \n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420342","messageId":"patch-09.11-6a43bf897ae-20210328T021238Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH v2 09/10] object tests: add test for unexpected objects in tags","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T02:13:39Z","receivedAt":"2021-03-28T02:15:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a blind spot in the tests added in 0616617c7e1 (t: introduce tests\nfor unexpected object types, 2019-04-09), there were no meaningful\ntests for checking how we reported on finding the incorrect object\ntype in a tag, i.e. one that broke the \"type\" promise in the tag\nheader.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t6102-rev-list-unexpected-objects.sh | 113 ++++++++++++++++++++++++-\n 1 file changed, 112 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 52cde097dd5..2ea1982b9ed 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -31,7 +31,8 @@ test_expect_success 'setup unexpected non-tree entry' '\n '\n \n test_expect_success 'traverse unexpected non-tree entry (lone)' '\n-\ttest_must_fail git rev-list --objects $broken_tree\n+\ttest_must_fail git rev-list --objects $broken_tree >output 2>&1 &&\n+\ttest_i18ngrep \"not a tree\" output\n '\n \n test_expect_success 'traverse unexpected non-tree entry (seen)' '\n@@ -124,4 +125,114 @@ test_expect_success 'traverse unexpected non-blob tag (seen)' '\n \ttest_i18ngrep \"not a blob\" output\n '\n \n+test_expect_success 'setup unexpected non-tag tag' '\n+\ttest_when_finished \"git tag -d tag-commit tag-tag\" &&\n+\n+\tgit tag -a -m\"tagged commit\" tag-commit $commit &&\n+\ttag_commit=$(git rev-parse tag-commit) &&\n+\tgit tag -a -m\"tagged tag\" tag-tag tag-commit &&\n+\ttag_tag=$(git rev-parse tag-tag) &&\n+\n+\tgit cat-file tag tag-tag >good-tag-tag &&\n+\tgit cat-file tag tag-commit >good-commit-tag &&\n+\n+\tsed -e \"s/$tag_commit/$commit/\" <good-tag-tag >broken-tag-tag-commit &&\n+\tsed -e \"s/$tag_commit/$tree/\" <good-tag-tag >broken-tag-tag-tree &&\n+\tsed -e \"s/$tag_commit/$blob/\" <good-tag-tag >broken-tag-tag-blob &&\n+\n+\tsed -e \"s/$commit/$tag_commit/\" <good-commit-tag >broken-commit-tag-tag &&\n+\tsed -e \"s/$commit/$tree/\" <good-commit-tag >broken-commit-tag-tree &&\n+\tsed -e \"s/$commit/$blob/\" <good-commit-tag >broken-commit-tag-blob &&\n+\n+\ttag_tag_commit=$(git hash-object -w -t tag broken-tag-tag-commit) &&\n+\ttag_tag_tree=$(git hash-object -w -t tag broken-tag-tag-tree) &&\n+\ttag_tag_blob=$(git hash-object -w -t tag broken-tag-tag-blob) &&\n+\n+\tcommit_tag_tag=$(git hash-object -w -t tag broken-commit-tag-tag) &&\n+\tcommit_tag_tree=$(git hash-object -w -t tag broken-commit-tag-tree) &&\n+\tcommit_tag_blob=$(git hash-object -w -t tag broken-commit-tag-blob)\n+'\n+\n+test_expect_success 'traverse unexpected incorrectly typed tag (to commit & tag)' '\n+\ttest_must_fail git rev-list --objects $tag_tag_commit 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $commit is a tag, not a commit\n+\tfatal: bad object $commit\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $commit_tag_tag 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $tag_commit is a commit, not a tag\n+\tfatal: bad object $tag_commit\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected incorrectly typed tag (to tree)' '\n+\ttest_must_fail git rev-list --objects $tag_tag_tree 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $tree is a tag, not a tree\n+\tfatal: bad object $tree\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $commit_tag_tree 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $tree is a commit, not a tree\n+\tfatal: bad object $tree\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected incorrectly typed tag (to blob)' '\n+\ttest_must_fail git rev-list --objects $tag_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a tag, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $commit_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a commit, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected non-tag tag (tree seen to blob)' '\n+\ttest_must_fail git rev-list --objects $tree $commit_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a commit, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $tree $tag_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a tag, not a blob\n+\tfatal: bad object $blob\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n+test_expect_success 'traverse unexpected non-tag tag (blob seen to blob)' '\n+\ttest_must_fail git rev-list --objects $blob $commit_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a blob, not a commit\n+\terror: bad tag pointer to $blob in $commit_tag_blob\n+\tfatal: bad object $commit_tag_blob\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git rev-list --objects $blob $tag_tag_blob 2>err &&\n+\tcat >expected <<-EOF &&\n+\terror: object $blob is a blob, not a tag\n+\terror: bad tag pointer to $blob in $tag_tag_blob\n+\tfatal: bad object $tag_tag_blob\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n test_done\n-- \n2.31.1.442.g6c06c9fe35c\n\n"},{"id":"420358","messageId":"xmqqy2e7on7d.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-01.11-e51c860a65d-20210328T021238Z-avarab@gmail.com","subject":"Re: [PATCH v2 01/10] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-28T05:35:02Z","receivedAt":"2021-03-28T05:49:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Change the type_from_string() macro into a function and drop the\n> support for passing len < 0.\n>\n> Support for len < 0 was added in fe8e3b71805 (Refactor\n> type_from_string() to allow continuing after detecting an error,\n> 2014-09-10), but no callers use that form. Let's drop it to simplify\n> this, and in preparation for simplifying these even further.\n\nGiven the recent fallout of oversimplifying we've seen in other\ntopic, this line of thinking makes me nauseated, but let's see how\nwell this works this time around.\n\nAt least, replacing an already queued topic with v2 would not\nincrease the number of topics that are supposedly in-flight but not\nquite moving due to lack of reviews and responses, unlike bunch of\ntotally new patches ;-)\n\nWill replace.  Thanks.\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  object.c | 10 +++++++---\n>  object.h |  2 +-\n>  2 files changed, 8 insertions(+), 4 deletions(-)\n>\n> diff --git a/object.c b/object.c\n> index 78343781ae7..65446172172 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -39,9 +39,6 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n>  {\n>  \tint i;\n>  \n> -\tif (len < 0)\n> -\t\tlen = strlen(str);\n> -\n>  \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n>  \t\tif (!strncmp(str, object_type_strings[i], len) &&\n>  \t\t    object_type_strings[i][len] == '\\0')\n> @@ -53,6 +50,13 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n>  \tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n>  }\n>  \n> +int type_from_string(const char *str)\n> +{\n> +\tsize_t len = strlen(str);\n> +\tint ret = type_from_string_gently(str, len, 0);\n> +\treturn ret;\n> +}\n> +\n>  /*\n>   * Return a numerical hash value between 0 and n-1 for the object with\n>   * the specified sha1.  n must be a power of 2.  Please note that the\n> diff --git a/object.h b/object.h\n> index 59daadce214..3ab3eb193d3 100644\n> --- a/object.h\n> +++ b/object.h\n> @@ -94,7 +94,7 @@ struct object {\n>  \n>  const char *type_name(unsigned int type);\n>  int type_from_string_gently(const char *str, ssize_t, int gentle);\n> -#define type_from_string(str) type_from_string_gently(str, -1, 0)\n> +int type_from_string(const char *str);\n>  \n>  /*\n>   * Return the current number of buckets in the object hashmap.\n"},{"id":"420375","messageId":"YGBHH7sAVsPpVKWd@coredump.intra.peff.net","threadId":"1003","inReplyTo":"87h7kwnjpp.fsf@evledraar.gmail.com","subject":"Re: [PATCH 6/7] object tests: add test for unexpected objects in tags","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-28T09:06:39Z","receivedAt":"2021-03-28T09:07:36Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Mar 28, 2021 at 03:35:46AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> >> Fix a blind spot in the tests added in 0616617c7e1 (t: introduce tests\n> >> for unexpected object types, 2019-04-09), there were no meaningful\n> >> tests for checking how we reported on finding the incorrect object\n> >> type in a tag, i.e. one that broke the \"type\" promise in the tag\n> >> header.\n> >\n> > Isn't this covered by tests 16 and 17 (\"traverse unexpected non-commit\n> > tag\", both \"lone\" and \"seen\")? And likewise the matching \"non-tree\" and\n> > \"non-blob\" variants afterwards?\n> \n> Barely, those tests are mainly testing that rev-list doesn't die, and\n> only do a very fuzzy match on the output. E.g. checking `grep \"not a\n> commit\" err`, not a full test_cmp that'll check what OID is reported\n> etc.\n\nI thought the \"blind spot\" you meant was not testing these cases. But I\nguess you mean that we are not checking stderr.\n\nSo OK, but...\n\n> > The only thing we don't seem to cover is an unexpected non-tag. I don't\n> > mind adding that, but why wouldn't we just follow the template of the\n> > existing tests?\n> \n> I am following that template to some extent, e.g. using\n> ${commit,tree,blob}. It just didn't seem worth it to refactor an earlier\n> test in the file just to re-use a single hash-object invocation, those\n> tests e.g. clobber the $tag variable, so bending over backwards to\n> re-use anything set up in them would mean some refactoring.\n> \n> I think it's much clearer just do do all the different kinds of setup in\n> the new setup function.\n\nIt does not seem to make the resulting test script more clear at all to\ncreate the same situation twice, but test stderr only in the second\ncase. I.e., why is the change to the test script not just:\n\ndiff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\nindex 52cde097dd..4cdc87c913 100755\n--- a/t/t6102-rev-list-unexpected-objects.sh\n+++ b/t/t6102-rev-list-unexpected-objects.sh\n@@ -82,12 +82,13 @@ test_expect_success 'setup unexpected non-commit tag' '\n '\n \n test_expect_success 'traverse unexpected non-commit tag (lone)' '\n-\ttest_must_fail git rev-list --objects $tag\n+\ttest_must_fail git rev-list --objects $tag >output 2>&1 &&\n+\ttest_i18ngrep \"is a blob, not a commit\" output\n '\n \n test_expect_success 'traverse unexpected non-commit tag (seen)' '\n \ttest_must_fail git rev-list --objects $blob $tag >output 2>&1 &&\n-\ttest_i18ngrep \"not a commit\" output\n+\ttest_i18ngrep \"is a blob, not a commit\" output\n '\n \n test_expect_success 'setup unexpected non-tree tag' '\n\nand so forth (or you can replace it with a full test_cmp if you really\nprefer). That does not seem like bending over backwards to me, but\nrather keeping the test script tidy and readable.\n\nBut I wonder if there is something more going on that led you to have\ntrouble demonstrating your problem with the existing tests. Looking at\nyour follow-on patch that flips the \"is an X, not a Y\", I am not sure\nthis is something that we can actually handle reliably. At least not\nwithout further access to the object database.\n\nBecause when we call, say, lookup_blob() and find that the object is\nalready in memory as a non-blob, we don't know who the culprit is.\nPerhaps an earlier part of the code called parse_object(), found that it\nreally is a blob on disk, and used that type. But it may equally have\nbeen the case that we saw a reference to the object as a commit, called\nlookup_commit() on it, and now our lookup_blob() call is unhappy,\nthinking it is really a commit. In that case, one of those references is\nwrong, but we don't know which.\n\nI think a robust solution would be one of:\n\n  - make the message more precise: \"saw object X as a commit, but\n    previously it was referred to as a blob\". Or vice versa.\n\n  - when we see such a mismatch, go to the object database to say \"aha,\n    on disk it is really a blob\". That's expensive, but this is an error\n    case, so we can afford to be slow. But it does produce unsatisfying\n    results when it was the earlier lookup_commit() call that was wrong.\n    Because we have to say \"object X is really a blob, but some object\n    earlier referred to it as a commit. No idea who did that, though!\".\n\n-Peff\n"},{"id":"420376","messageId":"YGBL88lYheyFmwCg@coredump.intra.peff.net","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"Re: [PATCH v2 00/10] improve reporting of unexpected objects","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-28T09:27:15Z","receivedAt":"2021-03-28T09:28:18Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Mar 28, 2021 at 04:13:30AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> Ævar Arnfjörð Bjarmason (10):\n>   object.c: stop supporting len == -1 in type_from_string_gently()\n>   object.c: refactor type_from_string_gently()\n>   object.c: make type_from_string() return \"enum object_type\"\n>   object-file.c: make oid_object_info() return \"enum object_type\"\n>   object-name.c: make dependency on object_type order more obvious\n>   tree.c: fix misindentation in parse_tree_gently()\n>   object.c: add a utility function for \"expected type X, got Y\"\n>   object.c: add and use oid_is_type_or_die_msg() function\n>   object tests: add test for unexpected objects in tags\n>   tag: don't misreport type of tagged objects in errors\n\nI'm somewhat skeptical of the final patch, given my comments (just now)\nin:\n\n  https://lore.kernel.org/git/YGBHH7sAVsPpVKWd@coredump.intra.peff.net/\n\nI'll quote them here:\n\n> Because when we call, say, lookup_blob() and find that the object is\n> already in memory as a non-blob, we don't know who the culprit is.\n> Perhaps an earlier part of the code called parse_object(), found that it\n> really is a blob on disk, and used that type. But it may equally have\n> been the case that we saw a reference to the object as a commit, called\n> lookup_commit() on it, and now our lookup_blob() call is unhappy,\n> thinking it is really a commit. In that case, one of those references is\n> wrong, but we don't know which.\n>\n> I think a robust solution would be one of:\n>\n>   - make the message more precise: \"saw object X as a commit, but\n>     previously it was referred to as a blob\". Or vice versa.\n>\n>   - when we see such a mismatch, go to the object database to say \"aha,\n>     on disk it is really a blob\". That's expensive, but this is an error\n>     case, so we can afford to be slow. But it does produce unsatisfying\n>     results when it was the earlier lookup_commit() call that was wrong.\n>     Because we have to say \"object X is really a blob, but some object\n>     earlier referred to it as a commit. No idea who did that, though!\".\n\nLooking at the final patch, I think you side-step the issue to some\ndegree because it is only touching the parse_object() code paths, where\nwe really have looked at the bytes in the object database. So it\nbasically is doing the second thing above (which is \"free\" because we\nwere accessing the odb anyway).\n\nBut I think it still has the \"oops, somebody made a wrong reference much\nearlier\" problem. The actual bug is in some other object entirely, whose\nidentity is long forgotten. I think we would be much better off to say\nsomething like \"somebody expected X to be a commit, but now somebody\nelse expects it to be a blob\", which is all that we can reliably say.\nAnd the next step really ought to be running \"git fsck\" to figure out\nwhat is going on (and we should perhaps even say so via advise()).\n\n-Peff\n"},{"id":"420411","messageId":"8735wfnv7i.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"YGBHH7sAVsPpVKWd@coredump.intra.peff.net","subject":"Re: [PATCH 6/7] object tests: add test for unexpected objects in tags","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T15:39:45Z","receivedAt":"2021-03-28T15:40:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Mar 28 2021, Jeff King wrote:\n\n> On Sun, Mar 28, 2021 at 03:35:46AM +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>> >> Fix a blind spot in the tests added in 0616617c7e1 (t: introduce tests\n>> >> for unexpected object types, 2019-04-09), there were no meaningful\n>> >> tests for checking how we reported on finding the incorrect object\n>> >> type in a tag, i.e. one that broke the \"type\" promise in the tag\n>> >> header.\n>> >\n>> > Isn't this covered by tests 16 and 17 (\"traverse unexpected non-commit\n>> > tag\", both \"lone\" and \"seen\")? And likewise the matching \"non-tree\" and\n>> > \"non-blob\" variants afterwards?\n>> \n>> Barely, those tests are mainly testing that rev-list doesn't die, and\n>> only do a very fuzzy match on the output. E.g. checking `grep \"not a\n>> commit\" err`, not a full test_cmp that'll check what OID is reported\n>> etc.\n>\n> I thought the \"blind spot\" you meant was not testing these cases. But I\n> guess you mean that we are not checking stderr.\n>\n> So OK, but...\n\nAh yes. I'll clarify that. I thought it was clear since the series is\nabout the output we emit on errors, not the rev-list traversal itself.\n\n>> > The only thing we don't seem to cover is an unexpected non-tag. I don't\n>> > mind adding that, but why wouldn't we just follow the template of the\n>> > existing tests?\n>> \n>> I am following that template to some extent, e.g. using\n>> ${commit,tree,blob}. It just didn't seem worth it to refactor an earlier\n>> test in the file just to re-use a single hash-object invocation, those\n>> tests e.g. clobber the $tag variable, so bending over backwards to\n>> re-use anything set up in them would mean some refactoring.\n>> \n>> I think it's much clearer just do do all the different kinds of setup in\n>> the new setup function.\n>\n> It does not seem to make the resulting test script more clear at all to\n> create the same situation twice, but test stderr only in the second\n> case. I.e., why is the change to the test script not just:\n>\n> diff --git a/t/t6102-rev-list-unexpected-objects.sh b/t/t6102-rev-list-unexpected-objects.sh\n> index 52cde097dd..4cdc87c913 100755\n> --- a/t/t6102-rev-list-unexpected-objects.sh\n> +++ b/t/t6102-rev-list-unexpected-objects.sh\n> @@ -82,12 +82,13 @@ test_expect_success 'setup unexpected non-commit tag' '\n>  '\n>  \n>  test_expect_success 'traverse unexpected non-commit tag (lone)' '\n> -\ttest_must_fail git rev-list --objects $tag\n> +\ttest_must_fail git rev-list --objects $tag >output 2>&1 &&\n> +\ttest_i18ngrep \"is a blob, not a commit\" output\n>  '\n>  \n>  test_expect_success 'traverse unexpected non-commit tag (seen)' '\n>  \ttest_must_fail git rev-list --objects $blob $tag >output 2>&1 &&\n> -\ttest_i18ngrep \"not a commit\" output\n> +\ttest_i18ngrep \"is a blob, not a commit\" output\n>  '\n>  \n>  test_expect_success 'setup unexpected non-tree tag' '\n>\n> and so forth (or you can replace it with a full test_cmp if you really\n> prefer). That does not seem like bending over backwards to me, but\n> rather keeping the test script tidy and readable.\n\nYeah, it needs to be a test_cmp (or equivalent) since the point of the\ntest is *which* thing we're reporting as the \"is X not Y\".\n\nBut yes, these can be combined. But I still think it's clearer to have\nminimal tests for the traversal and then later (much more verbose) tests\nfor the output.\n\nSo if you the traversal fails you'd be looking at a fairly isolated test\nwith just two lines, v.s. 10-15 lines of later test_cmp etc.\n\n> [...]\n\nWill reply to the rest, but that discussion seems split, so reading the\nthread to see what the best place to continue that chat is...\n"},{"id":"420414","messageId":"87zgynmgbk.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"xmqqy2e7on7d.fsf@gitster.g","subject":"Re: [PATCH v2 01/10] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-28T15:46:39Z","receivedAt":"2021-03-28T15:47:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Mar 28 2021, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Change the type_from_string() macro into a function and drop the\n>> support for passing len < 0.\n>>\n>> Support for len < 0 was added in fe8e3b71805 (Refactor\n>> type_from_string() to allow continuing after detecting an error,\n>> 2014-09-10), but no callers use that form. Let's drop it to simplify\n>> this, and in preparation for simplifying these even further.\n>\n> Given the recent fallout of oversimplifying we've seen in other\n> topic, this line of thinking makes me nauseated, but let's see how\n> well this works this time around.\n\nDo you mean related to tree-walk.[ch]? But yeah, this step doesn't\nstriclly need to be taken, but seemed worth it given that there's just\n10 or so callers (none of which used this).\n\n> At least, replacing an already queued topic with v2 would not\n> increase the number of topics that are supposedly in-flight but not\n> quite moving due to lack of reviews and responses, unlike bunch of\n> totally new patches ;-)\n\nI'm not sure what to do to improve things in that area.\n\nI'm obviously for increasing the net velocity of my patches making it to\nmaster, but if it's held up my number of reviews a submission of Y won't\nnecessarily make X worse, since people who've got an interest in Y will\nbe different than those with an interest in X.\n\nBut some of it's definitely on my end, e.g. re-rolls sometimes taking me\nlonger than I'd prefer. It's a different activity to dissect outstanding\nreviews & re-roll than writing code, and sometimes I'm interested in one\nover the other...\n\n>> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>> ---\n>>  object.c | 10 +++++++---\n>>  object.h |  2 +-\n>>  2 files changed, 8 insertions(+), 4 deletions(-)\n>>\n>> diff --git a/object.c b/object.c\n>> index 78343781ae7..65446172172 100644\n>> --- a/object.c\n>> +++ b/object.c\n>> @@ -39,9 +39,6 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n>>  {\n>>  \tint i;\n>>  \n>> -\tif (len < 0)\n>> -\t\tlen = strlen(str);\n>> -\n>>  \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n>>  \t\tif (!strncmp(str, object_type_strings[i], len) &&\n>>  \t\t    object_type_strings[i][len] == '\\0')\n>> @@ -53,6 +50,13 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n>>  \tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n>>  }\n>>  \n>> +int type_from_string(const char *str)\n>> +{\n>> +\tsize_t len = strlen(str);\n>> +\tint ret = type_from_string_gently(str, len, 0);\n>> +\treturn ret;\n>> +}\n>> +\n>>  /*\n>>   * Return a numerical hash value between 0 and n-1 for the object with\n>>   * the specified sha1.  n must be a power of 2.  Please note that the\n>> diff --git a/object.h b/object.h\n>> index 59daadce214..3ab3eb193d3 100644\n>> --- a/object.h\n>> +++ b/object.h\n>> @@ -94,7 +94,7 @@ struct object {\n>>  \n>>  const char *type_name(unsigned int type);\n>>  int type_from_string_gently(const char *str, ssize_t, int gentle);\n>> -#define type_from_string(str) type_from_string_gently(str, -1, 0)\n>> +int type_from_string(const char *str);\n>>  \n>>  /*\n>>   * Return the current number of buckets in the object hashmap.\n\n"},{"id":"420418","messageId":"xmqq8s67m8zi.fsf@gitster.g","threadId":"1003","inReplyTo":"87zgynmgbk.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 01/10] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-28T18:25:05Z","receivedAt":"2021-03-28T18:26:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n>> At least, replacing an already queued topic with v2 would not\n>> increase the number of topics that are supposedly in-flight but not\n>> quite moving due to lack of reviews and responses, unlike bunch of\n>> totally new patches ;-)\n>\n> I'm not sure what to do to improve things in that area.\n>\n> I'm obviously for increasing the net velocity of my patches making it to\n> master, but if it's held up my number of reviews a submission of Y won't\n> necessarily make X worse, since people who've got an interest in Y will\n> be different than those with an interest in X.\n>\n> But some of it's definitely on my end, e.g. re-rolls sometimes taking me\n> longer than I'd prefer. It's a different activity to dissect outstanding\n> reviews & re-roll than writing code, and sometimes I'm interested in one\n> over the other...\n\nWhat I'd like to encourage contributors to think is the velocity in\nthe whole project, not only their own patches.  The changes proposed\non the list would consume the review bandwidth, which is\nunfortunately not an infinite resource.\n\nTo balance the supply and the consumption, one way might be to\nthrottle incoming patches to restrict consumption and distribute the\nsupply more evenly among authors.  But a more desirable way that\nwould benefit the community more would be to increase the supply.\n\nIf all of those who consume the review bandwidth tip in by reviewing\nothers' patches, not limited to the area they are interested in but\nmore in the \"I am not so familiar with the area, but I've been here\nlong enough and know general principles, so let's polish your patch\ntogether\" spirit, that would help the community greatly, I would\nthink, by:\n\n - replenishing review bandwidth they consumed from the pool;\n\n - throttling their patch flow that consume review bandwidth (while\n   they are reviewing others patches, they won't be throwing new\n   patches at the list to consume even more review bandwidth);\n\n - helping the reviewers themselves become more familiar with the\n   parts of the code they are not working in right now.\n\nI am reasonably sure I and a few others on the list are net\nsuppliers of the reviewer bandwidth.  I do not expect all the\nprolific contributors to become net suppliers; after all, designing\nand writing their own stuff is always fun.  But I wish that the most\nprominent contributors in the community to be reviewing others'\ntopics and ushering these topics to completion from time to time,\nand I am hoping to see that happen more.\n\nThanks.\n"},{"id":"420436","messageId":"YGGbBz+TXJfLV8VC@coredump.intra.peff.net","threadId":"1003","inReplyTo":"8735wfnv7i.fsf@evledraar.gmail.com","subject":"Re: [PATCH 6/7] object tests: add test for unexpected objects in tags","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-29T09:16:55Z","receivedAt":"2021-03-29T09:17:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sun, Mar 28, 2021 at 05:39:45PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> > I thought the \"blind spot\" you meant was not testing these cases. But I\n> > guess you mean that we are not checking stderr.\n> >\n> > So OK, but...\n> \n> Ah yes. I'll clarify that. I thought it was clear since the series is\n> about the output we emit on errors, not the rev-list traversal itself.\n\nTBH, I think it was as much a reading comprehension fail on my part. But\nit certainly doesn't hurt to make the commit message more clear.\n\n-Peff\n"},{"id":"420467","messageId":"87r1jym6d0.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"YGBL88lYheyFmwCg@coredump.intra.peff.net","subject":"Re: [PATCH v2 00/10] improve reporting of unexpected objects","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-29T13:34:03Z","receivedAt":"2021-03-29T13:34:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sun, Mar 28 2021, Jeff King wrote:\n\n> On Sun, Mar 28, 2021 at 04:13:30AM +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>> Ævar Arnfjörð Bjarmason (10):\n>>   object.c: stop supporting len == -1 in type_from_string_gently()\n>>   object.c: refactor type_from_string_gently()\n>>   object.c: make type_from_string() return \"enum object_type\"\n>>   object-file.c: make oid_object_info() return \"enum object_type\"\n>>   object-name.c: make dependency on object_type order more obvious\n>>   tree.c: fix misindentation in parse_tree_gently()\n>>   object.c: add a utility function for \"expected type X, got Y\"\n>>   object.c: add and use oid_is_type_or_die_msg() function\n>>   object tests: add test for unexpected objects in tags\n>>   tag: don't misreport type of tagged objects in errors\n>\n> I'm somewhat skeptical of the final patch, given my comments (just now)\n> in:\n>\n>   https://lore.kernel.org/git/YGBHH7sAVsPpVKWd@coredump.intra.peff.net/\n>\n> I'll quote them here:\n\nPicking up where we left off in\nhttp://lore.kernel.org/git/8735wfnv7i.fsf@evledraar.gmail.com ...\n\n>> Because when we call, say, lookup_blob() and find that the object is\n>> already in memory as a non-blob, we don't know who the culprit is.\n>> Perhaps an earlier part of the code called parse_object(), found that it\n>> really is a blob on disk, and used that type. But it may equally have\n>> been the case that we saw a reference to the object as a commit, called\n>> lookup_commit() on it, and now our lookup_blob() call is unhappy,\n>> thinking it is really a commit. In that case, one of those references is\n>> wrong, but we don't know which.\n>>\n>> I think a robust solution would be one of:\n>>\n>>   - make the message more precise: \"saw object X as a commit, but\n>>     previously it was referred to as a blob\". Or vice versa.\n>>\n>>   - when we see such a mismatch, go to the object database to say \"aha,\n>>     on disk it is really a blob\". That's expensive, but this is an error\n>>     case, so we can afford to be slow. But it does produce unsatisfying\n>>     results when it was the earlier lookup_commit() call that was wrong.\n>>     Because we have to say \"object X is really a blob, but some object\n>>     earlier referred to it as a commit. No idea who did that, though!\".\n>\n> Looking at the final patch, I think you side-step the issue to some\n> degree because it is only touching the parse_object() code paths, where\n> we really have looked at the bytes in the object database. So it\n> basically is doing the second thing above (which is \"free\" because we\n> were accessing the odb anyway).\n>\n> But I think it still has the \"oops, somebody made a wrong reference much\n> earlier\" problem. The actual bug is in some other object entirely, whose\n> identity is long forgotten. I think we would be much better off to say\n> something like \"somebody expected X to be a commit, but now somebody\n> else expects it to be a blob\", which is all that we can reliably say.\n> And the next step really ought to be running \"git fsck\" to figure out\n> what is going on (and we should perhaps even say so via advise()).\n\nYes I'm totally side-stepping the issue, but I don't see a way around\nthat that doesn't make the whole object lookup code either much slower,\nor more complex.\n\nI.e. the whole thing is an emergent effect of us seeing a tag object,\nand noting in-memory that we saw a given OID of type X, but we don't\neven know if we can look it up at that point, or that it's not type Y.\n\nI don't think it's guaranteed that we're neatly in one single object\ntraversal at that point (e.g. if we're looking at N tags, and only later\ndereferencing their \"object\" pointers). So passing a \"object A which I\nhave now says B is a X, assert!\" wouldn't work.\n\nWe could eagerly get the object from disk when parsing tags (slow?), or\nhave a void* in the object struct or whatever to say \"this is the OID\nthat claimed you were XYZ\" (ew!).\n\nOr, which I think makes sense here, just don't worry about it and error\nwith the limited info we have at hand. Yes we can't report who the\nultimate culprit is without an fsck, but that's not different than a lot\nof other error() and die() messages in the object code now.\n\nSo if we're going to emit an advise() that seems generally useful for\nmany of those error()/die() messages, and not something we should tack\nonto this incremental improvement to one error.\n"},{"id":"420554","messageId":"xmqq35wdfaw5.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-10.11-a84f670ac24-20210328T021238Z-avarab@gmail.com","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-30T05:50:18Z","receivedAt":"2021-03-30T05:51:30Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Fix a regression in 89e4202f982 ([PATCH] Parse tags for absent\n> objects, 2005-06-21) (yes, that ancient!) and correctly report an\n> error on a tag like:\n>\n>     object <a tree hash>\n>     type commit\n>\n> As:\n>\n>     error: object <a tree hash> is tree, not a commit\n>\n> Instead of our long-standing misbehavior of inverting the two, and\n> reporting:\n>\n>     error: object <a tree hash> is commit, not a tree\n>\n> Which, as can be trivially seen with 'git cat-file -t <a tree hash>'\n> is incorrect.\n\nHmph, I've always thought it is just \"supposed to be a\" missing in\nthe sentence ;-)\n\n> Hence the non-intuitive solution of adding a\n> lookup_{blob,commit,tag,tree}_type() function. It's to distinguish\n> calls from parse_object_buffer() where we actually know the type, from\n> a parse_tag_buffer() where we're just guessing about the type.\n\nI think it makes sense to allow the caller to express distinction\nbetween \"I know that this object is a blob, because I just read its\nobject header\" and \"Another object tells me that this object must be\na blob, because it is in a tree entry whose mode bits are 100644\".\n\nI wish we found a set of names better than lookup_<type>_type() for\nthat, though.  It's just between\n\n      lookup_tag_type(r, oid, OBJ_NONE);\n      lookup_tag_type(r, oid, OBJ_TAG);\n\nI cannot quite tell which one is which.  I also wonder if the last\narg should just be a boolean (\"I know it is a tag\" vs \"I heard it\nmust be a tag\").\n"},{"id":"420697","messageId":"YGRSQfMFS14Ksy0o@coredump.intra.peff.net","threadId":"1003","inReplyTo":"87r1jym6d0.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 00/10] improve reporting of unexpected objects","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-31T10:43:13Z","receivedAt":"2021-03-31T10:44:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 29, 2021 at 03:34:03PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> > But I think it still has the \"oops, somebody made a wrong reference much\n> > earlier\" problem. The actual bug is in some other object entirely, whose\n> > identity is long forgotten. I think we would be much better off to say\n> > something like \"somebody expected X to be a commit, but now somebody\n> > else expects it to be a blob\", which is all that we can reliably say.\n> > And the next step really ought to be running \"git fsck\" to figure out\n> > what is going on (and we should perhaps even say so via advise()).\n> \n> Yes I'm totally side-stepping the issue, but I don't see a way around\n> that that doesn't make the whole object lookup code either much slower,\n> or more complex.\n> \n> I.e. the whole thing is an emergent effect of us seeing a tag object,\n> and noting in-memory that we saw a given OID of type X, but we don't\n> even know if we can look it up at that point, or that it's not type Y.\n> \n> I don't think it's guaranteed that we're neatly in one single object\n> traversal at that point (e.g. if we're looking at N tags, and only later\n> dereferencing their \"object\" pointers). So passing a \"object A which I\n> have now says B is a X, assert!\" wouldn't work.\n> \n> We could eagerly get the object from disk when parsing tags (slow?), or\n> have a void* in the object struct or whatever to say \"this is the OID\n> that claimed you were XYZ\" (ew!).\n> \n> Or, which I think makes sense here, just don't worry about it and error\n> with the limited info we have at hand. Yes we can't report who the\n> ultimate culprit is without an fsck, but that's not different than a lot\n> of other error() and die() messages in the object code now.\n\nYes, that \"don't worry too much about it\" was where my line of thinking\nis going. But then I do not see all that much point in your final patch\nat all. I.e., I think just changing the message to more clearly say what\nwe do know in lookup_commit(), etc, would be sufficient.\n\n> So if we're going to emit an advise() that seems generally useful for\n> many of those error()/die() messages, and not something we should tack\n> onto this incremental improvement to one error.\n\nYeah, I think doing an advise() is probably overkill. My next step would\nalways be \"run fsck\", and I was thinking only that we might point the\nuser in that direction. But it's probably fine to just emit the error.\n\n-Peff\n"},{"id":"420698","messageId":"YGRWqX+qF+Rtqr20@coredump.intra.peff.net","threadId":"1003","inReplyTo":"xmqq35wdfaw5.fsf@gitster.g","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-31T11:02:01Z","receivedAt":"2021-03-31T11:02:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Mar 29, 2021 at 10:50:18PM -0700, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n> \n> > Fix a regression in 89e4202f982 ([PATCH] Parse tags for absent\n> > objects, 2005-06-21) (yes, that ancient!) and correctly report an\n> > error on a tag like:\n> >\n> >     object <a tree hash>\n> >     type commit\n> >\n> > As:\n> >\n> >     error: object <a tree hash> is tree, not a commit\n> >\n> > Instead of our long-standing misbehavior of inverting the two, and\n> > reporting:\n> >\n> >     error: object <a tree hash> is commit, not a tree\n> >\n> > Which, as can be trivially seen with 'git cat-file -t <a tree hash>'\n> > is incorrect.\n> \n> Hmph, I've always thought it is just \"supposed to be a\" missing in\n> the sentence ;-)\n\nSo going with the discussion elsewhere in the thread, I'd probably say\nsomething like:\n\n  error: object <oid> seen as both a commit and a tree\n\nwhich precisely says what we do know, without implying which is correct.\n\nÆvar's patch tries to improve the case where we might _know_ which is\ncorrect (because we're actually parsing the object contents), but of\ncourse it covers only a fraction of cases. I'm not really opposed to\nthat per se, but I probably wouldn't bother myself.\n\n  Side note: this is all making the assumption that what is in the\n  object itself is \"correct\", but of course that is not necessarily\n  true, even. All of these cases are the result of bugs, so it is\n  possible that the bug was in the writing of the original object\n  contents, and not the object that is referring to it. Likewise, I'd\n  imagine an easy way to get into this situation is with a bogus\n  refs/replace object that switches type.\n\n> > Hence the non-intuitive solution of adding a\n> > lookup_{blob,commit,tag,tree}_type() function. It's to distinguish\n> > calls from parse_object_buffer() where we actually know the type, from\n> > a parse_tag_buffer() where we're just guessing about the type.\n> \n> I think it makes sense to allow the caller to express distinction\n> between \"I know that this object is a blob, because I just read its\n> object header\" and \"Another object tells me that this object must be\n> a blob, because it is in a tree entry whose mode bits are 100644\".\n> \n> I wish we found a set of names better than lookup_<type>_type() for\n> that, though.  It's just between\n> \n>       lookup_tag_type(r, oid, OBJ_NONE);\n>       lookup_tag_type(r, oid, OBJ_TAG);\n> \n> I cannot quite tell which one is which.  I also wonder if the last\n> arg should just be a boolean (\"I know it is a tag\" vs \"I heard it\n> must be a tag\").\n\nYeah, I also found that very confusing. AFAICT lookup_tag_type() would\nonly ever see OBJ_NONE or OBJ_TAG. Making it more than a boolean makes\nboth the interface and implementation more complicated.\n\nI also think the manual handling of OBJ_NONE in each lookup_* function\nis confusing. They all call object_as_type() because the point of that\nfunction is both to type-check the struct and to convert it away from\nOBJ_NONE.\n\nIf we handled this error there, then I think it would be much more\nnatural, because we'd have already covered the OBJ_NONE case, and\nbecause it's already the place we're emitting the existing error. E.g.:\n\ndiff --git a/object.c b/object.c\nindex 2c32691dc4..e6345541f7 100644\n--- a/object.c\n+++ b/object.c\n@@ -157,7 +157,7 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n \treturn obj;\n }\n \n-void *object_as_type(struct object *obj, enum object_type type, int quiet)\n+void *object_as_type(struct object *obj, enum object_type type, unsigned flags)\n {\n \tif (obj->type == type)\n \t\treturn obj;\n@@ -169,10 +169,16 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n \t\treturn obj;\n \t}\n \telse {\n-\t\tif (!quiet)\n-\t\t\terror(_(\"object %s is a %s, not a %s\"),\n-\t\t\t      oid_to_hex(&obj->oid),\n-\t\t\t      type_name(obj->type), type_name(type));\n+\t\tif (!(flags & OBJECT_AS_TYPE_QUIET)) {\n+\t\t\tif (flags & OBJECT_AS_TYPE_EXPECT_PARSED)\n+\t\t\t\terror(_(\"object %s is a %s, but was referred to as a %s\"),\n+\t\t\t\t      oid_to_hex(&obj->oid), type_name(obj->type),\n+\t\t\t\t      type_name(type));\n+\t\t\telse\n+\t\t\t\terror(_(\"object %s referred to as both a %s and a %s\"),\n+\t\t\t\t      oid_to_hex(&obj->oid),\n+\t\t\t\t      type_name(obj->type), type_name(type));\n+\t\t}\n \t\treturn NULL;\n \t}\n }\n\n-Peff\n"},{"id":"420715","messageId":"xmqqim578agu.fsf@gitster.g","threadId":"1003","inReplyTo":"YGRWqX+qF+Rtqr20@coredump.intra.peff.net","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-31T18:05:53Z","receivedAt":"2021-03-31T18:06:31Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> I also think the manual handling of OBJ_NONE in each lookup_* function\n> is confusing. They all call object_as_type() because the point of that\n> function is both to type-check the struct and to convert it away from\n> OBJ_NONE.\n>\n> If we handled this error there, then I think it would be much more\n> natural, because we'd have already covered the OBJ_NONE case, and\n> because it's already the place we're emitting the existing error. E.g.:\n\nThis makes quite a lot of sense.  If presented with this simple\nchange and 10-patch series at the same time and are told that the\ngoal of the changes were more or less the same, I'd pick this one\n100% of the time.\n\n> diff --git a/object.c b/object.c\n> index 2c32691dc4..e6345541f7 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -157,7 +157,7 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n>  \treturn obj;\n>  }\n>  \n> -void *object_as_type(struct object *obj, enum object_type type, int quiet)\n> +void *object_as_type(struct object *obj, enum object_type type, unsigned flags)\n>  {\n>  \tif (obj->type == type)\n>  \t\treturn obj;\n> @@ -169,10 +169,16 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n>  \t\treturn obj;\n>  \t}\n>  \telse {\n> -\t\tif (!quiet)\n> -\t\t\terror(_(\"object %s is a %s, not a %s\"),\n> -\t\t\t      oid_to_hex(&obj->oid),\n> -\t\t\t      type_name(obj->type), type_name(type));\n> +\t\tif (!(flags & OBJECT_AS_TYPE_QUIET)) {\n> +\t\t\tif (flags & OBJECT_AS_TYPE_EXPECT_PARSED)\n> +\t\t\t\terror(_(\"object %s is a %s, but was referred to as a %s\"),\n> +\t\t\t\t      oid_to_hex(&obj->oid), type_name(obj->type),\n> +\t\t\t\t      type_name(type));\n> +\t\t\telse\n> +\t\t\t\terror(_(\"object %s referred to as both a %s and a %s\"),\n> +\t\t\t\t      oid_to_hex(&obj->oid),\n> +\t\t\t\t      type_name(obj->type), type_name(type));\n> +\t\t}\n>  \t\treturn NULL;\n>  \t}\n>  }\n>\n> -Peff\n"},{"id":"420718","messageId":"87k0pnkwej.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"YGRWqX+qF+Rtqr20@coredump.intra.peff.net","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-31T18:31:16Z","receivedAt":"2021-03-31T18:32:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Mar 31 2021, Jeff King wrote:\n\n> On Mon, Mar 29, 2021 at 10:50:18PM -0700, Junio C Hamano wrote:\n>\n>> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>> \n>> > Fix a regression in 89e4202f982 ([PATCH] Parse tags for absent\n>> > objects, 2005-06-21) (yes, that ancient!) and correctly report an\n>> > error on a tag like:\n>> >\n>> >     object <a tree hash>\n>> >     type commit\n>> >\n>> > As:\n>> >\n>> >     error: object <a tree hash> is tree, not a commit\n>> >\n>> > Instead of our long-standing misbehavior of inverting the two, and\n>> > reporting:\n>> >\n>> >     error: object <a tree hash> is commit, not a tree\n>> >\n>> > Which, as can be trivially seen with 'git cat-file -t <a tree hash>'\n>> > is incorrect.\n>> \n>> Hmph, I've always thought it is just \"supposed to be a\" missing in\n>> the sentence ;-)\n>\n> So going with the discussion elsewhere in the thread, I'd probably say\n> something like:\n>\n>   error: object <oid> seen as both a commit and a tree\n>\n> which precisely says what we do know, without implying which is correct.\n>\n> Ævar's patch tries to improve the case where we might _know_ which is\n> correct (because we're actually parsing the object contents), but of\n> course it covers only a fraction of cases. I'm not really opposed to\n> that per se, but I probably wouldn't bother myself.\n\nWhat fraction of cases? As far as I can tell it covers all cases where\nwe get this error.\n\nIf there is a case like what you're describing I haven't found it.\n\nI.e. it happens when we have an un-parsed \"struct object\" whose type is\ninferred, and parse it to find out it's not what we expected.\n\nIt's not ambigious at all what the object actually is. It's just that\nthe previous code was leaking the *assumption* about the type at the\ntime of emitting the error, due to an apparent oversight with parsed\nv.s. non-parsed.\n\nOr in other words, we're leaking the implementation detail that we\npre-allocated an object struct of a given type in anticipation of\nholding a parsed version of that object soon.\n\n>   Side note: this is all making the assumption that what is in the\n>   object itself is \"correct\", but of course that is not necessarily\n>   true, even. All of these cases are the result of bugs, so it is\n>   possible that the bug was in the writing of the original object\n>   contents, and not the object that is referring to it. Likewise, I'd\n>   imagine an easy way to get into this situation is with a bogus\n>   refs/replace object that switches type.\n\nPerhaps, I haven't tested that in any detail.\n\n>> > Hence the non-intuitive solution of adding a\n>> > lookup_{blob,commit,tag,tree}_type() function. It's to distinguish\n>> > calls from parse_object_buffer() where we actually know the type, from\n>> > a parse_tag_buffer() where we're just guessing about the type.\n>> \n>> I think it makes sense to allow the caller to express distinction\n>> between \"I know that this object is a blob, because I just read its\n>> object header\" and \"Another object tells me that this object must be\n>> a blob, because it is in a tree entry whose mode bits are 100644\".\n>> \n>> I wish we found a set of names better than lookup_<type>_type() for\n>> that, though.  It's just between\n>> \n>>       lookup_tag_type(r, oid, OBJ_NONE);\n>>       lookup_tag_type(r, oid, OBJ_TAG);\n>> \n>> I cannot quite tell which one is which.  I also wonder if the last\n>> arg should just be a boolean (\"I know it is a tag\" vs \"I heard it\n>> must be a tag\").\n>\n> Yeah, I also found that very confusing. AFAICT lookup_tag_type() would\n> only ever see OBJ_NONE or OBJ_TAG. Making it more than a boolean makes\n> both the interface and implementation more complicated.\n\nI don't feel strongly either way, but one concern here is that these are\nvery hot functions, and maybe it's better to give the compiler a better\nchance to work with them without considering an extra argument, but I\nhaven't tested that...\n\n> I also think the manual handling of OBJ_NONE in each lookup_* function\n> is confusing. They all call object_as_type() because the point of that\n> function is both to type-check the struct and to convert it away from\n> OBJ_NONE.\n>\n> If we handled this error there, then I think it would be much more\n> natural, because we'd have already covered the OBJ_NONE case, and\n> because it's already the place we're emitting the existing error. E.g.:\n>\n> diff --git a/object.c b/object.c\n> index 2c32691dc4..e6345541f7 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -157,7 +157,7 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n>  \treturn obj;\n>  }\n>  \n> -void *object_as_type(struct object *obj, enum object_type type, int quiet)\n> +void *object_as_type(struct object *obj, enum object_type type, unsigned flags)\n>  {\n>  \tif (obj->type == type)\n>  \t\treturn obj;\n> @@ -169,10 +169,16 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n>  \t\treturn obj;\n>  \t}\n>  \telse {\n> -\t\tif (!quiet)\n> -\t\t\terror(_(\"object %s is a %s, not a %s\"),\n> -\t\t\t      oid_to_hex(&obj->oid),\n> -\t\t\t      type_name(obj->type), type_name(type));\n> +\t\tif (!(flags & OBJECT_AS_TYPE_QUIET)) {\n> +\t\t\tif (flags & OBJECT_AS_TYPE_EXPECT_PARSED)\n> +\t\t\t\terror(_(\"object %s is a %s, but was referred to as a %s\"),\n> +\t\t\t\t      oid_to_hex(&obj->oid), type_name(obj->type),\n> +\t\t\t\t      type_name(type));\n> +\t\t\telse\n> +\t\t\t\terror(_(\"object %s referred to as both a %s and a %s\"),\n> +\t\t\t\t      oid_to_hex(&obj->oid),\n> +\t\t\t\t      type_name(obj->type), type_name(type));\n> +\t\t}\n>  \t\treturn NULL;\n>  \t}\n>  }\n\nPer the above I don't understand how you think there's any uncertainty\nhere.\n\nIf I'm right and there isn't then first of all I don't see how we could\nemit 1/2 of those errors. The whole problem here is that we don't know\nthe type of the un-parsed object (and presumably don't want to eagerly\nknow, it would mean hitting the object store).\n\nBut when we do know why would we beat around the bush and say \"was\nreferred to as X and Y\" once we know what it is. \n\nAFAICT there's no more reason to think that parse_object_buffer() will\nbe wrong about the type than \"git cat-file -t\" will be. They both use\nthe same underlying functions to get that information.\n"},{"id":"420720","messageId":"xmqqv9976u9d.fsf@gitster.g","threadId":"1003","inReplyTo":"YGRWqX+qF+Rtqr20@coredump.intra.peff.net","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-03-31T18:41:18Z","receivedAt":"2021-03-31T18:42:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> +\t\t\tif (flags & OBJECT_AS_TYPE_EXPECT_PARSED)\n> +\t\t\t\terror(_(\"object %s is a %s, but was referred to as a %s\"),\n> +\t\t\t\t      oid_to_hex(&obj->oid), type_name(obj->type),\n> +\t\t\t\t      type_name(type));\n> +\t\t\telse\n> +\t\t\t\terror(_(\"object %s referred to as both a %s and a %s\"),\n> +\t\t\t\t      oid_to_hex(&obj->oid),\n> +\t\t\t\t      type_name(obj->type), type_name(type));\n> +\t\t}\n\nAm I correct to understand that the latter is after we read a tree\nthat refers to an object with 100644 (blob) and then another tree\nthat refers to the same object with 40000 (tree), before we have a\nneed/chance to actually find out what that object is?  The error\nwould trigger while reading the second tree and find the second\nmention of the object that conflicts with the earlier one?\n\n"},{"id":"420723","messageId":"YGTGgFI19fS7Uv6I@coredump.intra.peff.net","threadId":"1003","inReplyTo":"87k0pnkwej.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-31T18:59:12Z","receivedAt":"2021-03-31T18:59:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 31, 2021 at 08:31:16PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> > Ævar's patch tries to improve the case where we might _know_ which is\n> > correct (because we're actually parsing the object contents), but of\n> > course it covers only a fraction of cases. I'm not really opposed to\n> > that per se, but I probably wouldn't bother myself.\n> \n> What fraction of cases? As far as I can tell it covers all cases where\n> we get this error.\n> \n> If there is a case like what you're describing I haven't found it.\n\nIt would happen any time somebody calls lookup_foo() because they saw an\nobject referenced, but _doesn't_ parse it. And then somebody later calls\nlookup_bar() in the same way. Neither of them consulted the actual\nobject database.\n\nTry this with your patches:\n\n-- >8 --\ngit init repo\ncd repo\n\n# just for making things deterministic\nexport GIT_COMMITTER_NAME='A U Thor'\nexport GIT_COMMITTER_EMAIL='author@example.com'\nexport GIT_COMMITTER_DATE='@1234567890 +0000'\n\nblob=$(echo foo | git hash-object -w --stdin)\ngit tag -m 'tag of blob' tag-of-blob $blob\ngit update-ref refs/tags/tag-of-commit $(\n  git cat-file tag tag-of-blob |\n  sed s/blob/commit/g |\n  git hash-object -w --stdin -t tag\n)\ngit update-ref refs/tags/tag-of-tree $(\n  git cat-file tag tag-of-blob |\n  sed s/blob/tree/g |\n  git hash-object -w --stdin -t tag\n)\n\ngit fsck\n-- >8 --\n\nThat fsck produces (257cc5642 is the blob):\n\n  error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a blob, not a commit\n  error: 257cc5642cb1a054f08cc83f2d943e56fd3ebe99: object could not be parsed: .git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99\n  error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a commit, not a tree\n  error: bad tag pointer to 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 in aaff0d42df150e1a734f6a8516878b2ea315ee0a\n  error: aaff0d42df150e1a734f6a8516878b2ea315ee0a: object could not be parsed: .git/objects/aa/ff0d42df150e1a734f6a8516878b2ea315ee0a\n  error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a commit, not a blob\n  error: bad tag pointer to 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 in bbd2b7077cd91ee6175cdc0e4c477c25c230cdc7\n  error: bbd2b7077cd91ee6175cdc0e4c477c25c230cdc7: object could not be parsed: .git/objects/bb/d2b7077cd91ee6175cdc0e4c477c25c230cdc7\n\nSo we claim \"is X, not Y\" in multiple directions for the same object.\n\nIt might just be that there are spots in the fsck code that need to be\nadjusted to use your new function (if they are indeed parsing the\nreferred-to object). But there are lots of places that don't actually\nparse the object at the moment they're parsing the tag. E.g.:\n\n  $ git for-each-ref --format='%(*objectname)'\n  error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a commit, not a tree\n  error: bad tag pointer to 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 in aaff0d42df150e1a734f6a8516878b2ea315ee0a\n  Segmentation fault\n\nNeither of those types is the correct one. And the segfault is just a\nbonus! :)\n\nI'd expect similar cases with parsing commit parents and tree pointers.\nAnd probably tree entries whose modes are wrong.\n\n> I.e. it happens when we have an un-parsed \"struct object\" whose type is\n> inferred, and parse it to find out it's not what we expected.\n> \n> It's not ambigious at all what the object actually is. It's just that\n> the previous code was leaking the *assumption* about the type at the\n> time of emitting the error, due to an apparent oversight with parsed\n> v.s. non-parsed.\n> \n> Or in other words, we're leaking the implementation detail that we\n> pre-allocated an object struct of a given type in anticipation of\n> holding a parsed version of that object soon.\n\nRight. In the case that you are indeed parsing the object later, you can\nsay definitively \"it is X in the odb, but seen as Y previously\". But we\ndo not always hit the \"is X, not Y\" error when parsing the object. It\nmight be caused by two of these \"pre-allocations\" (though really I think\nit is not just an implementation detail; the pre-allocation happened\nbecause some other object referred to us as a given type, so it really\nis a corruption in the repository. Just not in the object we mention).\n\n> > @@ -169,10 +169,16 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n> >  \t\treturn obj;\n> >  \t}\n> >  \telse {\n> > -\t\tif (!quiet)\n> > -\t\t\terror(_(\"object %s is a %s, not a %s\"),\n> > -\t\t\t      oid_to_hex(&obj->oid),\n> > -\t\t\t      type_name(obj->type), type_name(type));\n> > +\t\tif (!(flags & OBJECT_AS_TYPE_QUIET)) {\n> > +\t\t\tif (flags & OBJECT_AS_TYPE_EXPECT_PARSED)\n> > +\t\t\t\terror(_(\"object %s is a %s, but was referred to as a %s\"),\n> > +\t\t\t\t      oid_to_hex(&obj->oid), type_name(obj->type),\n> > +\t\t\t\t      type_name(type));\n> > +\t\t\telse\n> > +\t\t\t\terror(_(\"object %s referred to as both a %s and a %s\"),\n> > +\t\t\t\t      oid_to_hex(&obj->oid),\n> > +\t\t\t\t      type_name(obj->type), type_name(type));\n> > +\t\t}\n> >  \t\treturn NULL;\n> >  \t}\n> >  }\n> \n> Per the above I don't understand how you think there's any uncertainty\n> here.\n> \n> If I'm right and there isn't then first of all I don't see how we could\n> emit 1/2 of those errors. The whole problem here is that we don't know\n> the type of the un-parsed object (and presumably don't want to eagerly\n> know, it would mean hitting the object store).\n\nForgetting for a moment how to trigger it with actual Git commands, the\nroot of the problem is that:\n\n  lookup_tree(&oid);\n  lookup_blob(&oid);\n\nis going to produce an error message. But we cannot know which object\ntype is wrong and which is right (if any). So we'd want to produce the\n\"referred to as both\" message.\n\n_If_ the caller happens to know that it has just parsed the object\ncontents and got a tree, then it would call lookup_parsed_tree(&oid),\nwhich would pass along OBJECT_AS_TYPE_EXPECT_PARSED, and produce the\nother message.\n\nIn practice, of course those two lookup_foo() calls are not right next\nto each other. But they may be triggered on an identical oid by two\nreferences from different objects.\n\n> But when we do know why would we beat around the bush and say \"was\n> referred to as X and Y\" once we know what it is. \n> \n> AFAICT there's no more reason to think that parse_object_buffer() will\n> be wrong about the type than \"git cat-file -t\" will be. They both use\n> the same underlying functions to get that information.\n\nMy point is that we are not always coming from parse_object_buffer()\nwhen we see these error messages.\n\n-Peff\n"},{"id":"420724","messageId":"YGTGt+xGM9FN/ewm@coredump.intra.peff.net","threadId":"1003","inReplyTo":"xmqqv9976u9d.fsf@gitster.g","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-03-31T19:00:07Z","receivedAt":"2021-03-31T19:01:01Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 31, 2021 at 11:41:18AM -0700, Junio C Hamano wrote:\n\n> Jeff King <peff@peff.net> writes:\n> \n> > +\t\t\tif (flags & OBJECT_AS_TYPE_EXPECT_PARSED)\n> > +\t\t\t\terror(_(\"object %s is a %s, but was referred to as a %s\"),\n> > +\t\t\t\t      oid_to_hex(&obj->oid), type_name(obj->type),\n> > +\t\t\t\t      type_name(type));\n> > +\t\t\telse\n> > +\t\t\t\terror(_(\"object %s referred to as both a %s and a %s\"),\n> > +\t\t\t\t      oid_to_hex(&obj->oid),\n> > +\t\t\t\t      type_name(obj->type), type_name(type));\n> > +\t\t}\n> \n> Am I correct to understand that the latter is after we read a tree\n> that refers to an object with 100644 (blob) and then another tree\n> that refers to the same object with 40000 (tree), before we have a\n> need/chance to actually find out what that object is?  The error\n> would trigger while reading the second tree and find the second\n> mention of the object that conflicts with the earlier one?\n\nYes, exactly (or two tags, or a tag and a tree, or a commit and a tree,\netc).\n\n-Peff\n"},{"id":"420747","messageId":"87eefvkq5d.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"YGTGgFI19fS7Uv6I@coredump.intra.peff.net","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-03-31T20:46:22Z","receivedAt":"2021-03-31T20:47:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, Mar 31 2021, Jeff King wrote:\n\n> On Wed, Mar 31, 2021 at 08:31:16PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>> > Ævar's patch tries to improve the case where we might _know_ which is\n>> > correct (because we're actually parsing the object contents), but of\n>> > course it covers only a fraction of cases. I'm not really opposed to\n>> > that per se, but I probably wouldn't bother myself.\n>> \n>> What fraction of cases? As far as I can tell it covers all cases where\n>> we get this error.\n>> \n>> If there is a case like what you're describing I haven't found it.\n>\n> It would happen any time somebody calls lookup_foo() because they saw an\n> object referenced, but _doesn't_ parse it. And then somebody later calls\n> lookup_bar() in the same way. Neither of them consulted the actual\n> object database.\n>\n> Try this with your patches:\n>\n> -- >8 --\n> git init repo\n> cd repo\n>\n> # just for making things deterministic\n> export GIT_COMMITTER_NAME='A U Thor'\n> export GIT_COMMITTER_EMAIL='author@example.com'\n> export GIT_COMMITTER_DATE='@1234567890 +0000'\n>\n> blob=$(echo foo | git hash-object -w --stdin)\n> git tag -m 'tag of blob' tag-of-blob $blob\n> git update-ref refs/tags/tag-of-commit $(\n>   git cat-file tag tag-of-blob |\n>   sed s/blob/commit/g |\n>   git hash-object -w --stdin -t tag\n> )\n> git update-ref refs/tags/tag-of-tree $(\n>   git cat-file tag tag-of-blob |\n>   sed s/blob/tree/g |\n>   git hash-object -w --stdin -t tag\n> )\n>\n> git fsck\n> -- >8 --\n>\n> That fsck produces (257cc5642 is the blob):\n>\n>   error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a blob, not a commit\n>   error: 257cc5642cb1a054f08cc83f2d943e56fd3ebe99: object could not be parsed: .git/objects/25/7cc5642cb1a054f08cc83f2d943e56fd3ebe99\n>   error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a commit, not a tree\n>   error: bad tag pointer to 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 in aaff0d42df150e1a734f6a8516878b2ea315ee0a\n>   error: aaff0d42df150e1a734f6a8516878b2ea315ee0a: object could not be parsed: .git/objects/aa/ff0d42df150e1a734f6a8516878b2ea315ee0a\n>   error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a commit, not a blob\n>   error: bad tag pointer to 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 in bbd2b7077cd91ee6175cdc0e4c477c25c230cdc7\n>   error: bbd2b7077cd91ee6175cdc0e4c477c25c230cdc7: object could not be parsed: .git/objects/bb/d2b7077cd91ee6175cdc0e4c477c25c230cdc7\n>\n> So we claim \"is X, not Y\" in multiple directions for the same object.\n>\n> It might just be that there are spots in the fsck code that need to be\n> adjusted to use your new function (if they are indeed parsing the\n> referred-to object). But there are lots of places that don't actually\n> parse the object at the moment they're parsing the tag. E.g.:\n>\n>   $ git for-each-ref --format='%(*objectname)'\n>   error: object 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 is a commit, not a tree\n>   error: bad tag pointer to 257cc5642cb1a054f08cc83f2d943e56fd3ebe99 in aaff0d42df150e1a734f6a8516878b2ea315ee0a\n>   Segmentation fault\n>\n> Neither of those types is the correct one. And the segfault is just a\n> bonus! :)\n>\n> I'd expect similar cases with parsing commit parents and tree pointers.\n> And probably tree entries whose modes are wrong.\n\nSo the segfault happens without my patches, but the change is that\nbefore we'd always get it wrong and say \"commit, not a tree\", but now\nwe'll get it right some of the time. Patching the relevant object.c code\nto emit different messages from the various functions shows that it's\nthe oid_is_type*() functions that get it right, but object_as_type() is\nwrong as before.\n\nSo that's certainly something I missed.\n\nBut are there any cases where it makes things worse? Or is it just that\nit's not a full fix in all cases, but only a partial one?\n\n>> I.e. it happens when we have an un-parsed \"struct object\" whose type is\n>> inferred, and parse it to find out it's not what we expected.\n>> \n>> It's not ambigious at all what the object actually is. It's just that\n>> the previous code was leaking the *assumption* about the type at the\n>> time of emitting the error, due to an apparent oversight with parsed\n>> v.s. non-parsed.\n>> \n>> Or in other words, we're leaking the implementation detail that we\n>> pre-allocated an object struct of a given type in anticipation of\n>> holding a parsed version of that object soon.\n>\n> Right. In the case that you are indeed parsing the object later, you can\n> say definitively \"it is X in the odb, but seen as Y previously\". But we\n> do not always hit the \"is X, not Y\" error when parsing the object. It\n> might be caused by two of these \"pre-allocations\" (though really I think\n> it is not just an implementation detail; the pre-allocation happened\n> because some other object referred to us as a given type, so it really\n> is a corruption in the repository. Just not in the object we mention).\n\nIndeed, the goal is to emit a sensible message on-the-fly when we see\nthat corruption.\n\n>> > @@ -169,10 +169,16 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n>> >  \t\treturn obj;\n>> >  \t}\n>> >  \telse {\n>> > -\t\tif (!quiet)\n>> > -\t\t\terror(_(\"object %s is a %s, not a %s\"),\n>> > -\t\t\t      oid_to_hex(&obj->oid),\n>> > -\t\t\t      type_name(obj->type), type_name(type));\n>> > +\t\tif (!(flags & OBJECT_AS_TYPE_QUIET)) {\n>> > +\t\t\tif (flags & OBJECT_AS_TYPE_EXPECT_PARSED)\n>> > +\t\t\t\terror(_(\"object %s is a %s, but was referred to as a %s\"),\n>> > +\t\t\t\t      oid_to_hex(&obj->oid), type_name(obj->type),\n>> > +\t\t\t\t      type_name(type));\n>> > +\t\t\telse\n>> > +\t\t\t\terror(_(\"object %s referred to as both a %s and a %s\"),\n>> > +\t\t\t\t      oid_to_hex(&obj->oid),\n>> > +\t\t\t\t      type_name(obj->type), type_name(type));\n>> > +\t\t}\n>> >  \t\treturn NULL;\n>> >  \t}\n>> >  }\n>> \n>> Per the above I don't understand how you think there's any uncertainty\n>> here.\n>> \n>> If I'm right and there isn't then first of all I don't see how we could\n>> emit 1/2 of those errors. The whole problem here is that we don't know\n>> the type of the un-parsed object (and presumably don't want to eagerly\n>> know, it would mean hitting the object store).\n>\n> Forgetting for a moment how to trigger it with actual Git commands, the\n> root of the problem is that:\n>\n>   lookup_tree(&oid);\n>   lookup_blob(&oid);\n>\n> is going to produce an error message. But we cannot know which object\n> type is wrong and which is right (if any). So we'd want to produce the\n> \"referred to as both\" message.\n>\n> _If_ the caller happens to know that it has just parsed the object\n> contents and got a tree, then it would call lookup_parsed_tree(&oid),\n> which would pass along OBJECT_AS_TYPE_EXPECT_PARSED, and produce the\n> other message.\n>\n> In practice, of course those two lookup_foo() calls are not right next\n> to each other. But they may be triggered on an identical oid by two\n> references from different objects.\n\n[...]\n\n>> But when we do know why would we beat around the bush and say \"was\n>> referred to as X and Y\" once we know what it is. \n>> \n>> AFAICT there's no more reason to think that parse_object_buffer() will\n>> be wrong about the type than \"git cat-file -t\" will be. They both use\n>> the same underlying functions to get that information.\n>\n> My point is that we are not always coming from parse_object_buffer()\n> when we see these error messages.\n\nIf my solution of relying on the parsed v.s. non-parsed shouldn't we\njust devolve to a full object info lookup when emitting the error? It's\nmore expensive, but we're emitting an error anyway...\n"},{"id":"420801","messageId":"YGV8UOsYUQt7Lpto@coredump.intra.peff.net","threadId":"1003","inReplyTo":"87eefvkq5d.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 10/10] tag: don't misreport type of tagged objects in errors","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-01T07:54:56Z","receivedAt":"2021-04-01T07:55:43Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Wed, Mar 31, 2021 at 10:46:22PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> > Neither of those types is the correct one. And the segfault is just a\n> > bonus! :)\n> >\n> > I'd expect similar cases with parsing commit parents and tree pointers.\n> > And probably tree entries whose modes are wrong.\n> \n> So the segfault happens without my patches,\n\nYeah, sorry if that was unclear. It is definitely a pre-existing bug.\n\n> but the change is that\n> before we'd always get it wrong and say \"commit, not a tree\", but now\n> we'll get it right some of the time. Patching the relevant object.c code\n> to emit different messages from the various functions shows that it's\n> the oid_is_type*() functions that get it right, but object_as_type() is\n> wrong as before.\n> \n> So that's certainly something I missed.\n> \n> But are there any cases where it makes things worse? Or is it just that\n> it's not a full fix in all cases, but only a partial one?\n\nRight, I don't think your patch is making anything worse. It's just that\nit does not cover all cases where we see an object as two different\ntypes. Nor can it, since it is relying on code paths that actually parse\nthe object, and not all of them do.\n\n> > My point is that we are not always coming from parse_object_buffer()\n> > when we see these error messages.\n> \n> If my solution of relying on the parsed v.s. non-parsed shouldn't we\n> just devolve to a full object info lookup when emitting the error? It's\n> more expensive, but we're emitting an error anyway...\n\nThat's certainly one option (that I suggested earlier in [0]). If we go\nthat route, then we do not need any of this \"the caller passes in an\nextra bit to say that it is parsing the object, and it found a tree\",\nbecause the error routine in object_as_type() would consult the odb\nitself.\n\nBut I still think it does not make the error messages fully useful. We\nmight say \"object X is really a tree in the odb, but we previously saw\nit as a commit\". But we will still have to return NULL from\nlookup_tree(), so whatever containing object referenced X, _even though\nit has the correct type_, will be the one to propagate the failure up\nthe stack. It was whoever was responsible for that \"previously saw\" that\nis actually corrupt, and we no longer know who that was.\n\nWhich is why I wonder if it is worth even bothering to put a lot of\neffort in here. If the issue is just that \"X is a foo, not a bar\" is\nsometimes misleading, then we could solve that by simply making the\nmessage more precise (\"we saw X as a foo and a bar; one of them is\nwrong\"). Even if we could know _which_ is wrong with respect to what's\nin the object contents, it isn't all that helpful without being able to\ntell the user which object reference was the one that led us to the\nwrong conclusion.\n\n-Peff\n\n[0] https://lore.kernel.org/git/YGBHH7sAVsPpVKWd@coredump.intra.peff.net/\n"},{"id":"420802","messageId":"YGWFGMdGcKeaqCQF@coredump.intra.peff.net","threadId":"1003","inReplyTo":"YGV8UOsYUQt7Lpto@coredump.intra.peff.net","subject":"[PATCH] ref-filter: fix NULL check for parse object failure","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-01T08:32:24Z","receivedAt":"2021-04-01T08:33:34Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, Apr 01, 2021 at 03:54:56AM -0400, Jeff King wrote:\n\n> On Wed, Mar 31, 2021 at 10:46:22PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> \n> > > Neither of those types is the correct one. And the segfault is just a\n> > > bonus! :)\n> > >\n> > > I'd expect similar cases with parsing commit parents and tree pointers.\n> > > And probably tree entries whose modes are wrong.\n> > \n> > So the segfault happens without my patches,\n> \n> Yeah, sorry if that was unclear. It is definitely a pre-existing bug.\n\nHere's a patch to fix it. This is mostly orthogonal to your patch\nseries. It happens to use a similar recipe to reproduce, but that is not\nthe only way to do it, and the fix and the test shouldn't conflict\ntextually or semantically.\n\n-- >8 --\nSubject: [PATCH] ref-filter: fix NULL check for parse object failure\n\nAfter we run parse_object_buffer() to get an object's contents, we try\nto check that the return value wasn't NULL. However, since our \"struct\nobject\" is a pointer-to-pointer, and we assign like:\n\n  *obj = parse_object_buffer(...);\n\nit's not correct to check:\n\n  if (!obj)\n\nThat will always be true, since our double pointer will continue to\npoint to the single pointer (which is itself NULL). This is a regression\nthat was introduced by aa46a0da30 (ref-filter: use oid_object_info() to\nget object, 2018-07-17); since that commit we'll segfault on a parse\nfailure, as we try to look at the NULL object pointer.\n\nThere are many ways a parse could fail, but most of them are hard to set\nup in the tests (it's easy to make a bogus object, but update-ref will\nrefuse to point to it). The test here uses a tag which points to a wrong\nobject type. A parse of just the broken tag object will succeed, but\nseeing both tag objects in the same process will lead to a parse error\n(since we'll see the pointed-to object as both types).\n\nSigned-off-by: Jeff King <peff@peff.net>\n---\n ref-filter.c            |  2 +-\n t/t6300-for-each-ref.sh | 10 ++++++++++\n 2 files changed, 11 insertions(+), 1 deletion(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f0bd32f714..a0adb4551d 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1608,7 +1608,7 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \n \tif (oi->info.contentp) {\n \t\t*obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten);\n-\t\tif (!obj) {\n+\t\tif (!*obj) {\n \t\t\tif (!eaten)\n \t\t\t\tfree(oi->content);\n \t\t\treturn strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\ndiff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\nindex cac7f443d0..2e7c32d50c 100755\n--- a/t/t6300-for-each-ref.sh\n+++ b/t/t6300-for-each-ref.sh\n@@ -1134,4 +1134,14 @@ test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '\n \ttest_cmp expect actual\n '\n \n+test_expect_success 'for-each-ref reports broken tags' '\n+\tgit tag -m \"good tag\" broken-tag-good HEAD &&\n+\tgit cat-file tag broken-tag-good >good &&\n+\tsed s/commit/blob/ <good >bad &&\n+\tbad=$(git hash-object -w -t tag bad) &&\n+\tgit update-ref refs/tags/broken-tag-bad $bad &&\n+\ttest_must_fail git for-each-ref --format=\"%(*objectname)\" \\\n+\t\trefs/tags/broken-tag-*\n+'\n+\n test_done\n-- \n2.31.1.478.g72c5357f0d\n\n"},{"id":"420820","messageId":"patch-5.6-2ffe8f9fe3c-20210401T135419Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-00000000000-20210401T135419Z-avarab@gmail.com","subject":"[PATCH v2 5/5] ref-filter: fix NULL check for parse object failure","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-01T13:56:30Z","receivedAt":"2021-04-01T17:53:27Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nAfter we run parse_object_buffer() to get an object's contents, we try\nto check that the return value wasn't NULL. However, since our \"struct\nobject\" is a pointer-to-pointer, and we assign like:\n\n  *obj = parse_object_buffer(...);\n\nit's not correct to check:\n\n  if (!obj)\n\nThat will always be true, since our double pointer will continue to\npoint to the single pointer (which is itself NULL). This is a regression\nthat was introduced by aa46a0da30 (ref-filter: use oid_object_info() to\nget object, 2018-07-17); since that commit we'll segfault on a parse\nfailure, as we try to look at the NULL object pointer.\n\nThere are many ways a parse could fail, but most of them are hard to set\nup in the tests (it's easy to make a bogus object, but update-ref will\nrefuse to point to it).\n\nA minimal stand-alone test can be found at, but let's use the newly\namended t3800-mktag.sh tests to test these cases exhaustively on all\nsorts of bad tags.\n\n1. http://lore.kernel.org/git/YGWFGMdGcKeaqCQF@coredump.intra.peff.net\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n ref-filter.c     | 2 +-\n t/t3800-mktag.sh | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/ref-filter.c b/ref-filter.c\nindex f0bd32f7141..a0adb4551d8 100644\n--- a/ref-filter.c\n+++ b/ref-filter.c\n@@ -1608,7 +1608,7 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n \n \tif (oi->info.contentp) {\n \t\t*obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten);\n-\t\tif (!obj) {\n+\t\tif (!*obj) {\n \t\t\tif (!eaten)\n \t\t\t\tfree(oi->content);\n \t\t\treturn strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 10e4fde28de..b175d639013 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -64,7 +64,7 @@ check_verify_failure () {\n \t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n \t\ttest_cmp expected actual &&\n \t\t# segfaults!\n-\t\t! git -C bad-tag for-each-ref --format=\"%(*objectname)\"\n+\t\ttest_must_fail git -C bad-tag for-each-ref --format=\"%(*objectname)\"\n \t'\n }\n \n-- \n2.31.1.474.g72d45d12706\n\n"},{"id":"420821","messageId":"patch-4.6-403024b1cca-20210401T135419Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-00000000000-20210401T135419Z-avarab@gmail.com","subject":"[PATCH v2 4/5] mktag tests: test for maybe segfaulting for-each-ref","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-01T13:56:29Z","receivedAt":"2021-04-01T17:53:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a test to check that \"for-each-ref\" fails on a repository with a\nbad tag, this test intentionally uses \"! \" instead of \"test_must_fail\n\" to hide a segfault. We'll fix the underlying bug in a subsequent\ncommit and convert it to \"test_must_fail\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3800-mktag.sh | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 4673235b1fd..10e4fde28de 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -58,7 +58,13 @@ check_verify_failure () {\n \t\t# The update-ref command itself might fail, but we are\n \t\t# not testing that\n \t\techo \"$bad_tag\" >\"bad-tag/.git/$tag_ref\" &&\n-\t\ttest_must_fail git -C bad-tag fsck\n+\t\ttest_must_fail git -C bad-tag fsck &&\n+\n+\t\tprintf \"%s tag\\t%s\\n\" \"$bad_tag\" \"$tag_ref\" >expected &&\n+\t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n+\t\ttest_cmp expected actual &&\n+\t\t# segfaults!\n+\t\t! git -C bad-tag for-each-ref --format=\"%(*objectname)\"\n \t'\n }\n \n-- \n2.31.1.474.g72d45d12706\n\n"},{"id":"420826","messageId":"patch-2.6-dd71740447d-20210401T135419Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-00000000000-20210401T135419Z-avarab@gmail.com","subject":"[PATCH v2 2/5] mktag tests: invert --no-strict test","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-01T13:56:27Z","receivedAt":"2021-04-01T17:58:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the mktag --no-strict test to actually test success under\n--no-strict, that test was added in 06ce79152be (mktag: add a\n--[no-]strict option, 2021-01-06).\n\nIt doesn't make sense to check that we have the same failure except\nwhen we want --no-strict, by doing that we're assuming that the\nbehavior will be different under --no-strict, bun nothing was testing\nfor that.\n\nWe should instead assert that --strict is the same as --no-strict,\nexcept in the cases where we've declared that it's not.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3800-mktag.sh | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex e9008744e3d..951e6d39c2a 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -33,6 +33,8 @@ check_verify_failure () {\n \t\tthen\n \t\t\ttest_must_fail git mktag <tag.sig 2>err2 &&\n \t\t\ttest_cmp err err2\n+\t\telse\n+\t\t\tgit mktag --no-strict <tag.sig\n \t\tfi\n \t'\n }\n-- \n2.31.1.474.g72d45d12706\n\n"},{"id":"420834","messageId":"patch-1.6-45e0f100613-20210401T135419Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-00000000000-20210401T135419Z-avarab@gmail.com","subject":"[PATCH v2 1/5] mktag tests: parse out options in helper","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-01T13:56:26Z","receivedAt":"2021-04-01T18:10:51Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change check_verify_failure() helper to parse out options from\n$@. This makes it easier to add new options in the future. See\n06ce79152be (mktag: add a --[no-]strict option, 2021-01-06) for the\ninitial implementation.\n\nLet's also replace \"\" quotes with '' for the test body, the varables\nwe need are eval'd into the body, so there's no need for the quoting\nconfusion.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3800-mktag.sh | 43 +++++++++++++++++++++++++++++++------------\n 1 file changed, 31 insertions(+), 12 deletions(-)\n\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 6275c98523f..e9008744e3d 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -12,15 +12,29 @@ test_description='git mktag: tag object verify test'\n # given in the expect.pat file.\n \n check_verify_failure () {\n-\ttest_expect_success \"$1\" \"\n-\t\ttest_must_fail git mktag <tag.sig 2>message &&\n-\t\tgrep '$2' message &&\n-\t\tif test '$3' != '--no-strict'\n+\tsubject=$1 &&\n+\tmessage=$2 &&\n+\tshift 2 &&\n+\n+\tno_strict= &&\n+\twhile test $# != 0\n+\tdo\n+\t\tcase \"$1\" in\n+\t\t--no-strict)\n+\t\t\tno_strict=yes\n+\t\t\t;;\n+\t\tesac &&\n+\t\tshift\n+\tdone &&\n+\n+\ttest_expect_success \"fail with [--[no-]strict]: $subject\" '\n+\t\ttest_must_fail git mktag <tag.sig 2>err &&\n+\t\tif test -z \"$no_strict\"\n \t\tthen\n-\t\t\ttest_must_fail git mktag --no-strict <tag.sig 2>message.no-strict &&\n-\t\t\tgrep '$2' message.no-strict\n+\t\t\ttest_must_fail git mktag <tag.sig 2>err2 &&\n+\t\t\ttest_cmp err err2\n \t\tfi\n-\t\"\n+\t'\n }\n \n test_expect_mktag_success() {\n@@ -243,7 +257,8 @@ tagger . <> 0 +0000\n EOF\n \n check_verify_failure 'verify tag-name check' \\\n-\t'^error:.* badTagName:' '--no-strict'\n+\t'^error:.* badTagName:' \\\n+\t--no-strict\n \n ############################################################\n # 11. tagger line label check #1\n@@ -257,7 +272,8 @@ This is filler\n EOF\n \n check_verify_failure '\"tagger\" line label check #1' \\\n-\t'^error:.* missingTaggerEntry:' '--no-strict'\n+\t'^error:.* missingTaggerEntry:' \\\n+\t--no-strict\n \n ############################################################\n # 12. tagger line label check #2\n@@ -272,7 +288,8 @@ This is filler\n EOF\n \n check_verify_failure '\"tagger\" line label check #2' \\\n-\t'^error:.* missingTaggerEntry:' '--no-strict'\n+\t'^error:.* missingTaggerEntry:' \\\n+\t--no-strict\n \n ############################################################\n # 13. allow missing tag author name like fsck\n@@ -301,7 +318,8 @@ tagger T A Gger <\n EOF\n \n check_verify_failure 'disallow malformed tagger' \\\n-\t'^error:.* badEmail:' '--no-strict'\n+\t'^error:.* badEmail:' \\\n+\t--no-strict\n \n ############################################################\n # 15. allow empty tag email\n@@ -425,7 +443,8 @@ this line should not be here\n EOF\n \n check_verify_failure 'detect invalid header entry' \\\n-\t'^error:.* extraHeaderEntry:' '--no-strict'\n+\t'^error:.* extraHeaderEntry:' \\\n+\t--no-strict\n \n test_expect_success 'invalid header entry config & fsck' '\n \ttest_must_fail git mktag <tag.sig &&\n-- \n2.31.1.474.g72d45d12706\n\n"},{"id":"420836","messageId":"cover-0.6-00000000000-20210401T135419Z-avarab@gmail.com","threadId":"1003","inReplyTo":"YGWFGMdGcKeaqCQF@coredump.intra.peff.net","subject":"[PATCH v2 0/5] mktag tests & fix for-each-ref segfault","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-01T13:56:25Z","receivedAt":"2021-04-01T18:22:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"On Thu, Apr 01 2021, Jeff King wrote:\n\n> On Thu, Apr 01, 2021 at 03:54:56AM -0400, Jeff King wrote:\n>\n>> On Wed, Mar 31, 2021 at 10:46:22PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>> \n>> > > Neither of those types is the correct one. And the segfault is just a\n>> > > bonus! :)\n>> > >\n>> > > I'd expect similar cases with parsing commit parents and tree pointers.\n>> > > And probably tree entries whose modes are wrong.\n>> > \n>> > So the segfault happens without my patches,\n>> \n>> Yeah, sorry if that was unclear. It is definitely a pre-existing bug.\n>\n> Here's a patch to fix it. This is mostly orthogonal to your patch\n> series. It happens to use a similar recipe to reproduce, but that is not\n> the only way to do it, and the fix and the test shouldn't conflict\n> textually or semantically.\n\nHere's a proposed v2. We test the same case, but I thought it made\nsense to test this more exhaustively.\n\nThe v1 will also leave t6300 in a bad state for whoever adds the next\ntest, trivial to fix with a test_create_repo, but this seems better.\n\nJeff King (1):\n  ref-filter: fix NULL check for parse object failure\n\nÆvar Arnfjörð Bjarmason (4):\n  mktag tests: parse out options in helper\n  mktag tests: invert --no-strict test\n  mktag tests: do fsck on failure\n  mktag tests: test for maybe segfaulting for-each-ref\n\n ref-filter.c     |  2 +-\n t/t3800-mktag.sh | 90 +++++++++++++++++++++++++++++++++++++++---------\n 2 files changed, 75 insertions(+), 17 deletions(-)\n\nRange-diff:\n-:  ----------- > 1:  45e0f100613 mktag tests: parse out options in helper\n-:  ----------- > 2:  dd71740447d mktag tests: invert --no-strict test\n-:  ----------- > 3:  688d7456843 mktag tests: do fsck on failure\n-:  ----------- > 4:  403024b1cca mktag tests: test for maybe segfaulting for-each-ref\n1:  9358541ce1f ! 5:  2ffe8f9fe3c ref-filter: fix NULL check for parse object failure\n    @@ Commit message\n     \n         There are many ways a parse could fail, but most of them are hard to set\n         up in the tests (it's easy to make a bogus object, but update-ref will\n    -    refuse to point to it). The test here uses a tag which points to a wrong\n    -    object type. A parse of just the broken tag object will succeed, but\n    -    seeing both tag objects in the same process will lead to a parse error\n    -    (since we'll see the pointed-to object as both types).\n    +    refuse to point to it).\n    +\n    +    A minimal stand-alone test can be found at, but let's use the newly\n    +    amended t3800-mktag.sh tests to test these cases exhaustively on all\n    +    sorts of bad tags.\n    +\n    +    1. http://lore.kernel.org/git/YGWFGMdGcKeaqCQF@coredump.intra.peff.net\n     \n         Signed-off-by: Jeff King <peff@peff.net>\n    +    Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## ref-filter.c ##\n     @@ ref-filter.c: static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n    @@ ref-filter.c: static int get_object(struct ref_array_item *ref, int deref, struc\n      \t\t\t\tfree(oi->content);\n      \t\t\treturn strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n     \n    - ## t/t6300-for-each-ref.sh ##\n    -@@ t/t6300-for-each-ref.sh: test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '\n    - \ttest_cmp expect actual\n    - '\n    + ## t/t3800-mktag.sh ##\n    +@@ t/t3800-mktag.sh: check_verify_failure () {\n    + \t\tgit -C bad-tag for-each-ref \"$tag_ref\" >actual &&\n    + \t\ttest_cmp expected actual &&\n    + \t\t# segfaults!\n    +-\t\t! git -C bad-tag for-each-ref --format=\"%(*objectname)\"\n    ++\t\ttest_must_fail git -C bad-tag for-each-ref --format=\"%(*objectname)\"\n    + \t'\n    + }\n      \n    -+test_expect_success 'for-each-ref reports broken tags' '\n    -+\tgit tag -m \"good tag\" broken-tag-good HEAD &&\n    -+\tgit cat-file tag broken-tag-good >good &&\n    -+\tsed s/commit/blob/ <good >bad &&\n    -+\tbad=$(git hash-object -w -t tag bad) &&\n    -+\tgit update-ref refs/tags/broken-tag-bad $bad &&\n    -+\ttest_must_fail git for-each-ref --format=\"%(*objectname)\" \\\n    -+\t\trefs/tags/broken-tag-*\n    -+'\n    -+\n    - test_done\n-- \n2.31.1.474.g72d45d12706\n\n"},{"id":"420837","messageId":"patch-3.6-688d7456843-20210401T135419Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-00000000000-20210401T135419Z-avarab@gmail.com","subject":"[PATCH v2 3/5] mktag tests: do fsck on failure","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-01T13:56:28Z","receivedAt":"2021-04-01T18:22:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the check_verify_failure() function to do an fsck of the bad\nobject on failure.\n\nDue to how fsck works and walks the graph the failure will be\ndifferent if the object is reachable, so we might succeed before we've\ncreated the ref, let's make sure we always fail after it's created.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3800-mktag.sh | 51 ++++++++++++++++++++++++++++++++++++++----------\n 1 file changed, 41 insertions(+), 10 deletions(-)\n\ndiff --git a/t/t3800-mktag.sh b/t/t3800-mktag.sh\nindex 951e6d39c2a..4673235b1fd 100755\n--- a/t/t3800-mktag.sh\n+++ b/t/t3800-mktag.sh\n@@ -16,6 +16,8 @@ check_verify_failure () {\n \tmessage=$2 &&\n \tshift 2 &&\n \n+\tno_strict= &&\n+\tfsck_obj_ok= &&\n \tno_strict= &&\n \twhile test $# != 0\n \tdo\n@@ -23,7 +25,10 @@ check_verify_failure () {\n \t\t--no-strict)\n \t\t\tno_strict=yes\n \t\t\t;;\n-\t\tesac &&\n+\t\t--fsck-obj-ok)\n+\t\t\tfsck_obj_ok=yes\n+\t\t\t;;\n+\t\tesac\n \t\tshift\n \tdone &&\n \n@@ -35,7 +40,25 @@ check_verify_failure () {\n \t\t\ttest_cmp err err2\n \t\telse\n \t\t\tgit mktag --no-strict <tag.sig\n-\t\tfi\n+\t\tfi &&\n+\n+\t\ttest_when_finished \"rm -rf bad-tag\" &&\n+\t\ttest_create_repo bad-tag &&\n+\t\tbad_tag=$(git -C bad-tag hash-object -t tag -w --stdin --literally <tag.sig) &&\n+\t\tif test -n \"$fsck_obj_ok\"\n+\t\tthen\n+\t\t\tgit -C bad-tag fsck\n+\t\telse\n+\t\t\ttest_must_fail git -C bad-tag fsck >out 2>err\n+\t\tfi &&\n+\n+\t\t# Do update-ref anyway to see if it segfaults\n+\t\ttag_ref=refs/tags/bad_tag &&\n+\t\ttest_might_fail git -C bad-tag update-ref \"$tag_ref\" \"$bad_tag\" &&\n+\t\t# The update-ref command itself might fail, but we are\n+\t\t# not testing that\n+\t\techo \"$bad_tag\" >\"bad-tag/.git/$tag_ref\" &&\n+\t\ttest_must_fail git -C bad-tag fsck\n \t'\n }\n \n@@ -183,7 +206,8 @@ tagger . <> 0 +0000\n EOF\n \n check_verify_failure 'verify object (hash/type) check -- correct type, nonexisting object' \\\n-\t'^fatal: could not read tagged object'\n+\t'^fatal: could not read tagged object' \\\n+\t--fsck-obj-ok\n \n cat >tag.sig <<EOF\n object $head\n@@ -216,7 +240,8 @@ tagger . <> 0 +0000\n EOF\n \n check_verify_failure 'verify object (hash/type) check -- mismatched type, valid object' \\\n-\t'^fatal: object.*tagged as.*tree.*but is.*commit'\n+\t'^fatal: object.*tagged as.*tree.*but is.*commit' \\\n+\t--fsck-obj-ok\n \n ############################################################\n #  9.5. verify object (hash/type) check -- replacement\n@@ -245,7 +270,8 @@ tagger . <> 0 +0000\n EOF\n \n check_verify_failure 'verify object (hash/type) check -- mismatched type, valid object' \\\n-\t'^fatal: object.*tagged as.*tree.*but is.*blob'\n+\t'^fatal: object.*tagged as.*tree.*but is.*blob' \\\n+\t--fsck-obj-ok\n \n ############################################################\n # 10. verify tag-name check\n@@ -260,7 +286,8 @@ EOF\n \n check_verify_failure 'verify tag-name check' \\\n \t'^error:.* badTagName:' \\\n-\t--no-strict\n+\t--no-strict \\\n+\t--fsck-obj-ok\n \n ############################################################\n # 11. tagger line label check #1\n@@ -275,7 +302,8 @@ EOF\n \n check_verify_failure '\"tagger\" line label check #1' \\\n \t'^error:.* missingTaggerEntry:' \\\n-\t--no-strict\n+\t--no-strict \\\n+\t--fsck-obj-ok\n \n ############################################################\n # 12. tagger line label check #2\n@@ -291,7 +319,8 @@ EOF\n \n check_verify_failure '\"tagger\" line label check #2' \\\n \t'^error:.* missingTaggerEntry:' \\\n-\t--no-strict\n+\t--no-strict \\\n+\t--fsck-obj-ok\n \n ############################################################\n # 13. allow missing tag author name like fsck\n@@ -321,7 +350,8 @@ EOF\n \n check_verify_failure 'disallow malformed tagger' \\\n \t'^error:.* badEmail:' \\\n-\t--no-strict\n+\t--no-strict \\\n+\t--fsck-obj-ok\n \n ############################################################\n # 15. allow empty tag email\n@@ -446,7 +476,8 @@ EOF\n \n check_verify_failure 'detect invalid header entry' \\\n \t'^error:.* extraHeaderEntry:' \\\n-\t--no-strict\n+\t--no-strict \\\n+\t--fsck-obj-ok\n \n test_expect_success 'invalid header entry config & fsck' '\n \ttest_must_fail git mktag <tag.sig &&\n-- \n2.31.1.474.g72d45d12706\n\n"},{"id":"420844","messageId":"YGYc2enwPChDKGsq@satellite","threadId":"1003","inReplyTo":"patch-5.6-2ffe8f9fe3c-20210401T135419Z-avarab@gmail.com","subject":"Re: [PATCH v2 5/5] ref-filter: fix NULL check for parse object failure","fromName":"Ramsay Jones","fromEmail":"ramsay@ramsayjones.plus.com","sentAt":"2021-04-01T19:19:53Z","receivedAt":"2021-04-01T19:20:15Z","isPatch":true,"sender":{"key":"ramsay@ramsayjones.plus.com","avatar":"https://avatars.githubusercontent.com/u/33702710?v=4"},"body":"On Thu, Apr 01, 2021 at 03:56:30PM +0200, Ævar Arnfjörð Bjarmason wrote:\n> From: Jeff King <peff@peff.net>\n> \n[snip]\n> \n> A minimal stand-alone test can be found at, but let's use the newly\n\n... can be found at, ... Hmm, missing test number?\n\nATB,\nRamsay Jones\n\n> amended t3800-mktag.sh tests to test these cases exhaustively on all\n> sorts of bad tags.\n> \n> 1. http://lore.kernel.org/git/YGWFGMdGcKeaqCQF@coredump.intra.peff.net\n> \n> Signed-off-by: Jeff King <peff@peff.net>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  ref-filter.c     | 2 +-\n>  t/t3800-mktag.sh | 2 +-\n>  2 files changed, 2 insertions(+), 2 deletions(-)\n> \n[snip]\n\n"},{"id":"420848","messageId":"xmqqh7kp3hq8.fsf@gitster.g","threadId":"1003","inReplyTo":"YGWFGMdGcKeaqCQF@coredump.intra.peff.net","subject":"Re: [PATCH] ref-filter: fix NULL check for parse object failure","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-01T19:52:31Z","receivedAt":"2021-04-01T19:52:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> Here's a patch to fix it. This is mostly orthogonal to your patch\n> series. It happens to use a similar recipe to reproduce, but that is not\n> the only way to do it, and the fix and the test shouldn't conflict\n> textually or semantically.\n>\n> -- >8 --\n> Subject: [PATCH] ref-filter: fix NULL check for parse object failure\n>\n> After we run parse_object_buffer() to get an object's contents, we try\n> to check that the return value wasn't NULL. However, since our \"struct\n> object\" is a pointer-to-pointer, and we assign like:\n>\n>   *obj = parse_object_buffer(...);\n>\n> it's not correct to check:\n>\n>   if (!obj)\n>\n> That will always be true, since our double pointer will continue to\n> point to the single pointer (which is itself NULL). This is a regression\n> that was introduced by aa46a0da30 (ref-filter: use oid_object_info() to\n> get object, 2018-07-17); since that commit we'll segfault on a parse\n> failure, as we try to look at the NULL object pointer.\n>\n> There are many ways a parse could fail, but most of them are hard to set\n> up in the tests (it's easy to make a bogus object, but update-ref will\n> refuse to point to it). The test here uses a tag which points to a wrong\n> object type. A parse of just the broken tag object will succeed, but\n> seeing both tag objects in the same process will lead to a parse error\n> (since we'll see the pointed-to object as both types).\n>\n> Signed-off-by: Jeff King <peff@peff.net>\n> ---\n>  ref-filter.c            |  2 +-\n>  t/t6300-for-each-ref.sh | 10 ++++++++++\n>  2 files changed, 11 insertions(+), 1 deletion(-)\n\nMakes sense.  Will queue.\n\n> diff --git a/ref-filter.c b/ref-filter.c\n> index f0bd32f714..a0adb4551d 100644\n> --- a/ref-filter.c\n> +++ b/ref-filter.c\n> @@ -1608,7 +1608,7 @@ static int get_object(struct ref_array_item *ref, int deref, struct object **obj\n>  \n>  \tif (oi->info.contentp) {\n>  \t\t*obj = parse_object_buffer(the_repository, &oi->oid, oi->type, oi->size, oi->content, &eaten);\n> -\t\tif (!obj) {\n> +\t\tif (!*obj) {\n>  \t\t\tif (!eaten)\n>  \t\t\t\tfree(oi->content);\n>  \t\t\treturn strbuf_addf_ret(err, -1, _(\"parse_object_buffer failed on %s for %s\"),\n> diff --git a/t/t6300-for-each-ref.sh b/t/t6300-for-each-ref.sh\n> index cac7f443d0..2e7c32d50c 100755\n> --- a/t/t6300-for-each-ref.sh\n> +++ b/t/t6300-for-each-ref.sh\n> @@ -1134,4 +1134,14 @@ test_expect_success 'for-each-ref --ignore-case works on multiple sort keys' '\n>  \ttest_cmp expect actual\n>  '\n>  \n> +test_expect_success 'for-each-ref reports broken tags' '\n> +\tgit tag -m \"good tag\" broken-tag-good HEAD &&\n> +\tgit cat-file tag broken-tag-good >good &&\n> +\tsed s/commit/blob/ <good >bad &&\n> +\tbad=$(git hash-object -w -t tag bad) &&\n> +\tgit update-ref refs/tags/broken-tag-bad $bad &&\n> +\ttest_must_fail git for-each-ref --format=\"%(*objectname)\" \\\n> +\t\trefs/tags/broken-tag-*\n> +'\n> +\n>  test_done\n"},{"id":"420849","messageId":"xmqqczvd3hkb.fsf@gitster.g","threadId":"1003","inReplyTo":"cover-0.6-00000000000-20210401T135419Z-avarab@gmail.com","subject":"Re: [PATCH v2 0/5] mktag tests & fix for-each-ref segfault","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-01T19:56:04Z","receivedAt":"2021-04-01T19:56:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Here's a proposed v2. We test the same case, but I thought it made\n> sense to test this more exhaustively.\n\nLet's first make a targetted fix that can be applied to maint and\nbelow.  After that is merged to 'master', you are free to add more\ntests on top, but let's avoid to have more and more topics that go\noverboard.\n\nThanks.\n"},{"id":"420877","messageId":"87wntkkjcd.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"xmqqczvd3hkb.fsf@gitster.g","subject":"Re: [PATCH v2 0/5] mktag tests & fix for-each-ref segfault","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-02T11:37:54Z","receivedAt":"2021-04-02T11:38:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Apr 01 2021, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Here's a proposed v2. We test the same case, but I thought it made\n>> sense to test this more exhaustively.\n>\n> Let's first make a targetted fix that can be applied to maint and\n> below.  After that is merged to 'master', you are free to add more\n> tests on top, \n\nMakes sense. I based Jeff's patch on top of mine to demonstrate that\nthose tests also catch the segfault.\n\n> but let's avoid to have more and more topics that go overboard.\n\nSo \"submit a new version on-top\" or \"maybe deal with your existing\ntopics first as you're overflowing my inbox\" ? :) I suspect the latter..\n"},{"id":"420892","messageId":"xmqqeefs4dge.fsf@gitster.g","threadId":"1003","inReplyTo":"87wntkkjcd.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 0/5] mktag tests & fix for-each-ref segfault","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-02T20:51:45Z","receivedAt":"2021-04-02T20:51:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> On Thu, Apr 01 2021, Junio C Hamano wrote:\n>\n>> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>>\n>>> Here's a proposed v2. We test the same case, but I thought it made\n>>> sense to test this more exhaustively.\n>>\n>> Let's first make a targetted fix that can be applied to maint and\n>> below.  After that is merged to 'master', you are free to add more\n>> tests on top, \n>\n> Makes sense. I based Jeff's patch on top of mine to demonstrate that\n> those tests also catch the segfault.\n>\n>> but let's avoid to have more and more topics that go overboard.\n>\n> So \"submit a new version on-top\" or \"maybe deal with your existing\n> topics first as you're overflowing my inbox\" ? :) I suspect the latter..\n\nWhat I meant is...\n\nComparing the five-patch series with Peff's small fix that is more\nto the point, I have a feeling that the five-patch series, like many\nother series from you, may be made unnecessarily large by not\nresisting the temptation to including unessential \"while at it\"\nchanges.\n"},{"id":"421348","messageId":"cover-0.3-0000000000-20210409T080534Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com","subject":"[PATCH 0/2] blob/object.c: trivial readability improvements","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:07:26Z","receivedAt":"2021-04-09T08:07:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This is the initial and very trivil part of a re-starting the\nab/unexpected-object-type topic by splitting it up into more managable\npieces, see a note about the split in [1].\n\n1. https://lore.kernel.org/git/87r1jkgvoc.fsf@evledraar.gmail.com/\n\nÆvar Arnfjörð Bjarmason (2):\n  blob.c: remove buffer & size arguments to parse_blob_buffer()\n  object.c: initialize automatic variable in lookup_object()\n\n blob.c   | 2 +-\n blob.h   | 3 +--\n object.c | 8 ++++----\n 3 files changed, 6 insertions(+), 7 deletions(-)\n\n-- \n2.31.1.584.gf4baedee75\n\n"},{"id":"421349","messageId":"patch-1.3-68a7709fe5-20210409T080534Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.3-0000000000-20210409T080534Z-avarab@gmail.com","subject":"[PATCH 1/2] blob.c: remove buffer & size arguments to parse_blob_buffer()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:07:27Z","receivedAt":"2021-04-09T08:07:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As noted in the comment introduced in 837d395a5c0 (Replace\nparse_blob() with an explanatory comment, 2010-01-18) the old\nparse_blob() function and the current parse_blob_buffer() exist merely\nto provide consistency in the API.\n\nWe're not going to parse blobs like we \"parse\" commits, trees or\ntags. So let's not have the parse_blob_buffer() take arguments that\npretends that we do. Its only use is to set the \"parsed\" flag.\n\nSee bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\nparse_object(), 2005-05-06) for the introduction of parse_blob_buffer().\n\nI'm moving the prototype of parse_blob_buffer() below the comment\nadded in 837d395a5c0 while I'm at it. That comment was originally\nmeant to be a replacement for the missing parse_blob() function, but\nit's much less confusing to have it be above the parse_blob_buffer()\nfunction it refers to.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n blob.c   | 2 +-\n blob.h   | 3 +--\n object.c | 4 ++--\n 3 files changed, 4 insertions(+), 5 deletions(-)\n\ndiff --git a/blob.c b/blob.c\nindex 182718aba9..389a7546dc 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -13,7 +13,7 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n \treturn object_as_type(obj, OBJ_BLOB, 0);\n }\n \n-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n+int parse_blob_buffer(struct blob *item)\n {\n \titem->object.parsed = 1;\n \treturn 0;\ndiff --git a/blob.h b/blob.h\nindex 1664872055..ac1d4804a5 100644\n--- a/blob.h\n+++ b/blob.h\n@@ -11,8 +11,6 @@ struct blob {\n \n struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n \n-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n-\n /**\n  * Blobs do not contain references to other objects and do not have\n  * structured data that needs parsing. However, code may use the\n@@ -21,5 +19,6 @@ int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n  * parse_blob_buffer() is used (by object.c) to flag that the object\n  * has been read successfully from the database.\n  **/\n+int parse_blob_buffer(struct blob *item);\n \n #endif /* BLOB_H */\ndiff --git a/object.c b/object.c\nindex 78343781ae..63896abf01 100644\n--- a/object.c\n+++ b/object.c\n@@ -195,7 +195,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \tif (type == OBJ_BLOB) {\n \t\tstruct blob *blob = lookup_blob(r, oid);\n \t\tif (blob) {\n-\t\t\tif (parse_blob_buffer(blob, buffer, size))\n+\t\t\tif (parse_blob_buffer(blob))\n \t\t\t\treturn NULL;\n \t\t\tobj = &blob->object;\n \t\t}\n@@ -266,7 +266,7 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n \t\t\treturn NULL;\n \t\t}\n-\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n+\t\tparse_blob_buffer(lookup_blob(r, oid));\n \t\treturn lookup_object(r, oid);\n \t}\n \n-- \n2.31.1.584.gf4baedee75\n\n"},{"id":"421350","messageId":"patch-2.3-f1fcc31717-20210409T080534Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.3-0000000000-20210409T080534Z-avarab@gmail.com","subject":"[PATCH 2/2] object.c: initialize automatic variable in lookup_object()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:07:28Z","receivedAt":"2021-04-09T08:07:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Initialize a \"struct object obj*\" variable to NULL explicitly and\nreturn it instead of leaving it uninitialized until the \"while\"\nloop.\n\nThere was no bug here, it's just less confusing when debugging if the\n\"obj\" is either NULL or a valid object, not some random invalid\npointer.\n\nSee 0556a11a0df (git object hash cleanups, 2006-06-30) for the initial\nimplementation.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 63896abf01..7fdca3ed1e 100644\n--- a/object.c\n+++ b/object.c\n@@ -87,10 +87,10 @@ static void insert_obj_hash(struct object *obj, struct object **hash, unsigned i\n struct object *lookup_object(struct repository *r, const struct object_id *oid)\n {\n \tunsigned int i, first;\n-\tstruct object *obj;\n+\tstruct object *obj = NULL;\n \n \tif (!r->parsed_objects->obj_hash)\n-\t\treturn NULL;\n+\t\treturn obj;\n \n \tfirst = i = hash_obj(oid, r->parsed_objects->obj_hash_size);\n \twhile ((obj = r->parsed_objects->obj_hash[i]) != NULL) {\n-- \n2.31.1.584.gf4baedee75\n\n"},{"id":"421351","messageId":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.3-0000000000-20210409T080534Z-avarab@gmail.com","subject":"[PATCH 0/6] {tag,object}*.c: refactorings + prep for a larger change","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:32:48Z","receivedAt":"2021-04-09T08:33:07Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Based on top of[1] this is part of a split-up of [2] into more\ndigestable pieces. I've addressed feedback on this part of the series\nthis mostly-a-re-roll.\n\n1. http://lore.kernel.org/git/cover-0.3-0000000000-20210409T080534Z-avarab@gmail.com\n2. https://lore.kernel.org/git/cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (6):\n  object.c: stop supporting len == -1 in type_from_string_gently()\n  object.c: remove \"gently\" argument to type_from_string_gently()\n  object.c: make type_from_string() return \"enum object_type\"\n  object-file.c: make oid_object_info() return \"enum object_type\"\n  object-name.c: make dependency on object_type order more obvious\n  tag.c: use type_from_string_gently() when parsing tags\n\n builtin/blame.c      |  2 +-\n builtin/index-pack.c |  2 +-\n fsck.c               |  2 +-\n object-file.c        | 10 ++++------\n object-name.c        | 25 +++++++++++++------------\n object-store.h       |  4 +++-\n object.c             | 20 +++++++++++---------\n object.h             |  4 ++--\n packfile.c           |  2 +-\n tag.c                | 19 ++++++++++---------\n 10 files changed, 47 insertions(+), 43 deletions(-)\n\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421352","messageId":"patch-1.6-820f3aed21-20210409T082935Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH 1/6] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:32:49Z","receivedAt":"2021-04-09T08:33:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the type_from_string() macro into a function and drop the\nsupport for passing len < 0.\n\nSupport for len < 0 was added in fe8e3b71805 (Refactor\ntype_from_string() to allow continuing after detecting an error,\n2014-09-10), but no callers use that form. Let's drop it to simplify\nthis, and in preparation for simplifying these even further.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 10 +++++++---\n object.h |  2 +-\n 2 files changed, 8 insertions(+), 4 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 7fdca3ed1e..88de01e5ac 100644\n--- a/object.c\n+++ b/object.c\n@@ -39,9 +39,6 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n {\n \tint i;\n \n-\tif (len < 0)\n-\t\tlen = strlen(str);\n-\n \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n \t\t    object_type_strings[i][len] == '\\0')\n@@ -53,6 +50,13 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n \tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n }\n \n+int type_from_string(const char *str)\n+{\n+\tsize_t len = strlen(str);\n+\tint ret = type_from_string_gently(str, len, 0);\n+\treturn ret;\n+}\n+\n /*\n  * Return a numerical hash value between 0 and n-1 for the object with\n  * the specified sha1.  n must be a power of 2.  Please note that the\ndiff --git a/object.h b/object.h\nindex 59daadce21..3ab3eb193d 100644\n--- a/object.h\n+++ b/object.h\n@@ -94,7 +94,7 @@ struct object {\n \n const char *type_name(unsigned int type);\n int type_from_string_gently(const char *str, ssize_t, int gentle);\n-#define type_from_string(str) type_from_string_gently(str, -1, 0)\n+int type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421353","messageId":"patch-3.6-7fd86f6699-20210409T082935Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH 3/6] object.c: make type_from_string() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:32:51Z","receivedAt":"2021-04-09T08:33:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the type_from_string*() functions to return an \"enum\nobject_type\", but don't refactor their callers to check for \"==\nOBJ_BAD\" instead of \"< 0\".\n\nRefactoring the check of the return value to check == OBJ_BAD would\nnow be equivalent to \"ret < 0\", but the consensus on an earlier\nversion of this patch was to not do that, and to instead use -1\nconsistently as a return value. It just so happens that OBJ_BAD == -1,\nbut let's not put a hard reliance on that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 8 ++++----\n object.h | 4 ++--\n 2 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 5477abc97c..2216cdcda2 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,9 +35,9 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, ssize_t len)\n+enum object_type type_from_string_gently(const char *str, ssize_t len)\n {\n-\tint i;\n+\tenum object_type i;\n \n \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n@@ -46,10 +46,10 @@ int type_from_string_gently(const char *str, ssize_t len)\n \treturn -1;\n }\n \n-int type_from_string(const char *str)\n+enum object_type type_from_string(const char *str)\n {\n \tsize_t len = strlen(str);\n-\tint ret = type_from_string_gently(str, len);\n+\tenum object_type ret = type_from_string_gently(str, len);\n \tif (ret < 0)\n \t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n \treturn ret;\ndiff --git a/object.h b/object.h\nindex ffdc129830..5e7a523e85 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,8 +93,8 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, ssize_t len);\n-int type_from_string(const char *str);\n+enum object_type type_from_string_gently(const char *str, ssize_t len);\n+enum object_type type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421354","messageId":"patch-2.6-daed40c479-20210409T082935Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH 2/6] object.c: remove \"gently\" argument to type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:32:50Z","receivedAt":"2021-04-09T08:33:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Get rid of the \"gently\" argument to type_from_string_gently() to make\nit consistent with most other *_gently() functions. It's already a\n\"gentle\" function, it shouldn't need a boolean argument telling it to\nbe gentle.\n\nThe reason it had a \"gentle\" parameter was because until the preceding\ncommit \"type_from_string()\" was a macro resolving to\n\"type_from_string_gently()\", it's now a function.\n\nThis refactoring of adding a third parameter was done in\nfe8e3b71805 (Refactor type_from_string() to allow continuing after\ndetecting an error, 2014-09-10) in preparation for its use in\nfsck.c.\n\nSimplifying this means we can move the die() into the simpler\ntype_from_string() function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n fsck.c        |  2 +-\n object-file.c |  2 +-\n object.c      | 12 +++++-------\n object.h      |  2 +-\n 4 files changed, 8 insertions(+), 10 deletions(-)\n\ndiff --git a/fsck.c b/fsck.c\nindex f5ed6a2635..8dda548c38 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -875,7 +875,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, \"invalid format - unexpected end after 'type' line\");\n \t\tgoto done;\n \t}\n-\t*tagged_type = type_from_string_gently(buffer, eol - buffer, 1);\n+\t*tagged_type = type_from_string_gently(buffer, eol - buffer);\n \tif (*tagged_type < 0)\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, \"invalid 'type' value\");\n \tif (ret)\ndiff --git a/object-file.c b/object-file.c\nindex 624af408cd..b7c26b6735 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1314,7 +1314,7 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,\n \t\ttype_len++;\n \t}\n \n-\ttype = type_from_string_gently(type_buf, type_len, 1);\n+\ttype = type_from_string_gently(type_buf, type_len);\n \tif (oi->type_name)\n \t\tstrbuf_add(oi->type_name, type_buf, type_len);\n \t/*\ndiff --git a/object.c b/object.c\nindex 88de01e5ac..5477abc97c 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,7 +35,7 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, ssize_t len, int gentle)\n+int type_from_string_gently(const char *str, ssize_t len)\n {\n \tint i;\n \n@@ -43,17 +43,15 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n \t\t    object_type_strings[i][len] == '\\0')\n \t\t\treturn i;\n-\n-\tif (gentle)\n-\t\treturn -1;\n-\n-\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n+\treturn -1;\n }\n \n int type_from_string(const char *str)\n {\n \tsize_t len = strlen(str);\n-\tint ret = type_from_string_gently(str, len, 0);\n+\tint ret = type_from_string_gently(str, len);\n+\tif (ret < 0)\n+\t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n \treturn ret;\n }\n \ndiff --git a/object.h b/object.h\nindex 3ab3eb193d..ffdc129830 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,7 +93,7 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, ssize_t, int gentle);\n+int type_from_string_gently(const char *str, ssize_t len);\n int type_from_string(const char *str);\n \n /*\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421355","messageId":"patch-4.6-ebea1b2b50-20210409T082935Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH 4/6] object-file.c: make oid_object_info() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:32:52Z","receivedAt":"2021-04-09T08:33:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change oid_object_info() to return an \"enum object_type\". Unlike\noid_object_info_extended() function the simpler oid_object_info()\nexplicitly returns the oi.typep member, which is itself an \"enum\nobject_type\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/blame.c      |  2 +-\n builtin/index-pack.c |  2 +-\n object-file.c        |  8 +++-----\n object-name.c        | 19 +++++++++----------\n object-store.h       |  4 +++-\n packfile.c           |  2 +-\n 6 files changed, 18 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 641523ff9a..5dd3c38a8c 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -810,7 +810,7 @@ static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)\n \toidcpy(&oid, oid_ret);\n \twhile (1) {\n \t\tstruct object *obj;\n-\t\tint kind = oid_object_info(r, &oid, NULL);\n+\t\tenum object_type kind = oid_object_info(r, &oid, NULL);\n \t\tif (kind == OBJ_COMMIT) {\n \t\t\toidcpy(oid_ret, &oid);\n \t\t\treturn 0;\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 15507b5cff..c0e3768c32 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -237,7 +237,7 @@ static unsigned check_object(struct object *obj)\n \n \tif (!(obj->flags & FLAG_CHECKED)) {\n \t\tunsigned long size;\n-\t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n+\t\tenum object_type type = oid_object_info(the_repository, &obj->oid, &size);\n \t\tif (type <= 0)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\ndiff --git a/object-file.c b/object-file.c\nindex b7c26b6735..8ed54d6f62 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1572,11 +1572,9 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,\n \treturn ret;\n }\n \n-\n-/* returns enum object_type or negative */\n-int oid_object_info(struct repository *r,\n-\t\t    const struct object_id *oid,\n-\t\t    unsigned long *sizep)\n+enum object_type oid_object_info(struct repository *r,\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t unsigned long *sizep)\n {\n \tenum object_type type;\n \tstruct object_info oi = OBJECT_INFO_INIT;\ndiff --git a/object-name.c b/object-name.c\nindex 64202de60b..4d7f0c66cf 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -239,9 +239,8 @@ static int disambiguate_committish_only(struct repository *r,\n \t\t\t\t\tvoid *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \n-\tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_COMMIT)\n \t\treturn 1;\n \tif (kind != OBJ_TAG)\n@@ -258,7 +257,7 @@ static int disambiguate_tree_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_TREE;\n }\n \n@@ -267,7 +266,7 @@ static int disambiguate_treeish_only(struct repository *r,\n \t\t\t\t     void *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind;\n \n \tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_TREE || kind == OBJ_COMMIT)\n@@ -286,7 +285,7 @@ static int disambiguate_blob_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_BLOB;\n }\n \n@@ -361,7 +360,7 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n {\n \tconst struct disambiguate_state *ds = data;\n \tstruct strbuf desc = STRBUF_INIT;\n-\tint type;\n+\tenum object_type type;\n \n \tif (ds->fn && !ds->fn(ds->repo, oid, ds->cb_data))\n \t\treturn 0;\n@@ -405,10 +404,10 @@ static int repo_collect_ambiguous(struct repository *r,\n static int sort_ambiguous(const void *a, const void *b, void *ctx)\n {\n \tstruct repository *sort_ambiguous_repo = ctx;\n-\tint a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n-\tint b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n-\tint a_type_sort;\n-\tint b_type_sort;\n+\tenum object_type a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n+\tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n+\tenum object_type a_type_sort;\n+\tenum object_type b_type_sort;\n \n \t/*\n \t * Sorts by hash within the same object type, just as\ndiff --git a/object-store.h b/object-store.h\nindex ec32c23dcb..eab9674d08 100644\n--- a/object-store.h\n+++ b/object-store.h\n@@ -208,7 +208,9 @@ static inline void *repo_read_object_file(struct repository *r,\n #endif\n \n /* Read and unpack an object file into memory, write memory to an object file */\n-int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n+enum object_type oid_object_info(struct repository *r,\n+\t\t\t\t const struct object_id *,\n+\t\t\t\t unsigned long *);\n \n int hash_object_file(const struct git_hash_algo *algo, const void *buf,\n \t\t     unsigned long len, const char *type,\ndiff --git a/packfile.c b/packfile.c\nindex 6661f3325a..3ee01ea732 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1266,7 +1266,7 @@ static int retry_bad_packed_offset(struct repository *r,\n \t\t\t\t   struct packed_git *p,\n \t\t\t\t   off_t obj_offset)\n {\n-\tint type;\n+\tenum object_type type;\n \tuint32_t pos;\n \tstruct object_id oid;\n \tif (offset_to_pack_pos(p, obj_offset, &pos) < 0)\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421356","messageId":"patch-6.6-3279d67d2b-20210409T082935Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH 6/6] tag.c: use type_from_string_gently() when parsing tags","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:32:54Z","receivedAt":"2021-04-09T08:33:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a series of strcmp() to instead use type_from_string_gently()\nto get the integer type early, and then use that for comparison.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n tag.c | 19 ++++++++++---------\n 1 file changed, 10 insertions(+), 9 deletions(-)\n\ndiff --git a/tag.c b/tag.c\nindex 3e18a41841..871c4c9a14 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -135,7 +135,7 @@ void release_tag_memory(struct tag *t)\n int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size)\n {\n \tstruct object_id oid;\n-\tchar type[20];\n+\tenum object_type type;\n \tconst char *bufptr = data;\n \tconst char *tail = bufptr + size;\n \tconst char *nl;\n@@ -162,23 +162,24 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u\n \t\treturn -1;\n \tbufptr += 5;\n \tnl = memchr(bufptr, '\\n', tail - bufptr);\n-\tif (!nl || sizeof(type) <= (nl - bufptr))\n+\tif (!nl)\n+\t\treturn -1;\n+\ttype = type_from_string_gently(bufptr, nl - bufptr);\n+\tif (type < 0)\n \t\treturn -1;\n-\tmemcpy(type, bufptr, nl - bufptr);\n-\ttype[nl - bufptr] = '\\0';\n \tbufptr = nl + 1;\n \n-\tif (!strcmp(type, blob_type)) {\n+\tif (type == OBJ_BLOB) {\n \t\titem->tagged = (struct object *)lookup_blob(r, &oid);\n-\t} else if (!strcmp(type, tree_type)) {\n+\t} else if (type == OBJ_TREE) {\n \t\titem->tagged = (struct object *)lookup_tree(r, &oid);\n-\t} else if (!strcmp(type, commit_type)) {\n+\t} else if (type == OBJ_COMMIT) {\n \t\titem->tagged = (struct object *)lookup_commit(r, &oid);\n-\t} else if (!strcmp(type, tag_type)) {\n+\t} else if (type == OBJ_TAG) {\n \t\titem->tagged = (struct object *)lookup_tag(r, &oid);\n \t} else {\n \t\treturn error(\"unknown tag type '%s' in %s\",\n-\t\t\t     type, oid_to_hex(&item->object.oid));\n+\t\t\t     type_name(type), oid_to_hex(&item->object.oid));\n \t}\n \n \tif (!item->tagged)\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421357","messageId":"patch-5.6-94e13611f0-20210409T082935Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH 5/6] object-name.c: make dependency on object_type order more obvious","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:32:53Z","receivedAt":"2021-04-09T08:33:13Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add an assert to make it more obvious that we were effectively\nhardcoding OBJ_TAG in sort_ambiguous() as \"4\".\n\nI wrote this code in 5cc044e0257 (get_short_oid: sort ambiguous\nobjects by type, then SHA-1, 2018-05-10), there was already a comment\nabout this magic, but let's make sure that someone doing a potential\nreordering of \"enum object_type\" in the future would notice it\nbreaking this function (and probably a bunch of other things...).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object-name.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 4d7f0c66cf..b6a7328b7a 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -408,6 +408,8 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)\n \tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n \tenum object_type a_type_sort;\n \tenum object_type b_type_sort;\n+\tconst enum object_type tag_type_offs = OBJ_TAG - OBJ_NONE;\n+\tassert(tag_type_offs == 4);\n \n \t/*\n \t * Sorts by hash within the same object type, just as\n@@ -425,8 +427,8 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)\n \t * cleverly) do that with modulus, since the enum assigns 1 to\n \t * commit, so tag becomes 0.\n \t */\n-\ta_type_sort = a_type % 4;\n-\tb_type_sort = b_type % 4;\n+\ta_type_sort = a_type % tag_type_offs;\n+\tb_type_sort = b_type % tag_type_offs;\n \treturn a_type_sort > b_type_sort ? 1 : -1;\n }\n \n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421358","messageId":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH 0/7] object.c: add and use \"is expected\" utility function + object_as_type() use","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:49:55Z","receivedAt":"2021-04-09T08:50:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This goes on top of [1] and is part of a split-up [2] into more\ndigestable pieces.\n\nAs in [2] we reduce duplication of \"object %s is a %s not a %s\" in\nvarious places by moving those messages/errors/dies to using a utility\nfunction.\n\nFor the more meaty \"don't misreport objects\" change I'm planning to\nsubmit on top of this I'm then refactoring object_as_type() to not\ntake a \"quiet\" argument. This wasn't strictly needed, but makes things\nsimpler.\n\nAs it turned out we had various parts of the codebase (ab)using\nobject_as_type() just to check if something was of a given type,\nanything that deals with parsed objects can/should just use obj->type\n== OBJ_{COMMIT,TREE,BLOB,TAG} instead. This leaves object_as_type() as\na low-level function for use in the object API itself.\n\n1. http://lore.kernel.org/git/cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com\n2. https://lore.kernel.org/git/cover-00.11-00000000000-20210328T021238Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (7):\n  tree.c: fix misindentation in parse_tree_gently()\n  object.c: add a utility function for \"expected type X, got Y\"\n  object.c: add and use oid_is_type_or_die_msg() function\n  commit-graph: use obj->type, not object_as_type()\n  commit.c: don't use deref_tag() -> object_as_type()\n  object.c: normalize brace style in object_as_type()\n  object.c: remove \"quiet\" parameter from object_as_type()\n\n blob.c                 |  2 +-\n builtin/commit-graph.c |  2 +-\n builtin/fsck.c         |  2 +-\n builtin/index-pack.c   |  9 +++-----\n combine-diff.c         |  3 +--\n commit.c               | 28 ++++++++++++++---------\n merge-recursive.c      |  5 ++++-\n object.c               | 51 ++++++++++++++++++++++++++++++++++--------\n object.h               | 10 ++++++++-\n refs.c                 |  2 +-\n t/helper/test-reach.c  |  2 +-\n tag.c                  |  2 +-\n tree.c                 | 15 +++++++------\n 13 files changed, 90 insertions(+), 43 deletions(-)\n\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421359","messageId":"patch-2.7-0be843e838-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH 2/7] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:49:57Z","receivedAt":"2021-04-09T08:50:18Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor various \"Object X is not Y\" error messages so that they use\nthe same message as the long-standing object_as_type() error\nmessage. Now we'll consistently report e.g. that we got a commit when\nwe expected a tag, not just that the object is not a tag.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/index-pack.c |  9 +++------\n combine-diff.c       |  3 +--\n commit.c             | 10 ++++------\n merge-recursive.c    |  1 +\n object.c             | 25 ++++++++++++++++++++++++-\n object.h             |  5 +++++\n tree.c               |  7 ++++---\n 7 files changed, 42 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex c0e3768c32..eabd9d4677 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -218,8 +218,8 @@ static int mark_link(struct object *obj, enum object_type type,\n \tif (!obj)\n \t\treturn -1;\n \n-\tif (type != OBJ_ANY && obj->type != type)\n-\t\tdie(_(\"object type mismatch at %s\"), oid_to_hex(&obj->oid));\n+\tif (type != OBJ_ANY)\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \n \tobj->flags |= FLAG_LINK;\n \treturn 0;\n@@ -241,10 +241,7 @@ static unsigned check_object(struct object *obj)\n \t\tif (type <= 0)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\n-\t\tif (type != obj->type)\n-\t\t\tdie(_(\"object %s: expected type %s, found %s\"),\n-\t\t\t    oid_to_hex(&obj->oid),\n-\t\t\t    type_name(obj->type), type_name(type));\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \t\tobj->flags |= FLAG_CHECKED;\n \t\treturn 1;\n \t}\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 06635f91bc..aa767dbb8e 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -333,8 +333,7 @@ static char *grab_blob(struct repository *r,\n \t\tfree_filespec(df);\n \t} else {\n \t\tblob = read_object_file(oid, &type, size);\n-\t\tif (type != OBJ_BLOB)\n-\t\t\tdie(\"object '%s' is not a blob!\", oid_to_hex(oid));\n+\t\toid_is_type_or_die(oid, OBJ_BLOB, &type);\n \t}\n \treturn blob;\n }\ndiff --git a/commit.c b/commit.c\nindex 8ea55a447f..b370100367 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -299,9 +299,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \t\tif (!ret)\n \t\t\tdie(\"cannot read commit object %s\",\n \t\t\t    oid_to_hex(&commit->object.oid));\n-\t\tif (type != OBJ_COMMIT)\n-\t\t\tdie(\"expected commit for %s, got %s\",\n-\t\t\t    oid_to_hex(&commit->object.oid), type_name(type));\n+\t\toid_is_type_or_die(&commit->object.oid, OBJ_COMMIT, &type);\n \t\tif (sizep)\n \t\t\t*sizep = size;\n \t}\n@@ -489,10 +487,10 @@ int repo_parse_commit_internal(struct repository *r,\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_COMMIT) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_COMMIT, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a commit\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \n \tret = parse_commit_buffer(r, item, buffer, size, 0);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex ed31f9496c..be7f727b5a 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2971,6 +2971,7 @@ static int read_oid_strbuf(struct merge_options *opt,\n \tif (!buf)\n \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n \tif (type != OBJ_BLOB) {\n+\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n \t\tfree(buf);\n \t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n \t}\ndiff --git a/object.c b/object.c\nindex 2216cdcda2..8b2df3a94c 100644\n--- a/object.c\n+++ b/object.c\n@@ -159,6 +159,29 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n \treturn obj;\n }\n \n+static const char *object_type_mismatch_msg = N_(\"object %s is a %s, not a %s\");\n+\n+void oid_is_type_or_die(const struct object_id *oid,\n+\t\t\tenum object_type want,\n+\t\t\tenum object_type *type)\n+{\n+\tif (want == *type)\n+\t\treturn;\n+\tdie(_(object_type_mismatch_msg), oid_to_hex(oid),\n+\t    type_name(*type), type_name(want));\n+}\n+\n+int oid_is_type_or_error(const struct object_id *oid,\n+\t\t\t enum object_type want,\n+\t\t\t enum object_type *type)\n+{\n+\tif (want == *type)\n+\t\treturn 0;\n+\treturn error(_(object_type_mismatch_msg),\n+\t\t     oid_to_hex(oid), type_name(*type),\n+\t\t     type_name(want));\n+}\n+\n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n \tif (obj->type == type)\n@@ -172,7 +195,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n \t}\n \telse {\n \t\tif (!quiet)\n-\t\t\terror(_(\"object %s is a %s, not a %s\"),\n+\t\t\terror(_(object_type_mismatch_msg),\n \t\t\t      oid_to_hex(&obj->oid),\n \t\t\t      type_name(obj->type), type_name(type));\n \t\treturn NULL;\ndiff --git a/object.h b/object.h\nindex 5e7a523e85..d2d4a236d0 100644\n--- a/object.h\n+++ b/object.h\n@@ -124,6 +124,11 @@ void *create_object(struct repository *r, const struct object_id *oid, void *obj\n \n void *object_as_type(struct object *obj, enum object_type type, int quiet);\n \n+void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n+\t\t\tenum object_type *type);\n+int oid_is_type_or_error(const struct object_id *oid, enum object_type want,\n+\t\t\t enum object_type *type);\n+\n /*\n  * Returns the object, having parsed it to find out what it is.\n  *\ndiff --git a/tree.c b/tree.c\nindex 482a37d8fa..6717d982fa 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -126,6 +126,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \tenum object_type type;\n \tvoid *buffer;\n \tunsigned long size;\n+\tint ret;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n@@ -134,10 +135,10 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_TREE) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_TREE, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a tree\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \treturn parse_tree_buffer(item, buffer, size);\n }\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421360","messageId":"patch-1.7-4bf9a4f7a1-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH 1/7] tree.c: fix misindentation in parse_tree_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:49:56Z","receivedAt":"2021-04-09T08:50:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The variables declared in parse_tree_gently() had a single space after\nthe TAB. This dates back to their introduction in bd2c39f58f9 ([PATCH]\ndon't load and decompress objects twice with parse_object(),\n2005-05-06). Let's fix them to follow the style of the rest of the\nfile.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n tree.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex 410e3b477e..482a37d8fa 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -123,9 +123,9 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n \n int parse_tree_gently(struct tree *item, int quiet_on_missing)\n {\n-\t enum object_type type;\n-\t void *buffer;\n-\t unsigned long size;\n+\tenum object_type type;\n+\tvoid *buffer;\n+\tunsigned long size;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421361","messageId":"patch-3.7-fb2e4feb3d-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH 3/7] object.c: add and use oid_is_type_or_die_msg() function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:49:58Z","receivedAt":"2021-04-09T08:50:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a oid_is_type_or_die_msg() function to go with the \"error\" and\n\"die\" forms for emitting \"expected type X, got Y\" messages. This is\nuseful for callers that want the message itself as a char *.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n merge-recursive.c |  6 ++++--\n object.c          | 12 ++++++++++++\n object.h          |  3 +++\n 3 files changed, 19 insertions(+), 2 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex be7f727b5a..2429d2cb89 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2971,9 +2971,11 @@ static int read_oid_strbuf(struct merge_options *opt,\n \tif (!buf)\n \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n \tif (type != OBJ_BLOB) {\n-\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n+\t\tchar *msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n+\t\tint ret = err(opt, msg);\n \t\tfree(buf);\n-\t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n+\t\tfree(msg);\n+\t\treturn ret;\n \t}\n \tstrbuf_attach(dst, buf, size, size + 1);\n \treturn 0;\ndiff --git a/object.c b/object.c\nindex 8b2df3a94c..1573e571de 100644\n--- a/object.c\n+++ b/object.c\n@@ -182,6 +182,18 @@ int oid_is_type_or_error(const struct object_id *oid,\n \t\t     type_name(want));\n }\n \n+char* oid_is_type_or_die_msg(const struct object_id *oid,\n+\t\t\t\t   enum object_type want,\n+\t\t\t\t   enum object_type *type)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tif (want == *type)\n+\t\tBUG(\"call this just to get the message!\");\n+\tstrbuf_addf(&sb, _(object_type_mismatch_msg), oid_to_hex(oid),\n+\t\t    type_name(*type), type_name(want));\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n \tif (obj->type == type)\ndiff --git a/object.h b/object.h\nindex d2d4a236d0..cdc3242a12 100644\n--- a/object.h\n+++ b/object.h\n@@ -128,6 +128,9 @@ void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n \t\t\tenum object_type *type);\n int oid_is_type_or_error(const struct object_id *oid, enum object_type want,\n \t\t\t enum object_type *type);\n+char* oid_is_type_or_die_msg(const struct object_id *oid,\n+\t\t\t     enum object_type want,\n+\t\t\t     enum object_type *type);\n \n /*\n  * Returns the object, having parsed it to find out what it is.\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421362","messageId":"patch-4.7-995135c814-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH 4/7] commit-graph: use obj->type, not object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:49:59Z","receivedAt":"2021-04-09T08:50:27Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a check of a deref_tag() return value to just use obj->type\ninstead of object_as_type(). The object_as_type() function is for\nlow-level use by fsck, {commit,tree,blob,tag}.c and the like, here we\ncan just assume the object is fully initialized.\n\nAs can be seen in plenty of existing uses in our codebase the return\nvalue of deref_tag() won't be an obj->type == OBJ_NONE or\n!obj->parsed. Fixes code added in 2f00c355cb7 (commit-graph: drop\nCOMMIT_GRAPH_WRITE_CHECK_OIDS flag, 2020-05-13).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/commit-graph.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex cd86315221..347d65abc8 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -158,7 +158,7 @@ static int read_one_commit(struct oidset *commits, struct progress *progress,\n \t\t\t   NULL, 0);\n \tif (!result)\n \t\treturn error(_(\"invalid object: %s\"), hash);\n-\telse if (object_as_type(result, OBJ_COMMIT, 1))\n+\telse if (result->type == OBJ_COMMIT)\n \t\toidset_insert(commits, &result->oid);\n \n \tdisplay_progress(progress, oidset_size(commits));\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421363","messageId":"patch-5.7-754d5ae267-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH 5/7] commit.c: don't use deref_tag() -> object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:50:00Z","receivedAt":"2021-04-09T08:50:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a use of the object_as_type() function introduced in\n8ff226a9d5e (add object_as_type helper for casting objects,\n2014-07-13) to instead assume that we're not dealing with OBJ_NONE (or\nOBJ_BAD) from deref_tag().\n\nThis makes this code easier to read, as the reader isn't wondering why\nthe function would need to deal with that. We're simply doing a check\nof OBJ_{COMMIT,TREE,BLOB,TAG} here, not the bare-bones initialization\nobject_as_type() might be called on to do.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n commit.c | 14 ++++++++++----\n 1 file changed, 10 insertions(+), 4 deletions(-)\n\ndiff --git a/commit.c b/commit.c\nindex b370100367..437a8b8548 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -31,13 +31,19 @@ const char *commit_type = \"commit\";\n struct commit *lookup_commit_reference_gently(struct repository *r,\n \t\tconst struct object_id *oid, int quiet)\n {\n-\tstruct object *obj = deref_tag(r,\n-\t\t\t\t       parse_object(r, oid),\n-\t\t\t\t       NULL, 0);\n+\tstruct object *tmp = parse_object(r, oid);\n+\tstruct object *obj = deref_tag(r, tmp, NULL, 0);\n \n \tif (!obj)\n \t\treturn NULL;\n-\treturn object_as_type(obj, OBJ_COMMIT, quiet);\n+\n+\tif (obj->type != OBJ_COMMIT) {\n+\t\tenum object_type want = OBJ_COMMIT;\n+\t\tif (!quiet)\n+\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &want);\n+\t\treturn NULL;\n+\t}\n+\treturn (struct commit *)obj;\n }\n \n struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid)\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421364","messageId":"patch-6.7-e414cfe40c-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH 6/7] object.c: normalize brace style in object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:50:01Z","receivedAt":"2021-04-09T08:50:29Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Normalize the brace style in this function introduced in\n8ff226a9d5e (add object_as_type helper for casting objects,\n2014-07-13) to be in line with the coding style of the project.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 1573e571de..e3400d1039 100644\n--- a/object.c\n+++ b/object.c\n@@ -196,16 +196,15 @@ char* oid_is_type_or_die_msg(const struct object_id *oid,\n \n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n-\tif (obj->type == type)\n+\tif (obj->type == type) {\n \t\treturn obj;\n-\telse if (obj->type == OBJ_NONE) {\n+\t} else if (obj->type == OBJ_NONE) {\n \t\tif (type == OBJ_COMMIT)\n \t\t\tinit_commit_node((struct commit *) obj);\n \t\telse\n \t\t\tobj->type = type;\n \t\treturn obj;\n-\t}\n-\telse {\n+\t} else {\n \t\tif (!quiet)\n \t\t\terror(_(object_type_mismatch_msg),\n \t\t\t      oid_to_hex(&obj->oid),\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421365","messageId":"patch-7.7-64360ac260-20210409T083436Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH 7/7] object.c: remove \"quiet\" parameter from object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T08:50:02Z","receivedAt":"2021-04-09T08:50:31Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the now-unused \"quiet\" parameter from object_as_type(). As\nshown in preceding commits the previous users of this parameter were\nbetter off with higher-level APIs.\n\nThe \"quiet\" parameter was originally introduced when the\nobject_as_type() function was added in 8ff226a9d5e (add object_as_type\nhelper for casting objects,.  2014-07-13), but the commit.c use-case\nfor it is now gone.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n blob.c                | 2 +-\n builtin/fsck.c        | 2 +-\n commit.c              | 8 +++++---\n object.c              | 9 ++++-----\n object.h              | 2 +-\n refs.c                | 2 +-\n t/helper/test-reach.c | 2 +-\n tag.c                 | 2 +-\n tree.c                | 2 +-\n 9 files changed, 16 insertions(+), 15 deletions(-)\n\ndiff --git a/blob.c b/blob.c\nindex 389a7546dc..b5bd27844e 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -10,7 +10,7 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_blob_node(r));\n-\treturn object_as_type(obj, OBJ_BLOB, 0);\n+\treturn object_as_type(obj, OBJ_BLOB);\n }\n \n int parse_blob_buffer(struct blob *item)\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 70ff95837a..5d534cf218 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -221,7 +221,7 @@ static void mark_unreachable_referents(const struct object_id *oid)\n \t\tenum object_type type = oid_object_info(the_repository,\n \t\t\t\t\t\t\t&obj->oid, NULL);\n \t\tif (type > 0)\n-\t\t\tobject_as_type(obj, type, 0);\n+\t\t\tobject_as_type(obj, type);\n \t}\n \n \toptions.walk = mark_used;\ndiff --git a/commit.c b/commit.c\nindex 437a8b8548..3014559d66 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -38,9 +38,11 @@ struct commit *lookup_commit_reference_gently(struct repository *r,\n \t\treturn NULL;\n \n \tif (obj->type != OBJ_COMMIT) {\n-\t\tenum object_type want = OBJ_COMMIT;\n+\t\tif (obj->type <= 0)\n+\t\t\tBUG(\"noes\");\n \t\tif (!quiet)\n-\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &want);\n+\t\t\tfprintf(stderr, \"noes ohes\");/*\n+\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &obj->type);*/\n \t\treturn NULL;\n \t}\n \treturn (struct commit *)obj;\n@@ -68,7 +70,7 @@ struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_commit_node(r));\n-\treturn object_as_type(obj, OBJ_COMMIT, 0);\n+\treturn object_as_type(obj, OBJ_COMMIT);\n }\n \n struct commit *lookup_commit_reference_by_name(const char *name)\ndiff --git a/object.c b/object.c\nindex e3400d1039..715e358603 100644\n--- a/object.c\n+++ b/object.c\n@@ -194,7 +194,7 @@ char* oid_is_type_or_die_msg(const struct object_id *oid,\n \treturn strbuf_detach(&sb, NULL);\n }\n \n-void *object_as_type(struct object *obj, enum object_type type, int quiet)\n+void *object_as_type(struct object *obj, enum object_type type)\n {\n \tif (obj->type == type) {\n \t\treturn obj;\n@@ -205,10 +205,9 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n \t\t\tobj->type = type;\n \t\treturn obj;\n \t} else {\n-\t\tif (!quiet)\n-\t\t\terror(_(object_type_mismatch_msg),\n-\t\t\t      oid_to_hex(&obj->oid),\n-\t\t\t      type_name(obj->type), type_name(type));\n+\t\terror(_(object_type_mismatch_msg),\n+\t\t      oid_to_hex(&obj->oid),\n+\t\t      type_name(obj->type), type_name(type));\n \t\treturn NULL;\n \t}\n }\ndiff --git a/object.h b/object.h\nindex cdc3242a12..61857ee48c 100644\n--- a/object.h\n+++ b/object.h\n@@ -122,7 +122,7 @@ struct object *lookup_object(struct repository *r, const struct object_id *oid);\n \n void *create_object(struct repository *r, const struct object_id *oid, void *obj);\n \n-void *object_as_type(struct object *obj, enum object_type type, int quiet);\n+void *object_as_type(struct object *obj, enum object_type type);\n \n void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n \t\t\tenum object_type *type);\ndiff --git a/refs.c b/refs.c\nindex 261fd82beb..7f4ca3441c 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -341,7 +341,7 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid\n \n \tif (o->type == OBJ_NONE) {\n \t\tint type = oid_object_info(the_repository, name, NULL);\n-\t\tif (type < 0 || !object_as_type(o, type, 0))\n+\t\tif (type < 0 || !object_as_type(o, type))\n \t\t\treturn PEEL_INVALID;\n \t}\n \ndiff --git a/t/helper/test-reach.c b/t/helper/test-reach.c\nindex cda804ed79..c9fd74b21f 100644\n--- a/t/helper/test-reach.c\n+++ b/t/helper/test-reach.c\n@@ -67,7 +67,7 @@ int cmd__reach(int ac, const char **av)\n \t\t\tdie(\"failed to load commit for input %s resulting in oid %s\\n\",\n \t\t\t    buf.buf, oid_to_hex(&oid));\n \n-\t\tc = object_as_type(peeled, OBJ_COMMIT, 0);\n+\t\tc = object_as_type(peeled, OBJ_COMMIT);\n \n \t\tif (!c)\n \t\t\tdie(\"failed to load commit for input %s resulting in oid %s\\n\",\ndiff --git a/tag.c b/tag.c\nindex 871c4c9a14..e750b00cf5 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -104,7 +104,7 @@ struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_tag_node(r));\n-\treturn object_as_type(obj, OBJ_TAG, 0);\n+\treturn object_as_type(obj, OBJ_TAG);\n }\n \n static timestamp_t parse_tag_date(const char *buf, const char *tail)\ndiff --git a/tree.c b/tree.c\nindex 6717d982fa..0bd18abd64 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -107,7 +107,7 @@ struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_object(r, oid, alloc_tree_node(r));\n-\treturn object_as_type(obj, OBJ_TREE, 0);\n+\treturn object_as_type(obj, OBJ_TREE);\n }\n \n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n-- \n2.31.1.592.gdf54ba9003\n\n"},{"id":"421420","messageId":"YHCUFwZMitOXELpq@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-1.3-68a7709fe5-20210409T080534Z-avarab@gmail.com","subject":"Re: [PATCH 1/2] blob.c: remove buffer & size arguments to parse_blob_buffer()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T17:51:19Z","receivedAt":"2021-04-09T17:51:21Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:07:27AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> As noted in the comment introduced in 837d395a5c0 (Replace\n> parse_blob() with an explanatory comment, 2010-01-18) the old\n> parse_blob() function and the current parse_blob_buffer() exist merely\n> to provide consistency in the API.\n> \n> We're not going to parse blobs like we \"parse\" commits, trees or\n> tags. So let's not have the parse_blob_buffer() take arguments that\n> pretends that we do. Its only use is to set the \"parsed\" flag.\n> \n> See bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\n> parse_object(), 2005-05-06) for the introduction of parse_blob_buffer().\n\nOK. Calling it parse_blob_buffer() is a little silly since it doesn't\neven take a buffer anymore. But I guess parse_blob() might imply that it\nactually loads the contents from disk to check them (which the other\nparse_foo() functions do), so that's not a good name.\n\nSo this might be the least bad thing. Given that there are only two\ncallers, just setting blob->object.parsed might not be unreasonable,\neither. But I don't think it's worth spending too much time on.\n\n> @@ -266,7 +266,7 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n>  \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n>  \t\t\treturn NULL;\n>  \t\t}\n> -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n> +\t\tparse_blob_buffer(lookup_blob(r, oid));\n>  \t\treturn lookup_object(r, oid);\n\nNot new in your patch, but I wondered if this could cause a segfault\nwhen lookup_blob() returns NULL. I _think_ the answer is \"no\". We'd hit\nthis code path when either:\n\n  - lookup_object() returns an object with type OBJ_BLOB, in which case\n    lookup_blob() would return that same object\n\n  - lookup_object() returned NULL, in which case lookup_blob() will call\n    it again, get NULL again, and then auto-create the blob and return\n    it\n\nSo I think it is OK. But there are a bunch of duplicate hash lookups in\nthis code. It would be clearer and more efficient as:\n\ndiff --git a/object.c b/object.c\nindex 2c32691dc4..2dfa038f13 100644\n--- a/object.c\n+++ b/object.c\n@@ -262,12 +262,14 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n \t    (!obj && repo_has_object_file(r, oid) &&\n \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n+\t\tif (!obj)\n+\t\t\tobj = create_object(r, oid, alloc_blob_node(r));\n \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n \t\t\treturn NULL;\n \t\t}\n-\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n-\t\treturn lookup_object(r, oid);\n+\t\tparse_blob_buffer(obj, NULL, 0);\n+\t\treturn obj;\n \t}\n \n \tbuffer = repo_read_object_file(r, oid, &type, &size);\n\nbut I doubt the efficiency matters much in practice. Those hash lookups\nwill be lost in the noise of computing the hash of the blob contents.\n\n-Peff\n"},{"id":"421421","messageId":"YHCUmM7CqJ83ZXrL@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-2.3-f1fcc31717-20210409T080534Z-avarab@gmail.com","subject":"Re: [PATCH 2/2] object.c: initialize automatic variable in lookup_object()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T17:53:28Z","receivedAt":"2021-04-09T17:53:31Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:07:28AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> Initialize a \"struct object obj*\" variable to NULL explicitly and\n> return it instead of leaving it uninitialized until the \"while\"\n> loop.\n> \n> There was no bug here, it's just less confusing when debugging if the\n> \"obj\" is either NULL or a valid object, not some random invalid\n> pointer.\n>\n> [...]\n>\n>  struct object *lookup_object(struct repository *r, const struct object_id *oid)\n>  {\n>  \tunsigned int i, first;\n> -\tstruct object *obj;\n> +\tstruct object *obj = NULL;\n>  \n>  \tif (!r->parsed_objects->obj_hash)\n> -\t\treturn NULL;\n> +\t\treturn obj;\n\nI actually prefer the original style (where any \"can we bail early\"\nchecks just explicitly return NULL, rather than making you check to see\nthat obj is NULL). But it's pretty subjective, and I don't feel\nstrongly.\n\n>  \tfirst = i = hash_obj(oid, r->parsed_objects->obj_hash_size);\n>  \twhile ((obj = r->parsed_objects->obj_hash[i]) != NULL) {\n\nThe important thing is that \"obj\" is not used uninitialized, which it\nisn't (before or after).\n\n-Peff\n"},{"id":"421422","messageId":"YHCXux5KJmwX3OSv@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-1.6-820f3aed21-20210409T082935Z-avarab@gmail.com","subject":"Re: [PATCH 1/6] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T18:06:51Z","receivedAt":"2021-04-09T18:06:53Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:32:49AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> diff --git a/object.c b/object.c\n> index 7fdca3ed1e..88de01e5ac 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -39,9 +39,6 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n>  {\n>  \tint i;\n>  \n> -\tif (len < 0)\n> -\t\tlen = strlen(str);\n> -\n\nThe \"ssize_t len\" in the parameters could become a size_t now, right?\n\nNot strictly necessary, but in theory it may help static analysis catch\na caller who mistakenly tries to pass -1 (though in practice I suspect\nit does not help that much, because any of gcc's sign-conversion\nwarnings generate far too much noise to be useful with our current\ncodebase).\n\n-Peff\n"},{"id":"421423","messageId":"YHCYfeRsHU34ZF/l@coredump.intra.peff.net","threadId":"1003","inReplyTo":"YHCXux5KJmwX3OSv@coredump.intra.peff.net","subject":"Re: [PATCH 1/6] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T18:10:05Z","receivedAt":"2021-04-09T18:10:08Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 02:06:51PM -0400, Jeff King wrote:\n\n> On Fri, Apr 09, 2021 at 10:32:49AM +0200, Ævar Arnfjörð Bjarmason wrote:\n> \n> > diff --git a/object.c b/object.c\n> > index 7fdca3ed1e..88de01e5ac 100644\n> > --- a/object.c\n> > +++ b/object.c\n> > @@ -39,9 +39,6 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n> >  {\n> >  \tint i;\n> >  \n> > -\tif (len < 0)\n> > -\t\tlen = strlen(str);\n> > -\n> \n> The \"ssize_t len\" in the parameters could become a size_t now, right?\n> \n> Not strictly necessary, but in theory it may help static analysis catch\n> a caller who mistakenly tries to pass -1 (though in practice I suspect\n> it does not help that much, because any of gcc's sign-conversion\n> warnings generate far too much noise to be useful with our current\n> codebase).\n\nActually, seeing patch 2, which changes the signature, mostly deals with\nthis. The compiler would complain about any existing calls because of\ndropping the \"gentle\" parameter (it is up to the human to realize that\nthey need to make sure we are not passing a negative len, but hopefully\nthey would look at the other commits at that point).\n\n-Peff\n"},{"id":"421427","messageId":"YHCYqpYi6TxWh/KC@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-2.6-daed40c479-20210409T082935Z-avarab@gmail.com","subject":"Re: [PATCH 2/6] object.c: remove \"gently\" argument to type_from_string_gently()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T18:10:50Z","receivedAt":"2021-04-09T18:10:55Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:32:50AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> Get rid of the \"gently\" argument to type_from_string_gently() to make\n> it consistent with most other *_gently() functions. It's already a\n> \"gentle\" function, it shouldn't need a boolean argument telling it to\n> be gentle.\n> \n> The reason it had a \"gentle\" parameter was because until the preceding\n> commit \"type_from_string()\" was a macro resolving to\n> \"type_from_string_gently()\", it's now a function.\n> \n> This refactoring of adding a third parameter was done in\n> fe8e3b71805 (Refactor type_from_string() to allow continuing after\n> detecting an error, 2014-09-10) in preparation for its use in\n> fsck.c.\n> \n> Simplifying this means we can move the die() into the simpler\n> type_from_string() function.\n\nYeah, this makes sense (and the change of signature will catch any\ncallers in topics-in-flight).\n\n-Peff\n"},{"id":"421448","messageId":"YHCZh5nLNVEHCWV2@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-3.6-7fd86f6699-20210409T082935Z-avarab@gmail.com","subject":"Re: [PATCH 3/6] object.c: make type_from_string() return \"enum object_type\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T18:14:31Z","receivedAt":"2021-04-09T18:14:44Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:32:51AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> Change the type_from_string*() functions to return an \"enum\n> object_type\", but don't refactor their callers to check for \"==\n> OBJ_BAD\" instead of \"< 0\".\n> \n> Refactoring the check of the return value to check == OBJ_BAD would\n> now be equivalent to \"ret < 0\", but the consensus on an earlier\n> version of this patch was to not do that, and to instead use -1\n> consistently as a return value. It just so happens that OBJ_BAD == -1,\n> but let's not put a hard reliance on that.\n\nI think what the patch is doing is good, but this rationale misses the\nmain point of that discussion, I think. I doubt that the value of\nOBJ_BAD would ever change. But the point was that we could grow a new\n\"failure\" value at \"-2\", and we would want to catch here (I do consider\nit relatively unlikely, but that IMHO is the reason to keep the negative\ncheck).\n\nI think for the same reason that \"return OBJ_BAD\" instead of \"return -1\"\nwould be just fine (it is not \"just so happens\" that OBJ_BAD is\nnegative; that was deliberate to allow exactly this convention). But I\nam also OK with leaving the \"return -1\" calls.\n\n-Peff\n"},{"id":"421449","messageId":"YHCb1JQ7Nv9b6jDK@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-4.6-ebea1b2b50-20210409T082935Z-avarab@gmail.com","subject":"Re: [PATCH 4/6] object-file.c: make oid_object_info() return \"enum object_type\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T18:24:20Z","receivedAt":"2021-04-09T18:24:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:32:52AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> Change oid_object_info() to return an \"enum object_type\". Unlike\n> oid_object_info_extended() function the simpler oid_object_info()\n> explicitly returns the oi.typep member, which is itself an \"enum\n> object_type\".\n\nOK. I don't think there is much difference from the compiler perspective\n(because of the equivalence of enums and ints in C), but it gives a clue\nto the reader about how the value is meant to be interpreted.\n\n> @@ -405,10 +404,10 @@ static int repo_collect_ambiguous(struct repository *r,\n>  static int sort_ambiguous(const void *a, const void *b, void *ctx)\n>  {\n>  \tstruct repository *sort_ambiguous_repo = ctx;\n> -\tint a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n> -\tint b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n> -\tint a_type_sort;\n> -\tint b_type_sort;\n> +\tenum object_type a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n> +\tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n> +\tenum object_type a_type_sort;\n> +\tenum object_type b_type_sort;\n\nNot new in your patch, but the way this function uses modulo is\ninteresting:\n\n  a_type_sort = a_type % 4;\n  b_type_sort = b_type % 4;\n\nWhat happens if we got OBJ_BAD as one of the results? We are not\nindexing any arrays here, so I guess the worst case is that we sort\nthings in a weird way (and presumably we'd barf later when trying to\nshow the output anyway).\n\n> --- a/object-store.h\n> +++ b/object-store.h\n> @@ -208,7 +208,9 @@ static inline void *repo_read_object_file(struct repository *r,\n>  #endif\n>  \n>  /* Read and unpack an object file into memory, write memory to an object file */\n> -int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n> +enum object_type oid_object_info(struct repository *r,\n> +\t\t\t\t const struct object_id *,\n> +\t\t\t\t unsigned long *);\n\nAlso not new in your patch, but that comment sure is misleading. :)\n\n-Peff\n"},{"id":"421450","messageId":"YHCekt1iXjy2NLrP@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-5.6-94e13611f0-20210409T082935Z-avarab@gmail.com","subject":"Re: [PATCH 5/6] object-name.c: make dependency on object_type order more obvious","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T18:36:02Z","receivedAt":"2021-04-09T18:36:05Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:32:53AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> Add an assert to make it more obvious that we were effectively\n> hardcoding OBJ_TAG in sort_ambiguous() as \"4\".\n> \n> I wrote this code in 5cc044e0257 (get_short_oid: sort ambiguous\n> objects by type, then SHA-1, 2018-05-10), there was already a comment\n> about this magic, but let's make sure that someone doing a potential\n> reordering of \"enum object_type\" in the future would notice it\n> breaking this function (and probably a bunch of other things...).\n\nYeah, those object type values are used for the on-disk formats, so\nquite a lot would break.\n\n> @@ -408,6 +408,8 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)\n>  \tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n>  \tenum object_type a_type_sort;\n>  \tenum object_type b_type_sort;\n> +\tconst enum object_type tag_type_offs = OBJ_TAG - OBJ_NONE;\n> +\tassert(tag_type_offs == 4);\n\nThis protects us against shifting of the values or reordering within the\nmain 4 types, but it doesn't protect against new types, nor reordering\nin which the main 4 types are no longer contiguous. E.g.:\n\n  enum object_type {\n          OBJ_NONE = 0,\n\t  OBJ_REF_DELTA = 1,\n\t  OBJ_OFS_DELTA = 2,\n\t  OBJ_COMMIT = 3,\n\t  OBJ_TAG = 4,\n\t  OBJ_BLOB = 5,\n\t  OBJ_TREE = 6,\n  };\n\nwould be wrong. I dunno. I guess in some sense I am glad to see an\nattempt at automated enforcement of assumptions. But I think if we are\nworried about the object_type enum changing, we'd do better to write\nthis function in a less-clever way.\n\n  /* sort tags before anything else */\n  if (a_type == OBJ_TAG)\n          a_type = 0;\n  if (b_type == OBJ_TAG)\n          b_type = 0;\n\nOf course that is still assuming that normal values are all positive,\nbut that seems reasonable. If you really wanted to be agnostic, you\ncould assign the minimum value.  But you can't easily know that for an\nenum. So you'd want to store them as ints (reversing your previous\ncommit!) and using INT_MIN.\n\nThe conditional probably performs less well in a tight loop, but I doubt\nthat matters for the size of array we expect to sort (if we cared about\nperformance we would not call oid_object_info() twice inside the\ncomparator!).\n\n-Peff\n"},{"id":"421451","messageId":"YHCgDm0KVygpjkNU@coredump.intra.peff.net","threadId":"1003","inReplyTo":"patch-6.6-3279d67d2b-20210409T082935Z-avarab@gmail.com","subject":"Re: [PATCH 6/6] tag.c: use type_from_string_gently() when parsing tags","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T18:42:22Z","receivedAt":"2021-04-09T18:42:24Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 10:32:54AM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> Change a series of strcmp() to instead use type_from_string_gently()\n> to get the integer type early, and then use that for comparison.\n\nThe result looks much nicer.\n\nOne interesting note...\n\n> @@ -162,23 +162,24 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u\n>  \t\treturn -1;\n>  \tbufptr += 5;\n>  \tnl = memchr(bufptr, '\\n', tail - bufptr);\n> -\tif (!nl || sizeof(type) <= (nl - bufptr))\n> +\tif (!nl)\n> +\t\treturn -1;\n> +\ttype = type_from_string_gently(bufptr, nl - bufptr);\n> +\tif (type < 0)\n>  \t\treturn -1;\n\nIf we got anything but the main-4 types here, we'll return an error.\nSo we know here:\n\n> -\tif (!strcmp(type, blob_type)) {\n> +\tif (type == OBJ_BLOB) {\n>  \t\titem->tagged = (struct object *)lookup_blob(r, &oid);\n> -\t} else if (!strcmp(type, tree_type)) {\n> +\t} else if (type == OBJ_TREE) {\n>  \t\titem->tagged = (struct object *)lookup_tree(r, &oid);\n> -\t} else if (!strcmp(type, commit_type)) {\n> +\t} else if (type == OBJ_COMMIT) {\n>  \t\titem->tagged = (struct object *)lookup_commit(r, &oid);\n> -\t} else if (!strcmp(type, tag_type)) {\n> +\t} else if (type == OBJ_TAG) {\n>  \t\titem->tagged = (struct object *)lookup_tag(r, &oid);\n>  \t} else {\n>  \t\treturn error(\"unknown tag type '%s' in %s\",\n> -\t\t\t     type, oid_to_hex(&item->object.oid));\n> +\t\t\t     type_name(type), oid_to_hex(&item->object.oid));\n>  \t}\n\nThat the final \"else\" clause can't be reached. I don't mind being\ndefensive, but if it _is_ reached, then we'd feed that unknown type to\ntype_name(), which will return NULL for unknown items (unless I guess it\nhas also learned about the hypothetical new type).\n\nI think this should just be:\n\n  else {\n          BUG(\"type_from_string gave us an unknown type: %d\", (int)type);\n  }\n\nwhich makes it clear we expect the code can't be reached, and doesn't\nmake any assumptions about what we can do with the odd value.\n\n-Peff\n"},{"id":"421469","messageId":"87fszzgs86.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"YHCZh5nLNVEHCWV2@coredump.intra.peff.net","subject":"Re: [PATCH 3/6] object.c: make type_from_string() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-09T19:42:17Z","receivedAt":"2021-04-09T19:42:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Apr 09 2021, Jeff King wrote:\n\n> On Fri, Apr 09, 2021 at 10:32:51AM +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>> Change the type_from_string*() functions to return an \"enum\n>> object_type\", but don't refactor their callers to check for \"==\n>> OBJ_BAD\" instead of \"< 0\".\n>> \n>> Refactoring the check of the return value to check == OBJ_BAD would\n>> now be equivalent to \"ret < 0\", but the consensus on an earlier\n>> version of this patch was to not do that, and to instead use -1\n>> consistently as a return value. It just so happens that OBJ_BAD == -1,\n>> but let's not put a hard reliance on that.\n>\n> I think what the patch is doing is good, but this rationale misses the\n> main point of that discussion, I think. I doubt that the value of\n> OBJ_BAD would ever change. But the point was that we could grow a new\n> \"failure\" value at \"-2\", and we would want to catch here (I do consider\n> it relatively unlikely, but that IMHO is the reason to keep the negative\n> check).\n>\n> I think for the same reason that \"return OBJ_BAD\" instead of \"return -1\"\n> would be just fine (it is not \"just so happens\" that OBJ_BAD is\n> negative; that was deliberate to allow exactly this convention). But I\n> am also OK with leaving the \"return -1\" calls.\n\nI'm beginning to think in response to this and the comment on 5/6 that\nit might be cleaner to split up the object_type enum, as demonstrated\nfor a config.[ch] feature in [1].\n\nConverting back and forth between them is a bit nasty, and having\nmultiple interchangable OBJ_* constants with identical values just to\nsatisfy them being in different enums, but it would allow having the\ncompiler explicitly help check that callers cover all possible cases of\nvalues they could get.\n\nMost callers just get OBJ_{COMMIT,TREE,BLOB,TAG} some more get that plus\nOBJ_{BAD,NONE}, almost nobody gets OBJ_{OFS,REF}_DELTA, and AFAICT just\nthe peel code cares about OBJ_ANY. We then have an OBJ_MAX nobody's ever\nused for anything (I've got some unsubmitted patch somewhere to remove\nit).\n\nWhat do you think about that sort of approach? I haven't convinced\nmyself that it's a good idea, so far I just thought bridging the gap of\nthings that return \"enum\" actually having that as part of their\nsignature for human legibility, even if C itself doesn't care about the\ndifference, and we currently can't get much/any of the benefits of the\ncompiler catching non-exhaustive \"case\" statements (unless every\ncallsite is to include OBJ_OFS etc.).\n\n1. https://lore.kernel.org/git/875z0wicmp.fsf@evledraar.gmail.com/\n"},{"id":"421480","messageId":"YHDHO/EXaSptqkaE@coredump.intra.peff.net","threadId":"1003","inReplyTo":"87fszzgs86.fsf@evledraar.gmail.com","subject":"Re: [PATCH 3/6] object.c: make type_from_string() return \"enum object_type\"","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-09T21:29:31Z","receivedAt":"2021-04-09T21:29:35Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Fri, Apr 09, 2021 at 09:42:17PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> > I think what the patch is doing is good, but this rationale misses the\n> > main point of that discussion, I think. I doubt that the value of\n> > OBJ_BAD would ever change. But the point was that we could grow a new\n> > \"failure\" value at \"-2\", and we would want to catch here (I do consider\n> > it relatively unlikely, but that IMHO is the reason to keep the negative\n> > check).\n> >\n> > I think for the same reason that \"return OBJ_BAD\" instead of \"return -1\"\n> > would be just fine (it is not \"just so happens\" that OBJ_BAD is\n> > negative; that was deliberate to allow exactly this convention). But I\n> > am also OK with leaving the \"return -1\" calls.\n> \n> I'm beginning to think in response to this and the comment on 5/6 that\n> it might be cleaner to split up the object_type enum, as demonstrated\n> for a config.[ch] feature in [1].\n> \n> Converting back and forth between them is a bit nasty, and having\n> multiple interchangable OBJ_* constants with identical values just to\n> satisfy them being in different enums, but it would allow having the\n> compiler explicitly help check that callers cover all possible cases of\n> values they could get.\n> \n> Most callers just get OBJ_{COMMIT,TREE,BLOB,TAG} some more get that plus\n> OBJ_{BAD,NONE}, almost nobody gets OBJ_{OFS,REF}_DELTA, and AFAICT just\n> the peel code cares about OBJ_ANY. We then have an OBJ_MAX nobody's ever\n> used for anything (I've got some unsubmitted patch somewhere to remove\n> it).\n> \n> What do you think about that sort of approach? I haven't convinced\n> myself that it's a good idea, so far I just thought bridging the gap of\n> things that return \"enum\" actually having that as part of their\n> signature for human legibility, even if C itself doesn't care about the\n> difference, and we currently can't get much/any of the benefits of the\n> compiler catching non-exhaustive \"case\" statements (unless every\n> callsite is to include OBJ_OFS etc.).\n\nI suspect you'll end up with a lot of awkward spots. I do agree that\n_most_ callers only care about getting one of the actual 4 object types,\nor an error. But those values are tied to the delta ones internally\n(when we see a delta type, and then later decide to promote it to the\n\"real\" type). And of course those are all used to read and write the\non-disk bits, too.\n\nSo while there might be some way of doing this cleaner, it hasn't\nhistorically been a place we've seen a lot of problems (at least not\nthat I recall). So it seems like a pretty deep rabbit hole that is not\nlikely to give a lot of benefit.\n\n-Peff\n"},{"id":"421489","messageId":"xmqqeefjm6nm.fsf@gitster.g","threadId":"1003","inReplyTo":"YHCUFwZMitOXELpq@coredump.intra.peff.net","subject":"Re: [PATCH 1/2] blob.c: remove buffer & size arguments to parse_blob_buffer()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-09T22:31:41Z","receivedAt":"2021-04-09T22:31:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> OK. Calling it parse_blob_buffer() is a little silly since it doesn't\n> even take a buffer anymore. But I guess parse_blob() might imply that it\n> actually loads the contents from disk to check them (which the other\n> parse_foo() functions do), so that's not a good name.\n\nmark_object_as_parsed(), perhaps?\n\n> So this might be the least bad thing. Given that there are only two\n> callers, just setting blob->object.parsed might not be unreasonable,\n> either. But I don't think it's worth spending too much time on.\n\nYup.\n"},{"id":"421490","messageId":"xmqqa6q7m6mj.fsf@gitster.g","threadId":"1003","inReplyTo":"YHCUmM7CqJ83ZXrL@coredump.intra.peff.net","subject":"Re: [PATCH 2/2] object.c: initialize automatic variable in lookup_object()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-09T22:32:20Z","receivedAt":"2021-04-09T22:32:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n>>  struct object *lookup_object(struct repository *r, const struct object_id *oid)\n>>  {\n>>  \tunsigned int i, first;\n>> -\tstruct object *obj;\n>> +\tstruct object *obj = NULL;\n>>  \n>>  \tif (!r->parsed_objects->obj_hash)\n>> -\t\treturn NULL;\n>> +\t\treturn obj;\n>\n> I actually prefer the original style (where any \"can we bail early\"\n> checks just explicitly return NULL, rather than making you check to see\n> that obj is NULL).\n\nPerhaps I should return \"me too\" here.\n\n\n\n"},{"id":"421528","messageId":"87y2dqfgbb.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"YHCUFwZMitOXELpq@coredump.intra.peff.net","subject":"Re: [PATCH 1/2] blob.c: remove buffer & size arguments to parse_blob_buffer()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-10T12:57:12Z","receivedAt":"2021-04-10T12:57:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, Apr 09 2021, Jeff King wrote:\n\n> On Fri, Apr 09, 2021 at 10:07:27AM +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>> As noted in the comment introduced in 837d395a5c0 (Replace\n>> parse_blob() with an explanatory comment, 2010-01-18) the old\n>> parse_blob() function and the current parse_blob_buffer() exist merely\n>> to provide consistency in the API.\n>> \n>> We're not going to parse blobs like we \"parse\" commits, trees or\n>> tags. So let's not have the parse_blob_buffer() take arguments that\n>> pretends that we do. Its only use is to set the \"parsed\" flag.\n>> \n>> See bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\n>> parse_object(), 2005-05-06) for the introduction of parse_blob_buffer().\n>\n> OK. Calling it parse_blob_buffer() is a little silly since it doesn't\n> even take a buffer anymore. But I guess parse_blob() might imply that it\n> actually loads the contents from disk to check them (which the other\n> parse_foo() functions do), so that's not a good name.\n>\n> So this might be the least bad thing. Given that there are only two\n> callers, just setting blob->object.parsed might not be unreasonable,\n> either. But I don't think it's worth spending too much time on.\n>\n>> @@ -266,7 +266,7 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n>>  \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n>>  \t\t\treturn NULL;\n>>  \t\t}\n>> -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n>> +\t\tparse_blob_buffer(lookup_blob(r, oid));\n>>  \t\treturn lookup_object(r, oid);\n>\n> Not new in your patch, but I wondered if this could cause a segfault\n> when lookup_blob() returns NULL. I _think_ the answer is \"no\". We'd hit\n> this code path when either:\n>\n>   - lookup_object() returns an object with type OBJ_BLOB, in which case\n>     lookup_blob() would return that same object\n>\n>   - lookup_object() returned NULL, in which case lookup_blob() will call\n>     it again, get NULL again, and then auto-create the blob and return\n>     it\n>\n> So I think it is OK. But there are a bunch of duplicate hash lookups in\n> this code. It would be clearer and more efficient as:\n>\n> diff --git a/object.c b/object.c\n> index 2c32691dc4..2dfa038f13 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -262,12 +262,14 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n>  \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n>  \t    (!obj && repo_has_object_file(r, oid) &&\n>  \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n> +\t\tif (!obj)\n> +\t\t\tobj = create_object(r, oid, alloc_blob_node(r));\n>  \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n>  \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n>  \t\t\treturn NULL;\n>  \t\t}\n> -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n> -\t\treturn lookup_object(r, oid);\n> +\t\tparse_blob_buffer(obj, NULL, 0);\n> +\t\treturn obj;\n>  \t}\n>  \n>  \tbuffer = repo_read_object_file(r, oid, &type, &size);\n>\n> but I doubt the efficiency matters much in practice. Those hash lookups\n> will be lost in the noise of computing the hash of the blob contents.\n\nI was trying to keep the changes smaller, but what about just doing this?:\n\ndiff --git a/blob.c b/blob.c\nindex 182718aba9..69293e7d8e 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -5,16 +5,16 @@\n \n const char *blob_type = \"blob\";\n \n+struct blob *create_blob(struct repository *r, const struct object_id *oid)\n+{\n+\treturn create_object(r, oid, alloc_blob_node(r));\n+}\n+\n struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n-\t\treturn create_object(r, oid, alloc_blob_node(r));\n-\treturn object_as_type(obj, OBJ_BLOB, 0);\n-}\n+\t\treturn create_blob(r, oid);\n \n-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n-{\n-\titem->object.parsed = 1;\n-\treturn 0;\n+\treturn object_as_type(obj, OBJ_BLOB, 0);\n }\ndiff --git a/blob.h b/blob.h\nindex 1664872055..ad34f0e9cc 100644\n--- a/blob.h\n+++ b/blob.h\n@@ -9,10 +9,9 @@ struct blob {\n \tstruct object object;\n };\n \n+struct blob *create_blob(struct repository *r, const struct object_id *oid);\n struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n \n-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n-\n /**\n  * Blobs do not contain references to other objects and do not have\n  * structured data that needs parsing. However, code may use the\ndiff --git a/object.c b/object.c\nindex 78343781ae..2699431404 100644\n--- a/object.c\n+++ b/object.c\n@@ -195,8 +195,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \tif (type == OBJ_BLOB) {\n \t\tstruct blob *blob = lookup_blob(r, oid);\n \t\tif (blob) {\n-\t\t\tif (parse_blob_buffer(blob, buffer, size))\n-\t\t\t\treturn NULL;\n+\t\t\tblob->object.parsed = 1;\n \t\t\tobj = &blob->object;\n \t\t}\n \t} else if (type == OBJ_TREE) {\n@@ -262,12 +261,16 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n \t    (!obj && repo_has_object_file(r, oid) &&\n \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n+\t\tstruct blob *blob;\n+\t\tif (!obj)\n+\t\t\tblob = create_blob(r, oid);\n \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n \t\t\treturn NULL;\n \t\t}\n-\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n-\t\treturn lookup_object(r, oid);\n+\t\tobj = &blob->object;\n+\t\tobj->parsed = 1;\n+\t\treturn obj;\n \t}\n \n \tbuffer = repo_read_object_file(r, oid, &type, &size);\n"},{"id":"421530","messageId":"87v98ufg3i.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"87y2dqfgbb.fsf@evledraar.gmail.com","subject":"Re: [PATCH 1/2] blob.c: remove buffer & size arguments to parse_blob_buffer()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-10T13:01:53Z","receivedAt":"2021-04-10T13:01:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Sat, Apr 10 2021, Ævar Arnfjörð Bjarmason wrote:\n\n> On Fri, Apr 09 2021, Jeff King wrote:\n>\n>> On Fri, Apr 09, 2021 at 10:07:27AM +0200, Ævar Arnfjörð Bjarmason wrote:\n>>\n>>> As noted in the comment introduced in 837d395a5c0 (Replace\n>>> parse_blob() with an explanatory comment, 2010-01-18) the old\n>>> parse_blob() function and the current parse_blob_buffer() exist merely\n>>> to provide consistency in the API.\n>>> \n>>> We're not going to parse blobs like we \"parse\" commits, trees or\n>>> tags. So let's not have the parse_blob_buffer() take arguments that\n>>> pretends that we do. Its only use is to set the \"parsed\" flag.\n>>> \n>>> See bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\n>>> parse_object(), 2005-05-06) for the introduction of parse_blob_buffer().\n>>\n>> OK. Calling it parse_blob_buffer() is a little silly since it doesn't\n>> even take a buffer anymore. But I guess parse_blob() might imply that it\n>> actually loads the contents from disk to check them (which the other\n>> parse_foo() functions do), so that's not a good name.\n>>\n>> So this might be the least bad thing. Given that there are only two\n>> callers, just setting blob->object.parsed might not be unreasonable,\n>> either. But I don't think it's worth spending too much time on.\n>>\n>>> @@ -266,7 +266,7 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n>>>  \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n>>>  \t\t\treturn NULL;\n>>>  \t\t}\n>>> -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n>>> +\t\tparse_blob_buffer(lookup_blob(r, oid));\n>>>  \t\treturn lookup_object(r, oid);\n>>\n>> Not new in your patch, but I wondered if this could cause a segfault\n>> when lookup_blob() returns NULL. I _think_ the answer is \"no\". We'd hit\n>> this code path when either:\n>>\n>>   - lookup_object() returns an object with type OBJ_BLOB, in which case\n>>     lookup_blob() would return that same object\n>>\n>>   - lookup_object() returned NULL, in which case lookup_blob() will call\n>>     it again, get NULL again, and then auto-create the blob and return\n>>     it\n>>\n>> So I think it is OK. But there are a bunch of duplicate hash lookups in\n>> this code. It would be clearer and more efficient as:\n>>\n>> diff --git a/object.c b/object.c\n>> index 2c32691dc4..2dfa038f13 100644\n>> --- a/object.c\n>> +++ b/object.c\n>> @@ -262,12 +262,14 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n>>  \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n>>  \t    (!obj && repo_has_object_file(r, oid) &&\n>>  \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n>> +\t\tif (!obj)\n>> +\t\t\tobj = create_object(r, oid, alloc_blob_node(r));\n>>  \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n>>  \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n>>  \t\t\treturn NULL;\n>>  \t\t}\n>> -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n>> -\t\treturn lookup_object(r, oid);\n>> +\t\tparse_blob_buffer(obj, NULL, 0);\n>> +\t\treturn obj;\n>>  \t}\n>>  \n>>  \tbuffer = repo_read_object_file(r, oid, &type, &size);\n>>\n>> but I doubt the efficiency matters much in practice. Those hash lookups\n>> will be lost in the noise of computing the hash of the blob contents.\n>\n> I was trying to keep the changes smaller, but what about just doing this?:\n\nSent a bit too soon...:\n\n> diff --git a/blob.c b/blob.c\n> index 182718aba9..69293e7d8e 100644\n> --- a/blob.c\n> +++ b/blob.c\n> @@ -5,16 +5,16 @@\n>  \n>  const char *blob_type = \"blob\";\n>  \n> +struct blob *create_blob(struct repository *r, const struct object_id *oid)\n> +{\n> +\treturn create_object(r, oid, alloc_blob_node(r));\n> +}\n> +\n>  struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n>  {\n>  \tstruct object *obj = lookup_object(r, oid);\n>  \tif (!obj)\n> -\t\treturn create_object(r, oid, alloc_blob_node(r));\n> -\treturn object_as_type(obj, OBJ_BLOB, 0);\n> -}\n> +\t\treturn create_blob(r, oid);\n>  \n> -int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n> -{\n> -\titem->object.parsed = 1;\n> -\treturn 0;\n> +\treturn object_as_type(obj, OBJ_BLOB, 0);\n>  }\n> diff --git a/blob.h b/blob.h\n> index 1664872055..ad34f0e9cc 100644\n> --- a/blob.h\n> +++ b/blob.h\n> @@ -9,10 +9,9 @@ struct blob {\n>  \tstruct object object;\n>  };\n>  \n> +struct blob *create_blob(struct repository *r, const struct object_id *oid);\n>  struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n>  \n> -int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n> -\n>  /**\n>   * Blobs do not contain references to other objects and do not have\n>   * structured data that needs parsing. However, code may use the\n> diff --git a/object.c b/object.c\n> index 78343781ae..2699431404 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -195,8 +195,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n>  \tif (type == OBJ_BLOB) {\n>  \t\tstruct blob *blob = lookup_blob(r, oid);\n>  \t\tif (blob) {\n> -\t\t\tif (parse_blob_buffer(blob, buffer, size))\n> -\t\t\t\treturn NULL;\n> +\t\t\tblob->object.parsed = 1;\n>  \t\t\tobj = &blob->object;\n>  \t\t}\n>  \t} else if (type == OBJ_TREE) {\n> @@ -262,12 +261,16 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n>  \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n>  \t    (!obj && repo_has_object_file(r, oid) &&\n>  \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n> +\t\tstruct blob *blob;\n> +\t\tif (!obj)\n> +\t\t\tblob = create_blob(r, oid);\n>\n>  \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n>  \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n>  \t\t\treturn NULL;\n>  \t\t}\n> -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n> -\t\treturn lookup_object(r, oid);\n> +\t\tobj = &blob->object;\n> +\t\tobj->parsed = 1;\n> +\t\treturn obj;\n>  \t}\n>  \n>  \tbuffer = repo_read_object_file(r, oid, &type, &size);\n\nWell, aside from this segfault think-o introduced while\nexperimenting. Needs to be:\n\n@@ -262,12 +261,16 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n \t    (!obj && repo_has_object_file(r, oid) &&\n \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n+\t\tif (!obj) {\n+\t\t\tstruct blob *blob = create_blob(r, oid);\n+\t\t\tobj = &blob->object;\n+\t\t}\n \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n \t\t\treturn NULL;\n \t\t}\n-\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n-\t\treturn lookup_object(r, oid);\n+\t\tobj->parsed = 1;\n+\t\treturn obj;\n \t}\n \n \tbuffer = repo_read_object_file(r, oid, &type, &size);\n\n\n\n"},{"id":"421852","messageId":"YHVVlCg2EAb4ZddJ@coredump.intra.peff.net","threadId":"1003","inReplyTo":"87y2dqfgbb.fsf@evledraar.gmail.com","subject":"Re: [PATCH 1/2] blob.c: remove buffer & size arguments to parse_blob_buffer()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2021-04-13T08:25:56Z","receivedAt":"2021-04-13T08:25:59Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Sat, Apr 10, 2021 at 02:57:12PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> > Not new in your patch, but I wondered if this could cause a segfault\n> > when lookup_blob() returns NULL. I _think_ the answer is \"no\". We'd hit\n> > this code path when either:\n> [...]\n> I was trying to keep the changes smaller, but what about just doing this?:\n> [...]\n\nYeah, that seems pretty reasonable to me. It cleans up the extra lookups\nin parse_object() and gets rid of the funny-named \"parse_blob_buffer()\"\nthat takes no buffer.\n\n-Peff\n"},{"id":"422406","messageId":"patch-01.10-5818eca45d-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 01/10] cat-file tests: test for bogus type name handling","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:34Z","receivedAt":"2021-04-20T12:50:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a test of how \"cat-file\" behaves when given a bogus type in its\n\"git cat-file <TYPE> <OBJECT>\" mode. There were existing tests (just\nbelow this one) for \"-t bogus\" or \"--allow-unknown-type\" modes, but\nnone for the switch-less mode.\n\nThis test is similar to the one that exists for \"git hash-object\"\nalready, see b7994af0f92 (type_from_string_gently: make sure length\nmatches, 2015-04-17).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1006-cat-file.sh | 16 ++++++++++++++++\n 1 file changed, 16 insertions(+)\n\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex 5d2dc99b74..908797dcae 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -315,6 +315,22 @@ test_expect_success '%(deltabase) reports packed delta bases' '\n \t}\n '\n \n+test_expect_success 'cat-file complains about bogus type name' '\n+\ttest_must_fail git cat-file co HEAD >out 2>err &&\n+\ttest_must_be_empty out &&\n+\tcat >expected <<-\\EOF &&\n+\tfatal: invalid object type \"co\"\n+\tEOF\n+\ttest_cmp expected err &&\n+\n+\ttest_must_fail git cat-file bogus HEAD >out 2>err &&\n+\ttest_must_be_empty out &&\n+\tcat >expected <<-\\EOF &&\n+\tfatal: invalid object type \"bogus\"\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n bogus_type=\"bogus\"\n bogus_content=\"bogus\"\n bogus_size=$(strlen \"$bogus_content\")\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422407","messageId":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.3-0000000000-20210409T080534Z-avarab@gmail.com","subject":"[PATCH v2 00/10] object.c et al: tests, small bug fixes etc.","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:33Z","receivedAt":"2021-04-20T12:50:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This is a re-roll of my v1 \"blob/object.c: trivial readability\nimprovements\"[1] which has grown from 2 patches to 10. As suggested by\nJeff King in v1 we can entirely get rid of parse_blob_buffer(), so we\nnow do that.\n\nThe other reason this has grown is to resolve a semantic conflict that\ncame up with type_from_string() and type_from_string_gently() early,\nbetween this and the series I'm about to re-roll on top of it we'll\nalso remove the \"emit an error\" argument to type_from_string_gently().\n\nThis involves going through some existing callers ande improving their\nerror messages, and fixing some subtle existing bugs.\n\n1. https://lore.kernel.org/git/cover-0.3-0000000000-20210409T080534Z-avarab@gmail.com\n\nÆvar Arnfjörð Bjarmason (10):\n  cat-file tests: test for bogus type name handling\n  hash-object tests: more detailed test for invalid type\n  mktree tests: add test for invalid object type\n  object-file.c: take type id, not string, in\n    read_object_with_reference()\n  {commit,tree,blob,tag}.c: add a create_{commit,tree,blob,tag}()\n  blob.c: remove parse_blob_buffer()\n  object.c: simplify return semantic of parse_object_buffer()\n  object.c: don't go past \"len\" under die() in type_from_string_gently()\n  mktree: stop setting *ntr++ to NIL\n  mktree: emit a more detailed error when the <type> is invalid\n\n blob.c                      | 13 ++++++-------\n blob.h                      | 12 +-----------\n builtin/cat-file.c          |  7 ++++---\n builtin/fast-import.c       |  6 +++---\n builtin/grep.c              |  4 ++--\n builtin/mktree.c            | 23 ++++++++++++++++-------\n builtin/pack-objects.c      |  2 +-\n cache.h                     |  2 +-\n commit-graph.c              |  2 +-\n commit.c                    |  7 ++++++-\n commit.h                    |  1 +\n object-file.c               |  7 +++----\n object.c                    | 26 +++++++++++++-------------\n t/helper/test-fast-rebase.c |  4 ++--\n t/t1006-cat-file.sh         | 16 ++++++++++++++++\n t/t1007-hash-object.sh      | 12 ++++++++++--\n t/t1010-mktree.sh           | 10 ++++++++++\n tag.c                       |  7 ++++++-\n tree-walk.c                 |  6 +++---\n tree.c                      |  7 ++++++-\n 20 files changed, 111 insertions(+), 63 deletions(-)\n\nRange-diff against v1:\n -:  ---------- >  1:  5818eca45d cat-file tests: test for bogus type name handling\n -:  ---------- >  2:  0b48389325 hash-object tests: more detailed test for invalid type\n -:  ---------- >  3:  cd585017a9 mktree tests: add test for invalid object type\n -:  ---------- >  4:  48aca62864 object-file.c: take type id, not string, in read_object_with_reference()\n -:  ---------- >  5:  5213d500b9 {commit,tree,blob,tag}.c: add a create_{commit,tree,blob,tag}()\n 1:  68a7709fe5 !  6:  02c8d2a9ba blob.c: remove buffer & size arguments to parse_blob_buffer()\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    blob.c: remove buffer & size arguments to parse_blob_buffer()\n    +    blob.c: remove parse_blob_buffer()\n     \n         As noted in the comment introduced in 837d395a5c0 (Replace\n         parse_blob() with an explanatory comment, 2010-01-18) the old\n    -    parse_blob() function and the current parse_blob_buffer() exist merely\n    -    to provide consistency in the API.\n    +    parse_blob() function and the parse_blob_buffer() existed to provide\n    +    consistency in the API.\n    +\n    +    See bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\n    +    parse_object(), 2005-05-06) for the introduction of\n    +    parse_blob_buffer().\n     \n         We're not going to parse blobs like we \"parse\" commits, trees or\n    -    tags. So let's not have the parse_blob_buffer() take arguments that\n    -    pretends that we do. Its only use is to set the \"parsed\" flag.\n    +    tags. So we should not have the parse_blob_buffer() take arguments\n    +    that pretends that we do. Its only use is to set the \"parsed\" flag.\n     \n    -    See bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\n    -    parse_object(), 2005-05-06) for the introduction of parse_blob_buffer().\n    +    So let's entirely remove the function, and use our newly created\n    +    create_blob() for the allocation. We can then set the \"parsed\" flag\n    +    directly in parse_object_buffer() and parse_object() instead.\n     \n    -    I'm moving the prototype of parse_blob_buffer() below the comment\n    -    added in 837d395a5c0 while I'm at it. That comment was originally\n    -    meant to be a replacement for the missing parse_blob() function, but\n    -    it's much less confusing to have it be above the parse_blob_buffer()\n    -    function it refers to.\n    +    At this point I could move the comment added in 837d395a5c0 to one or\n    +    both of those object.c function, but let's just delete it instead. I\n    +    think it's obvious from the flow of the code what's going on\n    +    here. Setting the parsed flag no longer happens at a distance, so why\n    +    we're doing it isn't unclear anymore.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## blob.c ##\n    +@@\n    + \n    + const char *blob_type = \"blob\";\n    + \n    +-static struct blob *create_blob(struct repository *r, const struct object_id *oid)\n    ++struct blob *create_blob(struct repository *r, const struct object_id *oid)\n    + {\n    + \treturn create_object(r, oid, alloc_blob_node(r));\n    + }\n     @@ blob.c: struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n    + \t\treturn create_blob(r, oid);\n      \treturn object_as_type(obj, OBJ_BLOB, 0);\n      }\n    - \n    +-\n     -int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n    -+int parse_blob_buffer(struct blob *item)\n    - {\n    - \titem->object.parsed = 1;\n    - \treturn 0;\n    +-{\n    +-\titem->object.parsed = 1;\n    +-\treturn 0;\n    +-}\n     \n      ## blob.h ##\n     @@ blob.h: struct blob {\n    + \tstruct object object;\n    + };\n      \n    ++struct blob *create_blob(struct repository *r, const struct object_id *oid);\n      struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n      \n     -int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n     -\n    - /**\n    -  * Blobs do not contain references to other objects and do not have\n    -  * structured data that needs parsing. However, code may use the\n    -@@ blob.h: int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n    -  * parse_blob_buffer() is used (by object.c) to flag that the object\n    -  * has been read successfully from the database.\n    -  **/\n    -+int parse_blob_buffer(struct blob *item);\n    - \n    +-/**\n    +- * Blobs do not contain references to other objects and do not have\n    +- * structured data that needs parsing. However, code may use the\n    +- * \"parsed\" bit in the struct object for a blob to determine whether\n    +- * its content has been found to actually be available, so\n    +- * parse_blob_buffer() is used (by object.c) to flag that the object\n    +- * has been read successfully from the database.\n    +- **/\n    +-\n      #endif /* BLOB_H */\n     \n      ## object.c ##\n    @@ object.c: struct object *parse_object_buffer(struct repository *r, const struct\n      \t\tstruct blob *blob = lookup_blob(r, oid);\n      \t\tif (blob) {\n     -\t\t\tif (parse_blob_buffer(blob, buffer, size))\n    -+\t\t\tif (parse_blob_buffer(blob))\n    - \t\t\t\treturn NULL;\n    +-\t\t\t\treturn NULL;\n    ++\t\t\tblob->object.parsed = 1;\n      \t\t\tobj = &blob->object;\n      \t\t}\n    + \t} else if (type == OBJ_TREE) {\n     @@ object.c: struct object *parse_object(struct repository *r, const struct object_id *oid)\n    + \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n    + \t    (!obj && repo_has_object_file(r, oid) &&\n    + \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n    ++\t\tif (!obj) {\n    ++\t\t\tstruct blob *blob = create_blob(r, oid);\n    ++\t\t\tobj = &blob->object;\n    ++\t\t}\n    + \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n      \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n      \t\t\treturn NULL;\n      \t\t}\n     -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n    -+\t\tparse_blob_buffer(lookup_blob(r, oid));\n    - \t\treturn lookup_object(r, oid);\n    +-\t\treturn lookup_object(r, oid);\n    ++\t\tobj->parsed = 1;\n    ++\t\treturn obj;\n      \t}\n      \n    + \tbuffer = repo_read_object_file(r, oid, &type, &size);\n 2:  f1fcc31717 !  7:  ee0b572f7d object.c: initialize automatic variable in lookup_object()\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    object.c: initialize automatic variable in lookup_object()\n    +    object.c: simplify return semantic of parse_object_buffer()\n     \n    -    Initialize a \"struct object obj*\" variable to NULL explicitly and\n    -    return it instead of leaving it uninitialized until the \"while\"\n    -    loop.\n    +    Remove the local \"obj\" variable from parse_object_buffer() and return\n    +    the object directly instead.\n     \n    -    There was no bug here, it's just less confusing when debugging if the\n    -    \"obj\" is either NULL or a valid object, not some random invalid\n    -    pointer.\n    +    The reason this variable was introduced was to free() a variable\n    +    before returning in bd2c39f58f9 ([PATCH] don't load and decompress\n    +    objects twice with parse_object() 2005-05-06). But that was when\n    +    parse_object_buffer() didn't exist, there was only the parse_object()\n    +    function.\n     \n    -    See 0556a11a0df (git object hash cleanups, 2006-06-30) for the initial\n    -    implementation.\n    +    Since the split-up of the two in 9f613ddd21c (Add git-for-each-ref:\n    +    helper for language bindings, 2006-09-15) we have not needed this\n    +    variable, and as demonstrated here not having to set it to (re)set it\n    +    to NULL simplifies the function.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## object.c ##\n    -@@ object.c: static void insert_obj_hash(struct object *obj, struct object **hash, unsigned i\n    - struct object *lookup_object(struct repository *r, const struct object_id *oid)\n    +@@ object.c: struct object *lookup_unknown_object(const struct object_id *oid)\n    + \n    + struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)\n      {\n    - \tunsigned int i, first;\n     -\tstruct object *obj;\n    -+\tstruct object *obj = NULL;\n    + \t*eaten_p = 0;\n      \n    - \tif (!r->parsed_objects->obj_hash)\n    --\t\treturn NULL;\n    -+\t\treturn obj;\n    +-\tobj = NULL;\n    + \tif (type == OBJ_BLOB) {\n    + \t\tstruct blob *blob = lookup_blob(r, oid);\n    + \t\tif (blob) {\n    + \t\t\tblob->object.parsed = 1;\n    +-\t\t\tobj = &blob->object;\n    ++\t\t\treturn &blob->object;\n    + \t\t}\n    + \t} else if (type == OBJ_TREE) {\n    + \t\tstruct tree *tree = lookup_tree(r, oid);\n    + \t\tif (tree) {\n    +-\t\t\tobj = &tree->object;\n    + \t\t\tif (!tree->buffer)\n    + \t\t\t\ttree->object.parsed = 0;\n    + \t\t\tif (!tree->object.parsed) {\n    +@@ object.c: struct object *parse_object_buffer(struct repository *r, const struct object_id\n    + \t\t\t\t\treturn NULL;\n    + \t\t\t\t*eaten_p = 1;\n    + \t\t\t}\n    ++\t\t\treturn &tree->object;\n    + \t\t}\n    + \t} else if (type == OBJ_COMMIT) {\n    + \t\tstruct commit *commit = lookup_commit(r, oid);\n    +@@ object.c: struct object *parse_object_buffer(struct repository *r, const struct object_id\n    + \t\t\t\tset_commit_buffer(r, commit, buffer, size);\n    + \t\t\t\t*eaten_p = 1;\n    + \t\t\t}\n    +-\t\t\tobj = &commit->object;\n    ++\t\t\treturn &commit->object;\n    + \t\t}\n    + \t} else if (type == OBJ_TAG) {\n    + \t\tstruct tag *tag = lookup_tag(r, oid);\n    + \t\tif (tag) {\n    + \t\t\tif (parse_tag_buffer(r, tag, buffer, size))\n    + \t\t\t       return NULL;\n    +-\t\t\tobj = &tag->object;\n    ++\t\t\treturn &tag->object;\n    + \t\t}\n    + \t} else {\n    + \t\twarning(_(\"object %s has unknown type id %d\"), oid_to_hex(oid), type);\n    +-\t\tobj = NULL;\n    + \t}\n    +-\treturn obj;\n    ++\treturn NULL;\n    + }\n      \n    - \tfirst = i = hash_obj(oid, r->parsed_objects->obj_hash_size);\n    - \twhile ((obj = r->parsed_objects->obj_hash[i]) != NULL) {\n    + struct object *parse_object_or_die(const struct object_id *oid,\n -:  ---------- >  8:  f652d0fb5c object.c: don't go past \"len\" under die() in type_from_string_gently()\n -:  ---------- >  9:  e463fe5f6a mktree: stop setting *ntr++ to NIL\n -:  ---------- > 10:  fe75526a65 mktree: emit a more detailed error when the <type> is invalid\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422408","messageId":"patch-03.10-cd585017a9-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 03/10] mktree tests: add test for invalid object type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:36Z","receivedAt":"2021-04-20T12:50:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a missing test for an invalid object type to the mktree tests,\nmaking it consistent with the same tests in cat-file.c. This tests the\ninteraction of mktree_line() and type_from_string().\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1010-mktree.sh | 10 ++++++++++\n 1 file changed, 10 insertions(+)\n\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex b946f87686..2a7b04aed8 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -58,6 +58,16 @@ test_expect_success 'allow missing object with --missing' '\n \ttest_cmp tree.missing actual\n '\n \n+test_expect_success 'invalid object type' '\n+\tsed \"s/tree/whee/g\" <top >bad-type &&\n+\ttest_must_fail git mktree <bad-type >out 2>err &&\n+\ttest_must_be_empty out &&\n+\tcat >expected <<-\\EOF &&\n+\tfatal: invalid object type \"whee\"\n+\tEOF\n+\ttest_cmp expected err\n+'\n+\n test_expect_success 'mktree refuses to read ls-tree -r output (1)' '\n \ttest_must_fail git mktree <all >actual\n '\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422409","messageId":"patch-04.10-48aca62864-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 04/10] object-file.c: take type id, not string, in read_object_with_reference()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:37Z","receivedAt":"2021-04-20T12:50:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Make the read_object_with_reference() function take \"enum object_type\"\ninstead of a \"const char *\" with a type name that it converted via\ntype_from_string().\n\nOut of the nine callers of this function, only one wanted to pass a\n\"const char *\". The others were simply passing along the\n{commit,tree}_type string constants.\n\nThat one caller in builtin/cat-file.c did not expect to pass a \"raw\"\ntype (i.e. in invalid \"--literally\" type, but one gotten from\ntype_from_string(). Furthermore the read_object_with_reference()\nfunction itself was calling type_from_string(), so this whole thing\namounted to unnecessarily going back and forth.\n\nThis API design dates back to f4913f91a96 ([PATCH] Accept commit in\nsome places when tree is needed., 2005-04-20). At that time there\nwasn't an API like type_from_string(). That only arrived in\ndf8436622fb (formalize typename(), and add its reverse\ntype_from_string(), 2007-02-26).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/cat-file.c     | 7 ++++---\n builtin/fast-import.c  | 6 +++---\n builtin/grep.c         | 4 ++--\n builtin/pack-objects.c | 2 +-\n cache.h                | 2 +-\n object-file.c          | 7 +++----\n tree-walk.c            | 6 +++---\n 7 files changed, 17 insertions(+), 17 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 5ebf13359e..46fc7a32ba 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -66,7 +66,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t\tint unknown_type)\n {\n \tstruct object_id oid;\n-\tenum object_type type;\n+\tenum object_type type, exp_type_id;\n \tchar *buf;\n \tunsigned long size;\n \tstruct object_context obj_context;\n@@ -154,7 +154,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tbreak;\n \n \tcase 0:\n-\t\tif (type_from_string(exp_type) == OBJ_BLOB) {\n+\t\texp_type_id = type_from_string(exp_type);\n+\t\tif (exp_type_id == OBJ_BLOB) {\n \t\t\tstruct object_id blob_oid;\n \t\t\tif (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {\n \t\t\t\tchar *buffer = read_object_file(&oid, &type,\n@@ -177,7 +178,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\t\t */\n \t\t}\n \t\tbuf = read_object_with_reference(the_repository,\n-\t\t\t\t\t\t &oid, exp_type, &size, NULL);\n+\t\t\t\t\t\t &oid, exp_type_id, &size, NULL);\n \t\tbreak;\n \n \tdefault:\ndiff --git a/builtin/fast-import.c b/builtin/fast-import.c\nindex 3afa81cf9a..ee52be02f8 100644\n--- a/builtin/fast-import.c\n+++ b/builtin/fast-import.c\n@@ -2481,7 +2481,7 @@ static void note_change_n(const char *p, struct branch *b, unsigned char *old_fa\n \t\tunsigned long size;\n \t\tchar *buf = read_object_with_reference(the_repository,\n \t\t\t\t\t\t       &commit_oid,\n-\t\t\t\t\t\t       commit_type, &size,\n+\t\t\t\t\t\t       OBJ_COMMIT, &size,\n \t\t\t\t\t\t       &commit_oid);\n \t\tif (!buf || size < the_hash_algo->hexsz + 6)\n \t\t\tdie(\"Not a valid commit: %s\", p);\n@@ -2553,7 +2553,7 @@ static void parse_from_existing(struct branch *b)\n \t\tchar *buf;\n \n \t\tbuf = read_object_with_reference(the_repository,\n-\t\t\t\t\t\t &b->oid, commit_type, &size,\n+\t\t\t\t\t\t &b->oid, OBJ_COMMIT, &size,\n \t\t\t\t\t\t &b->oid);\n \t\tparse_from_commit(b, buf, size);\n \t\tfree(buf);\n@@ -2649,7 +2649,7 @@ static struct hash_list *parse_merge(unsigned int *count)\n \t\t\tunsigned long size;\n \t\t\tchar *buf = read_object_with_reference(the_repository,\n \t\t\t\t\t\t\t       &n->oid,\n-\t\t\t\t\t\t\t       commit_type,\n+\t\t\t\t\t\t\t       OBJ_COMMIT,\n \t\t\t\t\t\t\t       &size, &n->oid);\n \t\t\tif (!buf || size < the_hash_algo->hexsz + 6)\n \t\t\t\tdie(\"Not a valid commit: %s\", from);\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5de725f904..f2a73c92fa 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -467,7 +467,7 @@ static int grep_submodule(struct grep_opt *opt,\n \t\tobject = parse_object_or_die(oid, NULL);\n \t\tobj_read_unlock();\n \t\tdata = read_object_with_reference(&subrepo,\n-\t\t\t\t\t\t  &object->oid, tree_type,\n+\t\t\t\t\t\t  &object->oid, OBJ_TREE,\n \t\t\t\t\t\t  &size, NULL);\n \t\tif (!data)\n \t\t\tdie(_(\"unable to read tree (%s)\"), oid_to_hex(&object->oid));\n@@ -635,7 +635,7 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\tint hit, len;\n \n \t\tdata = read_object_with_reference(opt->repo,\n-\t\t\t\t\t\t  &obj->oid, tree_type,\n+\t\t\t\t\t\t  &obj->oid, OBJ_TREE,\n \t\t\t\t\t\t  &size, NULL);\n \t\tif (!data)\n \t\t\tdie(_(\"unable to read tree (%s)\"), oid_to_hex(&obj->oid));\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex a1e33d7507..feb0320371 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -1649,7 +1649,7 @@ static void add_preferred_base(struct object_id *oid)\n \t\treturn;\n \n \tdata = read_object_with_reference(the_repository, oid,\n-\t\t\t\t\t  tree_type, &size, &tree_oid);\n+\t\t\t\t\t  OBJ_TREE, &size, &tree_oid);\n \tif (!data)\n \t\treturn;\n \ndiff --git a/cache.h b/cache.h\nindex 148d9ab5f1..dad9792c74 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1508,7 +1508,7 @@ int cache_name_stage_compare(const char *name1, int len1, int stage1, const char\n \n void *read_object_with_reference(struct repository *r,\n \t\t\t\t const struct object_id *oid,\n-\t\t\t\t const char *required_type,\n+\t\t\t\t enum object_type object_type,\n \t\t\t\t unsigned long *size,\n \t\t\t\t struct object_id *oid_ret);\n \ndiff --git a/object-file.c b/object-file.c\nindex 624af408cd..d2f223dcef 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1669,25 +1669,24 @@ void *read_object_file_extended(struct repository *r,\n \n void *read_object_with_reference(struct repository *r,\n \t\t\t\t const struct object_id *oid,\n-\t\t\t\t const char *required_type_name,\n+\t\t\t\t enum object_type object_type,\n \t\t\t\t unsigned long *size,\n \t\t\t\t struct object_id *actual_oid_return)\n {\n-\tenum object_type type, required_type;\n \tvoid *buffer;\n \tunsigned long isize;\n \tstruct object_id actual_oid;\n \n-\trequired_type = type_from_string(required_type_name);\n \toidcpy(&actual_oid, oid);\n \twhile (1) {\n \t\tint ref_length = -1;\n \t\tconst char *ref_type = NULL;\n+\t\tenum object_type type;\n \n \t\tbuffer = repo_read_object_file(r, &actual_oid, &type, &isize);\n \t\tif (!buffer)\n \t\t\treturn NULL;\n-\t\tif (type == required_type) {\n+\t\tif (type == object_type) {\n \t\t\t*size = isize;\n \t\t\tif (actual_oid_return)\n \t\t\t\toidcpy(actual_oid_return, &actual_oid);\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 2d6226d5f1..e5db9291e1 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -89,7 +89,7 @@ void *fill_tree_descriptor(struct repository *r,\n \tvoid *buf = NULL;\n \n \tif (oid) {\n-\t\tbuf = read_object_with_reference(r, oid, tree_type, &size, NULL);\n+\t\tbuf = read_object_with_reference(r, oid, OBJ_TREE, &size, NULL);\n \t\tif (!buf)\n \t\t\tdie(\"unable to read tree %s\", oid_to_hex(oid));\n \t}\n@@ -605,7 +605,7 @@ int get_tree_entry(struct repository *r,\n \tunsigned long size;\n \tstruct object_id root;\n \n-\ttree = read_object_with_reference(r, tree_oid, tree_type, &size, &root);\n+\ttree = read_object_with_reference(r, tree_oid, OBJ_TREE, &size, &root);\n \tif (!tree)\n \t\treturn -1;\n \n@@ -677,7 +677,7 @@ enum get_oid_result get_tree_entry_follow_symlinks(struct repository *r,\n \t\t\tunsigned long size;\n \t\t\ttree = read_object_with_reference(r,\n \t\t\t\t\t\t\t  &current_tree_oid,\n-\t\t\t\t\t\t\t  tree_type, &size,\n+\t\t\t\t\t\t\t  OBJ_TREE, &size,\n \t\t\t\t\t\t\t  &root);\n \t\t\tif (!tree)\n \t\t\t\tgoto done;\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422410","messageId":"patch-05.10-5213d500b9-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 05/10] {commit,tree,blob,tag}.c: add a create_{commit,tree,blob,tag}()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:38Z","receivedAt":"2021-04-20T12:50:57Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a create_*() function for our built-in types as a handy but\ntrivial wrapper around their calls to create_object().\n\nThis allows for slightly simplifying code added in\n96af91d410c (commit-graph: verify objects exist, 2018-06-27). The\nremaining three functions are added for consistency for now.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n blob.c                      | 7 ++++++-\n commit-graph.c              | 2 +-\n commit.c                    | 7 ++++++-\n commit.h                    | 1 +\n t/helper/test-fast-rebase.c | 4 ++--\n tag.c                       | 7 ++++++-\n tree.c                      | 7 ++++++-\n 7 files changed, 28 insertions(+), 7 deletions(-)\n\ndiff --git a/blob.c b/blob.c\nindex 182718aba9..d98b6badc7 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -5,11 +5,16 @@\n \n const char *blob_type = \"blob\";\n \n+static struct blob *create_blob(struct repository *r, const struct object_id *oid)\n+{\n+\treturn create_object(r, oid, alloc_blob_node(r));\n+}\n+\n struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n-\t\treturn create_object(r, oid, alloc_blob_node(r));\n+\t\treturn create_blob(r, oid);\n \treturn object_as_type(obj, OBJ_BLOB, 0);\n }\n \ndiff --git a/commit-graph.c b/commit-graph.c\nindex f18380b922..c456f84f41 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -2504,7 +2504,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\thashcpy(cur_oid.hash, g->chunk_oid_lookup + g->hash_len * i);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n-\t\todb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));\n+\t\todb_commit = create_commit(r, &cur_oid);\n \t\tif (parse_commit_internal(odb_commit, 0, 0)) {\n \t\t\tgraph_report(_(\"failed to parse commit %s from object database for commit-graph\"),\n \t\t\t\t     oid_to_hex(&cur_oid));\ndiff --git a/commit.c b/commit.c\nindex 8ea55a447f..3580c62b92 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -57,11 +57,16 @@ struct commit *lookup_commit_or_die(const struct object_id *oid, const char *ref\n \treturn c;\n }\n \n+struct commit *create_commit(struct repository *r, const struct object_id *oid)\n+{\n+\treturn create_object(r, oid, alloc_commit_node(r));\n+}\n+\n struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n-\t\treturn create_object(r, oid, alloc_commit_node(r));\n+\t\treturn create_commit(r, oid);\n \treturn object_as_type(obj, OBJ_COMMIT, 0);\n }\n \ndiff --git a/commit.h b/commit.h\nindex df42eb434f..09e2167f8c 100644\n--- a/commit.h\n+++ b/commit.h\n@@ -63,6 +63,7 @@ enum decoration_type {\n void add_name_decoration(enum decoration_type type, const char *name, struct object *obj);\n const struct name_decoration *get_name_decoration(const struct object *obj);\n \n+struct commit *create_commit(struct repository *r, const struct object_id *oid);\n struct commit *lookup_commit(struct repository *r, const struct object_id *oid);\n struct commit *lookup_commit_reference(struct repository *r,\n \t\t\t\t       const struct object_id *oid);\ndiff --git a/t/helper/test-fast-rebase.c b/t/helper/test-fast-rebase.c\nindex 373212256a..e3d3e991a5 100644\n--- a/t/helper/test-fast-rebase.c\n+++ b/t/helper/test-fast-rebase.c\n@@ -51,7 +51,7 @@ static char *get_author(const char *message)\n \treturn NULL;\n }\n \n-static struct commit *create_commit(struct tree *tree,\n+static struct commit *make_a_commit(struct tree *tree,\n \t\t\t\t    struct commit *based_on,\n \t\t\t\t    struct commit *parent)\n {\n@@ -177,7 +177,7 @@ int cmd__fast_rebase(int argc, const char **argv)\n \t\tif (!result.clean)\n \t\t\tdie(\"Aborting: Hit a conflict and restarting is not implemented.\");\n \t\tlast_picked_commit = commit;\n-\t\tlast_commit = create_commit(result.tree, commit, last_commit);\n+\t\tlast_commit = make_a_commit(result.tree, commit, last_commit);\n \t}\n \tfprintf(stderr, \"\\nDone.\\n\");\n \t/* TODO: There should be some kind of rev_info_free(&revs) call... */\ndiff --git a/tag.c b/tag.c\nindex 3e18a41841..ed7037256e 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -99,11 +99,16 @@ struct object *deref_tag_noverify(struct object *o)\n \treturn o;\n }\n \n+static struct tag *create_tag(struct repository *r, const struct object_id *oid)\n+{\n+\treturn create_object(r, oid, alloc_tag_node(r));\n+}\n+\n struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n-\t\treturn create_object(r, oid, alloc_tag_node(r));\n+\t\treturn create_tag(r, oid);\n \treturn object_as_type(obj, OBJ_TAG, 0);\n }\n \ndiff --git a/tree.c b/tree.c\nindex 410e3b477e..00958c581e 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -102,11 +102,16 @@ int cmp_cache_name_compare(const void *a_, const void *b_)\n \t\t\t\t  ce2->name, ce2->ce_namelen, ce_stage(ce2));\n }\n \n+static struct tree *create_tree(struct repository *r, const struct object_id *oid)\n+{\n+\treturn create_object(r, oid, alloc_tree_node(r));\n+}\n+\n struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n {\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n-\t\treturn create_object(r, oid, alloc_tree_node(r));\n+\t\treturn create_tree(r, oid);\n \treturn object_as_type(obj, OBJ_TREE, 0);\n }\n \n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422411","messageId":"patch-02.10-0b48389325-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 02/10] hash-object tests: more detailed test for invalid type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:35Z","receivedAt":"2021-04-20T12:50:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the tests added in b7994af0f92 (type_from_string_gently: make\nsure length matches, 2015-04-17) to check the return code and error\nthat's emitted.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t1007-hash-object.sh | 12 ++++++++++--\n 1 file changed, 10 insertions(+), 2 deletions(-)\n\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex 64b340f227..74486f6f1a 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -230,11 +230,19 @@ test_expect_success 'corrupt tag' '\n '\n \n test_expect_success 'hash-object complains about bogus type name' '\n-\ttest_must_fail git hash-object -t bogus --stdin </dev/null\n+\ttest_must_fail git hash-object -t bogus --stdin 2>actual </dev/null &&\n+\tcat >expect <<-\\EOF &&\n+\tfatal: invalid object type \"bogus\"\n+\tEOF\n+\ttest_cmp expect actual\n '\n \n test_expect_success 'hash-object complains about truncated type name' '\n-\ttest_must_fail git hash-object -t bl --stdin </dev/null\n+\ttest_must_fail git hash-object -t bl --stdin 2>actual </dev/null &&\n+\tcat >expect <<-\\EOF &&\n+\tfatal: invalid object type \"bl\"\n+\tEOF\n+\ttest_cmp expect actual\n '\n \n test_expect_success '--literally' '\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422412","messageId":"patch-06.10-02c8d2a9ba-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 06/10] blob.c: remove parse_blob_buffer()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:39Z","receivedAt":"2021-04-20T12:50:59Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"As noted in the comment introduced in 837d395a5c0 (Replace\nparse_blob() with an explanatory comment, 2010-01-18) the old\nparse_blob() function and the parse_blob_buffer() existed to provide\nconsistency in the API.\n\nSee bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\nparse_object(), 2005-05-06) for the introduction of\nparse_blob_buffer().\n\nWe're not going to parse blobs like we \"parse\" commits, trees or\ntags. So we should not have the parse_blob_buffer() take arguments\nthat pretends that we do. Its only use is to set the \"parsed\" flag.\n\nSo let's entirely remove the function, and use our newly created\ncreate_blob() for the allocation. We can then set the \"parsed\" flag\ndirectly in parse_object_buffer() and parse_object() instead.\n\nAt this point I could move the comment added in 837d395a5c0 to one or\nboth of those object.c function, but let's just delete it instead. I\nthink it's obvious from the flow of the code what's going on\nhere. Setting the parsed flag no longer happens at a distance, so why\nwe're doing it isn't unclear anymore.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n blob.c   |  8 +-------\n blob.h   | 12 +-----------\n object.c | 11 +++++++----\n 3 files changed, 9 insertions(+), 22 deletions(-)\n\ndiff --git a/blob.c b/blob.c\nindex d98b6badc7..1308299eab 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -5,7 +5,7 @@\n \n const char *blob_type = \"blob\";\n \n-static struct blob *create_blob(struct repository *r, const struct object_id *oid)\n+struct blob *create_blob(struct repository *r, const struct object_id *oid)\n {\n \treturn create_object(r, oid, alloc_blob_node(r));\n }\n@@ -17,9 +17,3 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n \t\treturn create_blob(r, oid);\n \treturn object_as_type(obj, OBJ_BLOB, 0);\n }\n-\n-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n-{\n-\titem->object.parsed = 1;\n-\treturn 0;\n-}\ndiff --git a/blob.h b/blob.h\nindex 1664872055..6e6b23a769 100644\n--- a/blob.h\n+++ b/blob.h\n@@ -9,17 +9,7 @@ struct blob {\n \tstruct object object;\n };\n \n+struct blob *create_blob(struct repository *r, const struct object_id *oid);\n struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n \n-int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n-\n-/**\n- * Blobs do not contain references to other objects and do not have\n- * structured data that needs parsing. However, code may use the\n- * \"parsed\" bit in the struct object for a blob to determine whether\n- * its content has been found to actually be available, so\n- * parse_blob_buffer() is used (by object.c) to flag that the object\n- * has been read successfully from the database.\n- **/\n-\n #endif /* BLOB_H */\ndiff --git a/object.c b/object.c\nindex 78343781ae..f4e419e5c3 100644\n--- a/object.c\n+++ b/object.c\n@@ -195,8 +195,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \tif (type == OBJ_BLOB) {\n \t\tstruct blob *blob = lookup_blob(r, oid);\n \t\tif (blob) {\n-\t\t\tif (parse_blob_buffer(blob, buffer, size))\n-\t\t\t\treturn NULL;\n+\t\t\tblob->object.parsed = 1;\n \t\t\tobj = &blob->object;\n \t\t}\n \t} else if (type == OBJ_TREE) {\n@@ -262,12 +261,16 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n \t    (!obj && repo_has_object_file(r, oid) &&\n \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n+\t\tif (!obj) {\n+\t\t\tstruct blob *blob = create_blob(r, oid);\n+\t\t\tobj = &blob->object;\n+\t\t}\n \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n \t\t\treturn NULL;\n \t\t}\n-\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n-\t\treturn lookup_object(r, oid);\n+\t\tobj->parsed = 1;\n+\t\treturn obj;\n \t}\n \n \tbuffer = repo_read_object_file(r, oid, &type, &size);\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422413","messageId":"patch-08.10-f652d0fb5c-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 08/10] object.c: don't go past \"len\" under die() in type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:41Z","receivedAt":"2021-04-20T12:51:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Fix a bug that's been with us ever since type_from_string_gently() was\nsplit off from type_from_string() in fe8e3b71805 (Refactor\ntype_from_string() to allow continuing after detecting an error,\n2014-09-10).\n\nWhen the type was invalid and we were in the non-gently mode we'd die,\nand then proceed to run off past the \"len\" of the buffer we were\nprovided with.\n\nLuckily, I think that nothing ever used this function in that way. Any\nnon-gentle invocation came via type_from_string(), which was passing a\nbuffer with a NIL at the same place as the \"len\" would take us (we got\nit via strlen()).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/object.c b/object.c\nindex 70af833ca1..bad9e17f25 100644\n--- a/object.c\n+++ b/object.c\n@@ -50,7 +50,7 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n \tif (gentle)\n \t\treturn -1;\n \n-\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n+\tdie(_(\"invalid object type \\\"%.*s\\\"\"), (int)len, str);\n }\n \n /*\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422414","messageId":"patch-07.10-ee0b572f7d-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 07/10] object.c: simplify return semantic of parse_object_buffer()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:40Z","receivedAt":"2021-04-20T12:51:00Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the local \"obj\" variable from parse_object_buffer() and return\nthe object directly instead.\n\nThe reason this variable was introduced was to free() a variable\nbefore returning in bd2c39f58f9 ([PATCH] don't load and decompress\nobjects twice with parse_object() 2005-05-06). But that was when\nparse_object_buffer() didn't exist, there was only the parse_object()\nfunction.\n\nSince the split-up of the two in 9f613ddd21c (Add git-for-each-ref:\nhelper for language bindings, 2006-09-15) we have not needed this\nvariable, and as demonstrated here not having to set it to (re)set it\nto NULL simplifies the function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 13 +++++--------\n 1 file changed, 5 insertions(+), 8 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex f4e419e5c3..70af833ca1 100644\n--- a/object.c\n+++ b/object.c\n@@ -188,20 +188,17 @@ struct object *lookup_unknown_object(const struct object_id *oid)\n \n struct object *parse_object_buffer(struct repository *r, const struct object_id *oid, enum object_type type, unsigned long size, void *buffer, int *eaten_p)\n {\n-\tstruct object *obj;\n \t*eaten_p = 0;\n \n-\tobj = NULL;\n \tif (type == OBJ_BLOB) {\n \t\tstruct blob *blob = lookup_blob(r, oid);\n \t\tif (blob) {\n \t\t\tblob->object.parsed = 1;\n-\t\t\tobj = &blob->object;\n+\t\t\treturn &blob->object;\n \t\t}\n \t} else if (type == OBJ_TREE) {\n \t\tstruct tree *tree = lookup_tree(r, oid);\n \t\tif (tree) {\n-\t\t\tobj = &tree->object;\n \t\t\tif (!tree->buffer)\n \t\t\t\ttree->object.parsed = 0;\n \t\t\tif (!tree->object.parsed) {\n@@ -209,6 +206,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \t\t\t\t\treturn NULL;\n \t\t\t\t*eaten_p = 1;\n \t\t\t}\n+\t\t\treturn &tree->object;\n \t\t}\n \t} else if (type == OBJ_COMMIT) {\n \t\tstruct commit *commit = lookup_commit(r, oid);\n@@ -219,20 +217,19 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n \t\t\t\tset_commit_buffer(r, commit, buffer, size);\n \t\t\t\t*eaten_p = 1;\n \t\t\t}\n-\t\t\tobj = &commit->object;\n+\t\t\treturn &commit->object;\n \t\t}\n \t} else if (type == OBJ_TAG) {\n \t\tstruct tag *tag = lookup_tag(r, oid);\n \t\tif (tag) {\n \t\t\tif (parse_tag_buffer(r, tag, buffer, size))\n \t\t\t       return NULL;\n-\t\t\tobj = &tag->object;\n+\t\t\treturn &tag->object;\n \t\t}\n \t} else {\n \t\twarning(_(\"object %s has unknown type id %d\"), oid_to_hex(oid), type);\n-\t\tobj = NULL;\n \t}\n-\treturn obj;\n+\treturn NULL;\n }\n \n struct object *parse_object_or_die(const struct object_id *oid,\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422415","messageId":"patch-09.10-e463fe5f6a-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 09/10] mktree: stop setting *ntr++ to NIL","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:42Z","receivedAt":"2021-04-20T12:51:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Since 58ce21b819e (builtin/mktree: remove hard-coded constant,\n2018-10-15) we have not made any subsequent use of the ntr variable\nitself, but we did rely on it to NIL-delimit the string we were about\nto feed to type_from_string().\n\nUsing type_from_string() here results in needless work, as we'd do a\nstrlen() on it, just to find point at which we had a SPC\ncharacter (now NIL) earlier in this function.\n\nWe can instead skip incrementing the ntr pointer, then pass the\npointer and length to the type_from_string() function instead.\n\nDoing so would have been buggy in cases where the type was invalid\nuntil a preceding commit fixed the die() invocation in\ntype_from_string() to also pay attention to the length. A preceding\ncommit added a test to t1010-mktree.sh which would fail if not for\nthat fix in type_from_string(), i.e. we'd end up printing the rest of\nthe line, not just the invalid type.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/mktree.c | 5 +----\n 1 file changed, 1 insertion(+), 4 deletions(-)\n\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex 891991b00d..7a27cfa2e0 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -95,9 +95,6 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n \tif (S_ISGITLINK(mode))\n \t\tallow_missing = 1;\n \n-\n-\t*ntr++ = 0; /* now at the beginning of SHA1 */\n-\n \tpath = (char *)p + 1;  /* at the beginning of name */\n \tif (!nul_term_line && path[0] == '\"') {\n \t\tstruct strbuf p_uq = STRBUF_INIT;\n@@ -111,7 +108,7 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n \t * These should all agree.\n \t */\n \tmode_type = object_type(mode);\n-\tif (mode_type != type_from_string(ptr)) {\n+\tif (mode_type != type_from_string_gently(ptr, ntr - ptr, 0)) {\n \t\tdie(\"entry '%s' object type (%s) doesn't match mode type (%s)\",\n \t\t\tpath, ptr, type_name(mode_type));\n \t}\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422416","messageId":"patch-10.10-fe75526a65-20210420T124428Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com","subject":"[PATCH v2 10/10] mktree: emit a more detailed error when the <type> is invalid","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T12:50:43Z","receivedAt":"2021-04-20T12:51:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"When given an invalid <type> as part of a \"<mode> SP [...]\" line (see\nthe added comment) we'd use the generic die() message in\ntype_from_string_gently().\n\nLet's do a bit better in that case and emit a message at the same\nlevel of detail as the existing die() message if the type was valid,\nbut didn't match the mode.\n\nIn preceding commits we fixed the type_from_string_gently() function\nfor cases where gentle=0, now there are no more callers of it that\npass \"gentle=0\" that aren't type_from_string() itself.\n\nSo that fixing of a bug wasn't strictly needed for this end-state, but\nhelps to incrementally explain and test the changes we're making, and\nof course leaves type_from_string_gently() in a good state for any\nfuture gently=0 callers.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/mktree.c  | 20 ++++++++++++++++----\n t/t1010-mktree.sh |  2 +-\n 2 files changed, 17 insertions(+), 5 deletions(-)\n\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex 7a27cfa2e0..67e11d8562 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -72,8 +72,17 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n \tchar *ptr, *ntr;\n \tconst char *p;\n \tunsigned mode;\n-\tenum object_type mode_type; /* object type derived from mode */\n-\tenum object_type obj_type; /* object type derived from sha */\n+\t/*\n+\t * For a line like:\n+\t *\n+\t *     <mode> SP <type> SP <object> SP <object size> TAB <file>\"\n+\t *\n+\t * We'll discover and validate the type from all of <mode>,\n+\t * <type> and <object>\n+\t */\n+\tenum object_type mode_type;\n+\tenum object_type type_type;\n+\tenum object_type obj_type;\n \tchar *path, *to_free = NULL;\n \tstruct object_id oid;\n \n@@ -108,10 +117,13 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n \t * These should all agree.\n \t */\n \tmode_type = object_type(mode);\n-\tif (mode_type != type_from_string_gently(ptr, ntr - ptr, 0)) {\n+\ttype_type = type_from_string_gently(ptr, ntr - ptr, 1);\n+\tif (type_type < 0)\n+\t\tdie(\"entry '%s' object type '%.*s' is invalid (our derived mode type is '%s')\",\n+\t\t\tpath, (int)(ntr - ptr), ptr, type_name(mode_type));\n+\telse if (mode_type != type_type)\n \t\tdie(\"entry '%s' object type (%s) doesn't match mode type (%s)\",\n \t\t\tpath, ptr, type_name(mode_type));\n-\t}\n \n \t/* Check the type of object identified by sha1 */\n \tobj_type = oid_object_info(the_repository, &oid, NULL);\ndiff --git a/t/t1010-mktree.sh b/t/t1010-mktree.sh\nindex 2a7b04aed8..fe8601e7bb 100755\n--- a/t/t1010-mktree.sh\n+++ b/t/t1010-mktree.sh\n@@ -63,7 +63,7 @@ test_expect_success 'invalid object type' '\n \ttest_must_fail git mktree <bad-type >out 2>err &&\n \ttest_must_be_empty out &&\n \tcat >expected <<-\\EOF &&\n-\tfatal: invalid object type \"whee\"\n+\tfatal: entry '\"'\"'a.'\"'\"' object type '\"'\"'whee'\"'\"' is invalid (our derived mode type is '\"'\"'tree'\"'\"')\n \tEOF\n \ttest_cmp expected err\n '\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422417","messageId":"patch-01.10-0ff9c653c3-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 01/10] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:07Z","receivedAt":"2021-04-20T13:00:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the type_from_string() macro into a function and drop the\nsupport for passing len < 0.\n\nSupport for len < 0 was added in fe8e3b71805 (Refactor\ntype_from_string() to allow continuing after detecting an error,\n2014-09-10), but no callers use that form. Let's drop it to simplify\nthis, and in preparation for simplifying these even further.\n\nEven though the argument was changed from ssize_t to the unsigned\nsize_t C is by design forgiving about passing -1 as an unsigned\ntype (it's just an alias for \"set all bits)\", let's detect any\noutstanding in-flight callers passing a -1.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 13 ++++++++++---\n object.h |  4 ++--\n 2 files changed, 12 insertions(+), 5 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex bad9e17f25..aae2a27e55 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,12 +35,12 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, ssize_t len, int gentle)\n+int type_from_string_gently(const char *str, size_t len, int gentle)\n {\n \tint i;\n \n-\tif (len < 0)\n-\t\tlen = strlen(str);\n+\tif (len == ~(size_t)0)\n+\t\tBUG(\"type-from-string-gently no longer allows unspecified length\");\n \n \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n@@ -53,6 +53,13 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n \tdie(_(\"invalid object type \\\"%.*s\\\"\"), (int)len, str);\n }\n \n+int type_from_string(const char *str)\n+{\n+\tsize_t len = strlen(str);\n+\tint ret = type_from_string_gently(str, len, 0);\n+\treturn ret;\n+}\n+\n /*\n  * Return a numerical hash value between 0 and n-1 for the object with\n  * the specified sha1.  n must be a power of 2.  Please note that the\ndiff --git a/object.h b/object.h\nindex 59daadce21..f9d8f4d22b 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,8 +93,8 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, ssize_t, int gentle);\n-#define type_from_string(str) type_from_string_gently(str, -1, 0)\n+int type_from_string_gently(const char *str, size_t, int gentle);\n+int type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422418","messageId":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com","subject":"[PATCH v2 00/10] {tag,object}*.c: refactorings + prep for a larger change","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:06Z","receivedAt":"2021-04-20T13:00:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This goes on top of my just-submitted\nhttps://lore.kernel.org/git/cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com/\nfor v1 of this see\nhttps://lore.kernel.org/git/cover-0.6-0000000000-20210409T082935Z-avarab@gmail.com/\n\nAs noted in the What's Cooking etc. the previous version of this\nseries's base and this on had a semantic conflict with brian's\nhash-object.c work. See\nhttps://lore.kernel.org/git/87mttx121j.fsf@evledraar.gmail.com/\n\nThat's now solved by this and the preceding series going through the\ncodebase and (culminating in this one) removing type_from_string()\nentirely. There's still a \"BUG\" here in case we have any other\nin-flight \"-1\" caller.\n\nThis will textually conflict with brian's hash-object.c work. But as\nnoted in the above-linked thread I've proposed another way forward\nwith brian's series independent of this one. In any case, the conflict\nisn't hard to resolve, and I wanted to re-roll this sooner than later.\n\nÆvar Arnfjörð Bjarmason (10):\n  object.c: stop supporting len == -1 in type_from_string_gently()\n  object.c: remove \"gently\" argument to type_from_string_gently()\n  object.c: make type_from_string() return \"enum object_type\"\n  object-file.c: make oid_object_info() return \"enum object_type\"\n  object-name.c: make dependency on object_type order more obvious\n  tag.c: use type_from_string_gently() when parsing tags\n  hash-object: pass along type length to object.c\n  hash-object: refactor nested else/if/if into else if/else if\n  hash-object: show usage on invalid --type\n  object.c: move type_from_string() code to its last user\n\n builtin/blame.c        |  2 +-\n builtin/cat-file.c     |  4 ++-\n builtin/hash-object.c  | 63 ++++++++++++++++++++++++++----------------\n builtin/index-pack.c   |  2 +-\n builtin/mktree.c       |  2 +-\n fsck.c                 |  2 +-\n object-file.c          | 36 ++++++++++++------------\n object-name.c          | 25 +++++++++--------\n object-store.h         |  8 ++++--\n object.c               | 14 ++++------\n object.h               |  3 +-\n packfile.c             |  2 +-\n t/t1007-hash-object.sh | 10 ++++---\n tag.c                  | 19 +++++++------\n 14 files changed, 106 insertions(+), 86 deletions(-)\n\nRange-diff against v1:\n 3:  820f3aed21 !  1:  0ff9c653c3 object.c: stop supporting len == -1 in type_from_string_gently()\n    @@ Commit message\n         2014-09-10), but no callers use that form. Let's drop it to simplify\n         this, and in preparation for simplifying these even further.\n     \n    +    Even though the argument was changed from ssize_t to the unsigned\n    +    size_t C is by design forgiving about passing -1 as an unsigned\n    +    type (it's just an alias for \"set all bits)\", let's detect any\n    +    outstanding in-flight callers passing a -1.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## object.c ##\n    -@@ object.c: int type_from_string_gently(const char *str, ssize_t len, int gentle)\n    +@@ object.c: const char *type_name(unsigned int type)\n    + \treturn object_type_strings[type];\n    + }\n    + \n    +-int type_from_string_gently(const char *str, ssize_t len, int gentle)\n    ++int type_from_string_gently(const char *str, size_t len, int gentle)\n      {\n      \tint i;\n      \n     -\tif (len < 0)\n     -\t\tlen = strlen(str);\n    --\n    ++\tif (len == ~(size_t)0)\n    ++\t\tBUG(\"type-from-string-gently no longer allows unspecified length\");\n    + \n      \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n      \t\tif (!strncmp(str, object_type_strings[i], len) &&\n    - \t\t    object_type_strings[i][len] == '\\0')\n     @@ object.c: int type_from_string_gently(const char *str, ssize_t len, int gentle)\n    - \tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n    + \tdie(_(\"invalid object type \\\"%.*s\\\"\"), (int)len, str);\n      }\n      \n     +int type_from_string(const char *str)\n    @@ object.c: int type_from_string_gently(const char *str, ssize_t len, int gentle)\n     \n      ## object.h ##\n     @@ object.h: struct object {\n    + };\n      \n      const char *type_name(unsigned int type);\n    - int type_from_string_gently(const char *str, ssize_t, int gentle);\n    +-int type_from_string_gently(const char *str, ssize_t, int gentle);\n     -#define type_from_string(str) type_from_string_gently(str, -1, 0)\n    ++int type_from_string_gently(const char *str, size_t, int gentle);\n     +int type_from_string(const char *str);\n      \n      /*\n 4:  daed40c479 !  2:  5fa3128127 object.c: remove \"gently\" argument to type_from_string_gently()\n    @@ Commit message\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    + ## builtin/mktree.c ##\n    +@@ builtin/mktree.c: static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n    + \t * These should all agree.\n    + \t */\n    + \tmode_type = object_type(mode);\n    +-\ttype_type = type_from_string_gently(ptr, ntr - ptr, 1);\n    ++\ttype_type = type_from_string_gently(ptr, ntr - ptr);\n    + \tif (type_type < 0)\n    + \t\tdie(\"entry '%s' object type '%.*s' is invalid (our derived mode type is '%s')\",\n    + \t\t\tpath, (int)(ntr - ptr), ptr, type_name(mode_type));\n    +\n      ## fsck.c ##\n     @@ fsck.c: int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n      \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, \"invalid format - unexpected end after 'type' line\");\n    @@ object.c: const char *type_name(unsigned int type)\n      \treturn object_type_strings[type];\n      }\n      \n    --int type_from_string_gently(const char *str, ssize_t len, int gentle)\n    -+int type_from_string_gently(const char *str, ssize_t len)\n    +-int type_from_string_gently(const char *str, size_t len, int gentle)\n    ++int type_from_string_gently(const char *str, size_t len)\n      {\n      \tint i;\n      \n    -@@ object.c: int type_from_string_gently(const char *str, ssize_t len, int gentle)\n    +@@ object.c: int type_from_string_gently(const char *str, size_t len, int gentle)\n      \t\tif (!strncmp(str, object_type_strings[i], len) &&\n      \t\t    object_type_strings[i][len] == '\\0')\n      \t\t\treturn i;\n    @@ object.c: int type_from_string_gently(const char *str, ssize_t len, int gentle)\n     -\tif (gentle)\n     -\t\treturn -1;\n     -\n    --\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n    +-\tdie(_(\"invalid object type \\\"%.*s\\\"\"), (int)len, str);\n     +\treturn -1;\n      }\n      \n    @@ object.h: struct object {\n      };\n      \n      const char *type_name(unsigned int type);\n    --int type_from_string_gently(const char *str, ssize_t, int gentle);\n    -+int type_from_string_gently(const char *str, ssize_t len);\n    +-int type_from_string_gently(const char *str, size_t, int gentle);\n    ++int type_from_string_gently(const char *str, size_t len);\n      int type_from_string(const char *str);\n      \n      /*\n 5:  7fd86f6699 !  3:  f0ec7d1dbb object.c: make type_from_string() return \"enum object_type\"\n    @@ object.c: const char *type_name(unsigned int type)\n      \treturn object_type_strings[type];\n      }\n      \n    --int type_from_string_gently(const char *str, ssize_t len)\n    -+enum object_type type_from_string_gently(const char *str, ssize_t len)\n    +-int type_from_string_gently(const char *str, size_t len)\n    ++enum object_type type_from_string_gently(const char *str, size_t len)\n      {\n     -\tint i;\n     +\tenum object_type i;\n      \n    - \tfor (i = 1; i < ARRAY_SIZE(object_type_strings); i++)\n    - \t\tif (!strncmp(str, object_type_strings[i], len) &&\n    -@@ object.c: int type_from_string_gently(const char *str, ssize_t len)\n    + \tif (len == ~(size_t)0)\n    + \t\tBUG(\"type-from-string-gently no longer allows unspecified length\");\n    +@@ object.c: int type_from_string_gently(const char *str, size_t len)\n      \treturn -1;\n      }\n      \n    @@ object.h: struct object {\n      };\n      \n      const char *type_name(unsigned int type);\n    --int type_from_string_gently(const char *str, ssize_t len);\n    +-int type_from_string_gently(const char *str, size_t len);\n     -int type_from_string(const char *str);\n    -+enum object_type type_from_string_gently(const char *str, ssize_t len);\n    ++enum object_type type_from_string_gently(const char *str, size_t len);\n     +enum object_type type_from_string(const char *str);\n      \n      /*\n 6:  ebea1b2b50 =  4:  fa97396517 object-file.c: make oid_object_info() return \"enum object_type\"\n 7:  94e13611f0 =  5:  a607239b56 object-name.c: make dependency on object_type order more obvious\n 8:  3279d67d2b =  6:  e6fe7ce064 tag.c: use type_from_string_gently() when parsing tags\n 1:  68a7709fe5 !  7:  a5ac9f1dd8 blob.c: remove buffer & size arguments to parse_blob_buffer()\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    blob.c: remove buffer & size arguments to parse_blob_buffer()\n    +    hash-object: pass along type length to object.c\n     \n    -    As noted in the comment introduced in 837d395a5c0 (Replace\n    -    parse_blob() with an explanatory comment, 2010-01-18) the old\n    -    parse_blob() function and the current parse_blob_buffer() exist merely\n    -    to provide consistency in the API.\n    +    Change the functions to do with passing the type down to\n    +    hash_object_file_literally() to pass the length of the type as well as\n    +    the \"const char *\" type name.\n     \n    -    We're not going to parse blobs like we \"parse\" commits, trees or\n    -    tags. So let's not have the parse_blob_buffer() take arguments that\n    -    pretends that we do. Its only use is to set the \"parsed\" flag.\n    +    The immediate motivation for this is to move hash-object.c over to\n    +    type_from_string_gently() to emit a better error message, but it will\n    +    also allow us in the future to craft an invalid object with a \"\\0\" in\n    +    the type name.\n     \n    -    See bd2c39f58f9 ([PATCH] don't load and decompress objects twice with\n    -    parse_object(), 2005-05-06) for the introduction of parse_blob_buffer().\n    -\n    -    I'm moving the prototype of parse_blob_buffer() below the comment\n    -    added in 837d395a5c0 while I'm at it. That comment was originally\n    -    meant to be a replacement for the missing parse_blob() function, but\n    -    it's much less confusing to have it be above the parse_blob_buffer()\n    -    function it refers to.\n    +    We'd need to learn a --type-file=* option or similar (we can't of\n    +    course, pass a string with \"\\0\" on the command-line). Right now such\n    +    an object can be manually crafted, but we can't test for it with\n    +    --literally.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## blob.c ##\n    -@@ blob.c: struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n    - \treturn object_as_type(obj, OBJ_BLOB, 0);\n    + ## builtin/hash-object.c ##\n    +@@ builtin/hash-object.c: static int hash_literally(struct object_id *oid, int fd, const char *type, unsig\n    + \tif (strbuf_read(&buf, fd, 4096) < 0)\n    + \t\tret = -1;\n    + \telse\n    +-\t\tret = hash_object_file_literally(buf.buf, buf.len, type, oid,\n    +-\t\t\t\t\t\t flags);\n    ++\t\tret = hash_object_file_literally(buf.buf, buf.len, type,\n    ++\t\t\t\t\t\t strlen(type), oid, flags);\n    + \tstrbuf_release(&buf);\n    + \treturn ret;\n    + }\n    + \n    +-static void hash_fd(int fd, const char *type, const char *path, unsigned flags,\n    +-\t\t    int literally)\n    ++static void hash_fd(int fd, const char *type, size_t type_len,\n    ++\t\t    const char *path, unsigned flags, int literally)\n    + {\n    + \tstruct stat st;\n    + \tstruct object_id oid;\n    +@@ builtin/hash-object.c: static void hash_fd(int fd, const char *type, const char *path, unsigned flags,\n    + \tmaybe_flush_or_die(stdout, \"hash to stdout\");\n    + }\n    + \n    +-static void hash_object(const char *path, const char *type, const char *vpath,\n    +-\t\t\tunsigned flags, int literally)\n    ++static void hash_object(const char *path, const char *type, size_t type_len,\n    ++\t\t\tconst char *vpath, unsigned flags, int literally)\n    + {\n    + \tint fd;\n    + \tfd = open(path, O_RDONLY);\n    + \tif (fd < 0)\n    + \t\tdie_errno(\"Cannot open '%s'\", path);\n    +-\thash_fd(fd, type, vpath, flags, literally);\n    ++\thash_fd(fd, type, type_len, vpath, flags, literally);\n      }\n      \n    --int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n    -+int parse_blob_buffer(struct blob *item)\n    +-static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n    +-\t\t\t     int literally)\n    ++static void hash_stdin_paths(const char *type, size_t type_len, int no_filters,\n    ++\t\t\t     unsigned flags, int literally)\n      {\n    - \titem->object.parsed = 1;\n    + \tstruct strbuf buf = STRBUF_INIT;\n    + \tstruct strbuf unquoted = STRBUF_INIT;\n    + \n    + \twhile (strbuf_getline(&buf, stdin) != EOF) {\n    ++\t\tconst char *vpath;\n    + \t\tif (buf.buf[0] == '\"') {\n    + \t\t\tstrbuf_reset(&unquoted);\n    + \t\t\tif (unquote_c_style(&unquoted, buf.buf, NULL))\n    + \t\t\t\tdie(\"line is badly quoted\");\n    + \t\t\tstrbuf_swap(&buf, &unquoted);\n    + \t\t}\n    +-\t\thash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,\n    +-\t\t\t    literally);\n    ++\t\tvpath = no_filters ? NULL : buf.buf;\n    ++\t\thash_object(buf.buf, type, type_len, vpath , flags, literally);\n    + \t}\n    + \tstrbuf_release(&buf);\n    + \tstrbuf_release(&unquoted);\n    +@@ builtin/hash-object.c: int cmd_hash_object(int argc, const char **argv, const char *prefix)\n    + \t\tNULL\n    + \t};\n    + \tconst char *type = blob_type;\n    ++\tsize_t type_len;\n    + \tint hashstdin = 0;\n    + \tint stdin_paths = 0;\n    + \tint no_filters = 0;\n    +@@ builtin/hash-object.c: int cmd_hash_object(int argc, const char **argv, const char *prefix)\n    + \t\tusage_with_options(hash_object_usage, hash_object_options);\n    + \t}\n    + \n    ++\ttype_len = strlen(type);\n    + \tif (hashstdin)\n    +-\t\thash_fd(0, type, vpath, flags, literally);\n    ++\t\thash_fd(0, type, type_len, vpath, flags, literally);\n    + \n    + \tfor (i = 0 ; i < argc; i++) {\n    + \t\tconst char *arg = argv[i];\n    +@@ builtin/hash-object.c: int cmd_hash_object(int argc, const char **argv, const char *prefix)\n    + \n    + \t\tif (prefix)\n    + \t\t\targ = to_free = prefix_filename(prefix, arg);\n    +-\t\thash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,\n    ++\t\thash_object(arg, type, type_len, no_filters ? NULL : vpath ? vpath : arg,\n    + \t\t\t    flags, literally);\n    + \t\tfree(to_free);\n    + \t}\n    + \n    + \tif (stdin_paths)\n    +-\t\thash_stdin_paths(type, no_filters, flags, literally);\n    ++\t\thash_stdin_paths(type, type_len, no_filters, flags, literally);\n    + \n      \treturn 0;\n    + }\n     \n    - ## blob.h ##\n    -@@ blob.h: struct blob {\n    - \n    - struct blob *lookup_blob(struct repository *r, const struct object_id *oid);\n    - \n    --int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n    --\n    - /**\n    -  * Blobs do not contain references to other objects and do not have\n    -  * structured data that needs parsing. However, code may use the\n    -@@ blob.h: int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size);\n    -  * parse_blob_buffer() is used (by object.c) to flag that the object\n    -  * has been read successfully from the database.\n    -  **/\n    -+int parse_blob_buffer(struct blob *item);\n    - \n    - #endif /* BLOB_H */\n    + ## object-file.c ##\n    +@@ object-file.c: void *read_object_with_reference(struct repository *r,\n    + \n    + static void write_object_file_prepare(const struct git_hash_algo *algo,\n    + \t\t\t\t      const void *buf, unsigned long len,\n    +-\t\t\t\t      const char *type, struct object_id *oid,\n    +-\t\t\t\t      char *hdr, int *hdrlen)\n    ++\t\t\t\t      const char *type, size_t type_len,\n    ++\t\t\t\t      struct object_id *oid, char *hdr,\n    ++\t\t\t\t      int *hdrlen)\n    + {\n    + \tgit_hash_ctx c;\n    + \n    + \t/* Generate the header */\n    +-\t*hdrlen = xsnprintf(hdr, *hdrlen, \"%s %\"PRIuMAX , type, (uintmax_t)len)+1;\n    ++\t*hdrlen = xsnprintf(hdr, *hdrlen, \"%.*s %\"PRIuMAX,\n    ++\t\t\t    (int)type_len, type, (uintmax_t)len) + 1;\n    + \n    + \t/* Sha1.. */\n    + \talgo->init_fn(&c);\n    +@@ object-file.c: int hash_object_file(const struct git_hash_algo *algo, const void *buf,\n    + {\n    + \tchar hdr[MAX_HEADER_LEN];\n    + \tint hdrlen = sizeof(hdr);\n    +-\twrite_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);\n    ++\twrite_object_file_prepare(algo, buf, len, type, strlen(type), oid, hdr,\n    ++\t\t\t\t  &hdrlen);\n    + \treturn 0;\n    + }\n    + \n    +@@ object-file.c: int write_object_file(const void *buf, unsigned long len, const char *type,\n    + {\n    + \tchar hdr[MAX_HEADER_LEN];\n    + \tint hdrlen = sizeof(hdr);\n    ++\tsize_t type_len = strlen(type);\n    + \n    + \t/* Normally if we have it in the pack then we do not bother writing\n    + \t * it out into .git/objects/??/?{38} file.\n    + \t */\n    +-\twrite_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,\n    +-\t\t\t\t  &hdrlen);\n    ++\twrite_object_file_prepare(the_hash_algo, buf, len, type, type_len, oid,\n    ++\t\t\t\t  hdr, &hdrlen);\n    + \tif (freshen_packed_object(oid) || freshen_loose_object(oid))\n    + \t\treturn 0;\n    + \treturn write_loose_object(oid, hdr, hdrlen, buf, len, 0);\n    + }\n    + \n    + int hash_object_file_literally(const void *buf, unsigned long len,\n    +-\t\t\t       const char *type, struct object_id *oid,\n    +-\t\t\t       unsigned flags)\n    ++\t\t\t       const char *type, size_t type_len,\n    ++\t\t\t       struct object_id *oid, unsigned flags)\n    + {\n    + \tchar *header;\n    + \tint hdrlen, status = 0;\n    + \n    + \t/* type string, SP, %lu of the length plus NUL must fit this */\n    +-\thdrlen = strlen(type) + MAX_HEADER_LEN;\n    ++\thdrlen = type_len + MAX_HEADER_LEN;\n    + \theader = xmalloc(hdrlen);\n    +-\twrite_object_file_prepare(the_hash_algo, buf, len, type, oid, header,\n    +-\t\t\t\t  &hdrlen);\n    ++\twrite_object_file_prepare(the_hash_algo, buf, len, type, type_len, oid,\n    ++\t\t\t\t  header, &hdrlen);\n    + \n    + \tif (!(flags & HASH_WRITE_OBJECT))\n    + \t\tgoto cleanup;\n     \n    - ## object.c ##\n    -@@ object.c: struct object *parse_object_buffer(struct repository *r, const struct object_id\n    - \tif (type == OBJ_BLOB) {\n    - \t\tstruct blob *blob = lookup_blob(r, oid);\n    - \t\tif (blob) {\n    --\t\t\tif (parse_blob_buffer(blob, buffer, size))\n    -+\t\t\tif (parse_blob_buffer(blob))\n    - \t\t\t\treturn NULL;\n    - \t\t\tobj = &blob->object;\n    - \t\t}\n    -@@ object.c: struct object *parse_object(struct repository *r, const struct object_id *oid)\n    - \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n    - \t\t\treturn NULL;\n    - \t\t}\n    --\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n    -+\t\tparse_blob_buffer(lookup_blob(r, oid));\n    - \t\treturn lookup_object(r, oid);\n    - \t}\n    + ## object-store.h ##\n    +@@ object-store.h: int write_object_file(const void *buf, unsigned long len,\n    + \t\t      const char *type, struct object_id *oid);\n    + \n    + int hash_object_file_literally(const void *buf, unsigned long len,\n    +-\t\t\t       const char *type, struct object_id *oid,\n    +-\t\t\t       unsigned flags);\n    ++\t\t\t       const char *type, size_t type_len,\n    ++\t\t\t       struct object_id *oid, unsigned flags);\n      \n    + /*\n    +  * Add an object file to the in-memory object store, without writing it\n -:  ---------- >  8:  7bf04edc74 hash-object: refactor nested else/if/if into else if/else if\n 2:  f1fcc31717 !  9:  eaa1b8f44c object.c: initialize automatic variable in lookup_object()\n    @@ Metadata\n     Author: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## Commit message ##\n    -    object.c: initialize automatic variable in lookup_object()\n    +    hash-object: show usage on invalid --type\n     \n    -    Initialize a \"struct object obj*\" variable to NULL explicitly and\n    -    return it instead of leaving it uninitialized until the \"while\"\n    -    loop.\n    +    Change the error displayed on \"hash-object -t bogus\" (without\n    +    --literally) to show the usage_with_options(), like we do for the\n    +    other usage errors.\n     \n    -    There was no bug here, it's just less confusing when debugging if the\n    -    \"obj\" is either NULL or a valid object, not some random invalid\n    -    pointer.\n    -\n    -    See 0556a11a0df (git object hash cleanups, 2006-06-30) for the initial\n    -    implementation.\n    +    As noted in a preceding commit it makes sense to pass the \"len\" down\n    +    to the object.c code, so now that we're using\n    +    type_from_string_gently() let's do that.\n     \n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n    - ## object.c ##\n    -@@ object.c: static void insert_obj_hash(struct object *obj, struct object **hash, unsigned i\n    - struct object *lookup_object(struct repository *r, const struct object_id *oid)\n    + ## builtin/hash-object.c ##\n    +@@ builtin/hash-object.c: static int hash_literally(struct object_id *oid, int fd, const char *type, unsig\n    + \treturn ret;\n    + }\n    + \n    +-static void hash_fd(int fd, const char *type, size_t type_len,\n    +-\t\t    const char *path, unsigned flags, int literally)\n    ++static void hash_fd(int fd, enum object_type otype, const char *type,\n    ++\t\t    size_t type_len, const char *path, unsigned flags,\n    ++\t\t    int literally)\n    + {\n    + \tstruct stat st;\n    + \tstruct object_id oid;\n    +@@ builtin/hash-object.c: static void hash_fd(int fd, const char *type, size_t type_len,\n    + \tif (fstat(fd, &st) < 0 ||\n    + \t    (literally\n    + \t     ? hash_literally(&oid, fd, type, flags)\n    +-\t     : index_fd(the_repository->index, &oid, fd, &st,\n    +-\t\t\ttype_from_string(type), path, flags)))\n    ++\t     : index_fd(the_repository->index, &oid, fd, &st, otype, path,\n    ++\t\t\tflags)))\n    + \t\tdie((flags & HASH_WRITE_OBJECT)\n    + \t\t    ? \"Unable to add %s to database\"\n    + \t\t    : \"Unable to hash %s\", path);\n    +@@ builtin/hash-object.c: static void hash_fd(int fd, const char *type, size_t type_len,\n    + \tmaybe_flush_or_die(stdout, \"hash to stdout\");\n    + }\n    + \n    +-static void hash_object(const char *path, const char *type, size_t type_len,\n    ++static void hash_object(const char *path, enum object_type otype,\n    ++\t\t\tconst char *type, size_t type_len,\n    + \t\t\tconst char *vpath, unsigned flags, int literally)\n      {\n    - \tunsigned int i, first;\n    --\tstruct object *obj;\n    -+\tstruct object *obj = NULL;\n    + \tint fd;\n    + \tfd = open(path, O_RDONLY);\n    + \tif (fd < 0)\n    + \t\tdie_errno(\"Cannot open '%s'\", path);\n    +-\thash_fd(fd, type, type_len, vpath, flags, literally);\n    ++\thash_fd(fd, otype, type, type_len, vpath, flags, literally);\n    + }\n    + \n    +-static void hash_stdin_paths(const char *type, size_t type_len, int no_filters,\n    ++static void hash_stdin_paths(enum object_type otype, const char *type,\n    ++\t\t\t     size_t type_len, int no_filters,\n    + \t\t\t     unsigned flags, int literally)\n    + {\n    + \tstruct strbuf buf = STRBUF_INIT;\n    +@@ builtin/hash-object.c: static void hash_stdin_paths(const char *type, size_t type_len, int no_filters,\n    + \t\t\tstrbuf_swap(&buf, &unquoted);\n    + \t\t}\n    + \t\tvpath = no_filters ? NULL : buf.buf;\n    +-\t\thash_object(buf.buf, type, type_len, vpath , flags, literally);\n    ++\t\thash_object(buf.buf, otype, type, type_len, vpath , flags, literally);\n    + \t}\n    + \tstrbuf_release(&buf);\n    + \tstrbuf_release(&unquoted);\n    +@@ builtin/hash-object.c: int cmd_hash_object(int argc, const char **argv, const char *prefix)\n    + \t};\n    + \tconst char *type = blob_type;\n    + \tsize_t type_len;\n    ++\tenum object_type otype = OBJ_BAD;\n    + \tint hashstdin = 0;\n    + \tint stdin_paths = 0;\n    + \tint no_filters = 0;\n    +@@ builtin/hash-object.c: int cmd_hash_object(int argc, const char **argv, const char *prefix)\n    + \t};\n    + \tint i;\n    + \tconst char *errstr = NULL;\n    ++\tint errstr_arg_type = 0;\n    + \n    + \targc = parse_options(argc, argv, prefix, hash_object_options,\n    + \t\t\t     hash_object_usage, 0);\n    +@@ builtin/hash-object.c: int cmd_hash_object(int argc, const char **argv, const char *prefix)\n    + \n    + \tgit_config(git_default_config, NULL);\n    + \n    +-\tif (stdin_paths) {\n    ++\ttype_len = strlen(type);\n    ++\totype = type_from_string_gently(type, type_len);\n    ++\tif (otype < 0 && !literally) {\n    ++\t\terrstr = \"the object type \\\"%.*s\\\" is invalid, did you mean to use --literally?\";\n    ++\t\terrstr_arg_type = 1;\n    ++\t} else if (stdin_paths) {\n    + \t\tif (hashstdin)\n    + \t\t\terrstr = \"Can't use --stdin-paths with --stdin\";\n    + \t\telse if (argc)\n    +@@ builtin/hash-object.c: int cmd_hash_object(int argc, const char **argv, const char *prefix)\n    + \t}\n    + \n    + \tif (errstr) {\n    +-\t\terror(\"%s\", errstr);\n    ++\t\tif (errstr_arg_type)\n    ++\t\t\terror(errstr, (int)type_len, type);\n    ++\t\telse\n    ++\t\t\terror(\"%s\", errstr);\n    + \t\tusage_with_options(hash_object_usage, hash_object_options);\n    + \t}\n    + \n    +-\ttype_len = strlen(type);\n    + \tif (hashstdin)\n    +-\t\thash_fd(0, type, type_len, vpath, flags, literally);\n    ++\t\thash_fd(0, otype, type, type_len, vpath, flags, literally);\n    + \n    + \tfor (i = 0 ; i < argc; i++) {\n    + \t\tconst char *arg = argv[i];\n    + \t\tchar *to_free = NULL;\n    ++\t\tconst char *tmp;\n    + \n    + \t\tif (prefix)\n    + \t\t\targ = to_free = prefix_filename(prefix, arg);\n    +-\t\thash_object(arg, type, type_len, no_filters ? NULL : vpath ? vpath : arg,\n    +-\t\t\t    flags, literally);\n    ++\t\ttmp = no_filters ? NULL : vpath ? vpath : arg;\n    ++\t\thash_object(arg, otype, type, type_len, tmp, flags, literally);\n    + \t\tfree(to_free);\n    + \t}\n    + \n    + \tif (stdin_paths)\n    +-\t\thash_stdin_paths(type, type_len, no_filters, flags, literally);\n    ++\t\thash_stdin_paths(otype, type, type_len, no_filters, flags,\n    ++\t\t\t\t literally);\n    + \n    + \treturn 0;\n    + }\n    +\n    + ## t/t1007-hash-object.sh ##\n    +@@ t/t1007-hash-object.sh: test_expect_success 'corrupt tag' '\n    + '\n      \n    - \tif (!r->parsed_objects->obj_hash)\n    --\t\treturn NULL;\n    -+\t\treturn obj;\n    + test_expect_success 'hash-object complains about bogus type name' '\n    +-\ttest_must_fail git hash-object -t bogus --stdin 2>actual </dev/null &&\n    ++\ttest_expect_code 129 git hash-object -t bogus --stdin 2>err </dev/null &&\n    ++\tgrep ^error err >actual &&\n    + \tcat >expect <<-\\EOF &&\n    +-\tfatal: invalid object type \"bogus\"\n    ++\terror: the object type \"bogus\" is invalid, did you mean to use --literally?\n    + \tEOF\n    + \ttest_cmp expect actual\n    + '\n      \n    - \tfirst = i = hash_obj(oid, r->parsed_objects->obj_hash_size);\n    - \twhile ((obj = r->parsed_objects->obj_hash[i]) != NULL) {\n    + test_expect_success 'hash-object complains about truncated type name' '\n    +-\ttest_must_fail git hash-object -t bl --stdin 2>actual </dev/null &&\n    ++\ttest_expect_code 129 git hash-object -t bl --stdin 2>err </dev/null &&\n    ++\tgrep ^error err >actual &&\n    + \tcat >expect <<-\\EOF &&\n    +-\tfatal: invalid object type \"bl\"\n    ++\terror: the object type \"bl\" is invalid, did you mean to use --literally?\n    + \tEOF\n    + \ttest_cmp expect actual\n    + '\n -:  ---------- > 10:  cb0ea49279 object.c: move type_from_string() code to its last user\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422419","messageId":"patch-02.10-5fa3128127-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 02/10] object.c: remove \"gently\" argument to type_from_string_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:08Z","receivedAt":"2021-04-20T13:00:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Get rid of the \"gently\" argument to type_from_string_gently() to make\nit consistent with most other *_gently() functions. It's already a\n\"gentle\" function, it shouldn't need a boolean argument telling it to\nbe gentle.\n\nThe reason it had a \"gentle\" parameter was because until the preceding\ncommit \"type_from_string()\" was a macro resolving to\n\"type_from_string_gently()\", it's now a function.\n\nThis refactoring of adding a third parameter was done in\nfe8e3b71805 (Refactor type_from_string() to allow continuing after\ndetecting an error, 2014-09-10) in preparation for its use in\nfsck.c.\n\nSimplifying this means we can move the die() into the simpler\ntype_from_string() function.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/mktree.c |  2 +-\n fsck.c           |  2 +-\n object-file.c    |  2 +-\n object.c         | 12 +++++-------\n object.h         |  2 +-\n 5 files changed, 9 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/mktree.c b/builtin/mktree.c\nindex 67e11d8562..7d3f323209 100644\n--- a/builtin/mktree.c\n+++ b/builtin/mktree.c\n@@ -117,7 +117,7 @@ static void mktree_line(char *buf, int nul_term_line, int allow_missing)\n \t * These should all agree.\n \t */\n \tmode_type = object_type(mode);\n-\ttype_type = type_from_string_gently(ptr, ntr - ptr, 1);\n+\ttype_type = type_from_string_gently(ptr, ntr - ptr);\n \tif (type_type < 0)\n \t\tdie(\"entry '%s' object type '%.*s' is invalid (our derived mode type is '%s')\",\n \t\t\tpath, (int)(ntr - ptr), ptr, type_name(mode_type));\ndiff --git a/fsck.c b/fsck.c\nindex f5ed6a2635..8dda548c38 100644\n--- a/fsck.c\n+++ b/fsck.c\n@@ -875,7 +875,7 @@ int fsck_tag_standalone(const struct object_id *oid, const char *buffer,\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_MISSING_TYPE, \"invalid format - unexpected end after 'type' line\");\n \t\tgoto done;\n \t}\n-\t*tagged_type = type_from_string_gently(buffer, eol - buffer, 1);\n+\t*tagged_type = type_from_string_gently(buffer, eol - buffer);\n \tif (*tagged_type < 0)\n \t\tret = report(options, oid, OBJ_TAG, FSCK_MSG_BAD_TYPE, \"invalid 'type' value\");\n \tif (ret)\ndiff --git a/object-file.c b/object-file.c\nindex d2f223dcef..4af4748edd 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1314,7 +1314,7 @@ static int parse_loose_header_extended(const char *hdr, struct object_info *oi,\n \t\ttype_len++;\n \t}\n \n-\ttype = type_from_string_gently(type_buf, type_len, 1);\n+\ttype = type_from_string_gently(type_buf, type_len);\n \tif (oi->type_name)\n \t\tstrbuf_add(oi->type_name, type_buf, type_len);\n \t/*\ndiff --git a/object.c b/object.c\nindex aae2a27e55..7028243c9a 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,7 +35,7 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, size_t len, int gentle)\n+int type_from_string_gently(const char *str, size_t len)\n {\n \tint i;\n \n@@ -46,17 +46,15 @@ int type_from_string_gently(const char *str, size_t len, int gentle)\n \t\tif (!strncmp(str, object_type_strings[i], len) &&\n \t\t    object_type_strings[i][len] == '\\0')\n \t\t\treturn i;\n-\n-\tif (gentle)\n-\t\treturn -1;\n-\n-\tdie(_(\"invalid object type \\\"%.*s\\\"\"), (int)len, str);\n+\treturn -1;\n }\n \n int type_from_string(const char *str)\n {\n \tsize_t len = strlen(str);\n-\tint ret = type_from_string_gently(str, len, 0);\n+\tint ret = type_from_string_gently(str, len);\n+\tif (ret < 0)\n+\t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n \treturn ret;\n }\n \ndiff --git a/object.h b/object.h\nindex f9d8f4d22b..470b3c1b86 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,7 +93,7 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, size_t, int gentle);\n+int type_from_string_gently(const char *str, size_t len);\n int type_from_string(const char *str);\n \n /*\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422420","messageId":"patch-03.10-f0ec7d1dbb-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 03/10] object.c: make type_from_string() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:09Z","receivedAt":"2021-04-20T13:00:37Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the type_from_string*() functions to return an \"enum\nobject_type\", but don't refactor their callers to check for \"==\nOBJ_BAD\" instead of \"< 0\".\n\nRefactoring the check of the return value to check == OBJ_BAD would\nnow be equivalent to \"ret < 0\", but the consensus on an earlier\nversion of this patch was to not do that, and to instead use -1\nconsistently as a return value. It just so happens that OBJ_BAD == -1,\nbut let's not put a hard reliance on that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 8 ++++----\n object.h | 4 ++--\n 2 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 7028243c9a..8f3ddfc8f4 100644\n--- a/object.c\n+++ b/object.c\n@@ -35,9 +35,9 @@ const char *type_name(unsigned int type)\n \treturn object_type_strings[type];\n }\n \n-int type_from_string_gently(const char *str, size_t len)\n+enum object_type type_from_string_gently(const char *str, size_t len)\n {\n-\tint i;\n+\tenum object_type i;\n \n \tif (len == ~(size_t)0)\n \t\tBUG(\"type-from-string-gently no longer allows unspecified length\");\n@@ -49,10 +49,10 @@ int type_from_string_gently(const char *str, size_t len)\n \treturn -1;\n }\n \n-int type_from_string(const char *str)\n+enum object_type type_from_string(const char *str)\n {\n \tsize_t len = strlen(str);\n-\tint ret = type_from_string_gently(str, len);\n+\tenum object_type ret = type_from_string_gently(str, len);\n \tif (ret < 0)\n \t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n \treturn ret;\ndiff --git a/object.h b/object.h\nindex 470b3c1b86..a4eca10d72 100644\n--- a/object.h\n+++ b/object.h\n@@ -93,8 +93,8 @@ struct object {\n };\n \n const char *type_name(unsigned int type);\n-int type_from_string_gently(const char *str, size_t len);\n-int type_from_string(const char *str);\n+enum object_type type_from_string_gently(const char *str, size_t len);\n+enum object_type type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422421","messageId":"patch-04.10-fa97396517-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 04/10] object-file.c: make oid_object_info() return \"enum object_type\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:10Z","receivedAt":"2021-04-20T13:00:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change oid_object_info() to return an \"enum object_type\". Unlike\noid_object_info_extended() function the simpler oid_object_info()\nexplicitly returns the oi.typep member, which is itself an \"enum\nobject_type\".\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/blame.c      |  2 +-\n builtin/index-pack.c |  2 +-\n object-file.c        |  8 +++-----\n object-name.c        | 19 +++++++++----------\n object-store.h       |  4 +++-\n packfile.c           |  2 +-\n 6 files changed, 18 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/blame.c b/builtin/blame.c\nindex 641523ff9a..5dd3c38a8c 100644\n--- a/builtin/blame.c\n+++ b/builtin/blame.c\n@@ -810,7 +810,7 @@ static int peel_to_commit_oid(struct object_id *oid_ret, void *cbdata)\n \toidcpy(&oid, oid_ret);\n \twhile (1) {\n \t\tstruct object *obj;\n-\t\tint kind = oid_object_info(r, &oid, NULL);\n+\t\tenum object_type kind = oid_object_info(r, &oid, NULL);\n \t\tif (kind == OBJ_COMMIT) {\n \t\t\toidcpy(oid_ret, &oid);\n \t\t\treturn 0;\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex 15507b5cff..c0e3768c32 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -237,7 +237,7 @@ static unsigned check_object(struct object *obj)\n \n \tif (!(obj->flags & FLAG_CHECKED)) {\n \t\tunsigned long size;\n-\t\tint type = oid_object_info(the_repository, &obj->oid, &size);\n+\t\tenum object_type type = oid_object_info(the_repository, &obj->oid, &size);\n \t\tif (type <= 0)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\ndiff --git a/object-file.c b/object-file.c\nindex 4af4748edd..398f2b60f9 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1572,11 +1572,9 @@ int oid_object_info_extended(struct repository *r, const struct object_id *oid,\n \treturn ret;\n }\n \n-\n-/* returns enum object_type or negative */\n-int oid_object_info(struct repository *r,\n-\t\t    const struct object_id *oid,\n-\t\t    unsigned long *sizep)\n+enum object_type oid_object_info(struct repository *r,\n+\t\t\t\t const struct object_id *oid,\n+\t\t\t\t unsigned long *sizep)\n {\n \tenum object_type type;\n \tstruct object_info oi = OBJECT_INFO_INIT;\ndiff --git a/object-name.c b/object-name.c\nindex 64202de60b..4d7f0c66cf 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -239,9 +239,8 @@ static int disambiguate_committish_only(struct repository *r,\n \t\t\t\t\tvoid *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \n-\tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_COMMIT)\n \t\treturn 1;\n \tif (kind != OBJ_TAG)\n@@ -258,7 +257,7 @@ static int disambiguate_tree_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_TREE;\n }\n \n@@ -267,7 +266,7 @@ static int disambiguate_treeish_only(struct repository *r,\n \t\t\t\t     void *cb_data_unused)\n {\n \tstruct object *obj;\n-\tint kind;\n+\tenum object_type kind;\n \n \tkind = oid_object_info(r, oid, NULL);\n \tif (kind == OBJ_TREE || kind == OBJ_COMMIT)\n@@ -286,7 +285,7 @@ static int disambiguate_blob_only(struct repository *r,\n \t\t\t\t  const struct object_id *oid,\n \t\t\t\t  void *cb_data_unused)\n {\n-\tint kind = oid_object_info(r, oid, NULL);\n+\tenum object_type kind = oid_object_info(r, oid, NULL);\n \treturn kind == OBJ_BLOB;\n }\n \n@@ -361,7 +360,7 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n {\n \tconst struct disambiguate_state *ds = data;\n \tstruct strbuf desc = STRBUF_INIT;\n-\tint type;\n+\tenum object_type type;\n \n \tif (ds->fn && !ds->fn(ds->repo, oid, ds->cb_data))\n \t\treturn 0;\n@@ -405,10 +404,10 @@ static int repo_collect_ambiguous(struct repository *r,\n static int sort_ambiguous(const void *a, const void *b, void *ctx)\n {\n \tstruct repository *sort_ambiguous_repo = ctx;\n-\tint a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n-\tint b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n-\tint a_type_sort;\n-\tint b_type_sort;\n+\tenum object_type a_type = oid_object_info(sort_ambiguous_repo, a, NULL);\n+\tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n+\tenum object_type a_type_sort;\n+\tenum object_type b_type_sort;\n \n \t/*\n \t * Sorts by hash within the same object type, just as\ndiff --git a/object-store.h b/object-store.h\nindex ec32c23dcb..eab9674d08 100644\n--- a/object-store.h\n+++ b/object-store.h\n@@ -208,7 +208,9 @@ static inline void *repo_read_object_file(struct repository *r,\n #endif\n \n /* Read and unpack an object file into memory, write memory to an object file */\n-int oid_object_info(struct repository *r, const struct object_id *, unsigned long *);\n+enum object_type oid_object_info(struct repository *r,\n+\t\t\t\t const struct object_id *,\n+\t\t\t\t unsigned long *);\n \n int hash_object_file(const struct git_hash_algo *algo, const void *buf,\n \t\t     unsigned long len, const char *type,\ndiff --git a/packfile.c b/packfile.c\nindex 8668345d93..ccfebc0567 100644\n--- a/packfile.c\n+++ b/packfile.c\n@@ -1269,7 +1269,7 @@ static int retry_bad_packed_offset(struct repository *r,\n \t\t\t\t   struct packed_git *p,\n \t\t\t\t   off_t obj_offset)\n {\n-\tint type;\n+\tenum object_type type;\n \tuint32_t pos;\n \tstruct object_id oid;\n \tif (offset_to_pack_pos(p, obj_offset, &pos) < 0)\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422422","messageId":"patch-05.10-a607239b56-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 05/10] object-name.c: make dependency on object_type order more obvious","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:11Z","receivedAt":"2021-04-20T13:00:39Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add an assert to make it more obvious that we were effectively\nhardcoding OBJ_TAG in sort_ambiguous() as \"4\".\n\nI wrote this code in 5cc044e0257 (get_short_oid: sort ambiguous\nobjects by type, then SHA-1, 2018-05-10), there was already a comment\nabout this magic, but let's make sure that someone doing a potential\nreordering of \"enum object_type\" in the future would notice it\nbreaking this function (and probably a bunch of other things...).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object-name.c | 6 ++++--\n 1 file changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/object-name.c b/object-name.c\nindex 4d7f0c66cf..b6a7328b7a 100644\n--- a/object-name.c\n+++ b/object-name.c\n@@ -408,6 +408,8 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)\n \tenum object_type b_type = oid_object_info(sort_ambiguous_repo, b, NULL);\n \tenum object_type a_type_sort;\n \tenum object_type b_type_sort;\n+\tconst enum object_type tag_type_offs = OBJ_TAG - OBJ_NONE;\n+\tassert(tag_type_offs == 4);\n \n \t/*\n \t * Sorts by hash within the same object type, just as\n@@ -425,8 +427,8 @@ static int sort_ambiguous(const void *a, const void *b, void *ctx)\n \t * cleverly) do that with modulus, since the enum assigns 1 to\n \t * commit, so tag becomes 0.\n \t */\n-\ta_type_sort = a_type % 4;\n-\tb_type_sort = b_type % 4;\n+\ta_type_sort = a_type % tag_type_offs;\n+\tb_type_sort = b_type % tag_type_offs;\n \treturn a_type_sort > b_type_sort ? 1 : -1;\n }\n \n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422423","messageId":"patch-06.10-e6fe7ce064-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 06/10] tag.c: use type_from_string_gently() when parsing tags","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:12Z","receivedAt":"2021-04-20T13:00:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a series of strcmp() to instead use type_from_string_gently()\nto get the integer type early, and then use that for comparison.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n tag.c | 19 ++++++++++---------\n 1 file changed, 10 insertions(+), 9 deletions(-)\n\ndiff --git a/tag.c b/tag.c\nindex ed7037256e..1bd81bf1d1 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -140,7 +140,7 @@ void release_tag_memory(struct tag *t)\n int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, unsigned long size)\n {\n \tstruct object_id oid;\n-\tchar type[20];\n+\tenum object_type type;\n \tconst char *bufptr = data;\n \tconst char *tail = bufptr + size;\n \tconst char *nl;\n@@ -167,23 +167,24 @@ int parse_tag_buffer(struct repository *r, struct tag *item, const void *data, u\n \t\treturn -1;\n \tbufptr += 5;\n \tnl = memchr(bufptr, '\\n', tail - bufptr);\n-\tif (!nl || sizeof(type) <= (nl - bufptr))\n+\tif (!nl)\n+\t\treturn -1;\n+\ttype = type_from_string_gently(bufptr, nl - bufptr);\n+\tif (type < 0)\n \t\treturn -1;\n-\tmemcpy(type, bufptr, nl - bufptr);\n-\ttype[nl - bufptr] = '\\0';\n \tbufptr = nl + 1;\n \n-\tif (!strcmp(type, blob_type)) {\n+\tif (type == OBJ_BLOB) {\n \t\titem->tagged = (struct object *)lookup_blob(r, &oid);\n-\t} else if (!strcmp(type, tree_type)) {\n+\t} else if (type == OBJ_TREE) {\n \t\titem->tagged = (struct object *)lookup_tree(r, &oid);\n-\t} else if (!strcmp(type, commit_type)) {\n+\t} else if (type == OBJ_COMMIT) {\n \t\titem->tagged = (struct object *)lookup_commit(r, &oid);\n-\t} else if (!strcmp(type, tag_type)) {\n+\t} else if (type == OBJ_TAG) {\n \t\titem->tagged = (struct object *)lookup_tag(r, &oid);\n \t} else {\n \t\treturn error(\"unknown tag type '%s' in %s\",\n-\t\t\t     type, oid_to_hex(&item->object.oid));\n+\t\t\t     type_name(type), oid_to_hex(&item->object.oid));\n \t}\n \n \tif (!item->tagged)\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422424","messageId":"patch-07.10-a5ac9f1dd8-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 07/10] hash-object: pass along type length to object.c","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:13Z","receivedAt":"2021-04-20T13:00:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the functions to do with passing the type down to\nhash_object_file_literally() to pass the length of the type as well as\nthe \"const char *\" type name.\n\nThe immediate motivation for this is to move hash-object.c over to\ntype_from_string_gently() to emit a better error message, but it will\nalso allow us in the future to craft an invalid object with a \"\\0\" in\nthe type name.\n\nWe'd need to learn a --type-file=* option or similar (we can't of\ncourse, pass a string with \"\\0\" on the command-line). Right now such\nan object can be manually crafted, but we can't test for it with\n--literally.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/hash-object.c | 31 +++++++++++++++++--------------\n object-file.c         | 26 +++++++++++++++-----------\n object-store.h        |  4 ++--\n 3 files changed, 34 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 640ef4ded5..4d3b8c49d2 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -25,14 +25,14 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig\n \tif (strbuf_read(&buf, fd, 4096) < 0)\n \t\tret = -1;\n \telse\n-\t\tret = hash_object_file_literally(buf.buf, buf.len, type, oid,\n-\t\t\t\t\t\t flags);\n+\t\tret = hash_object_file_literally(buf.buf, buf.len, type,\n+\t\t\t\t\t\t strlen(type), oid, flags);\n \tstrbuf_release(&buf);\n \treturn ret;\n }\n \n-static void hash_fd(int fd, const char *type, const char *path, unsigned flags,\n-\t\t    int literally)\n+static void hash_fd(int fd, const char *type, size_t type_len,\n+\t\t    const char *path, unsigned flags, int literally)\n {\n \tstruct stat st;\n \tstruct object_id oid;\n@@ -49,31 +49,32 @@ static void hash_fd(int fd, const char *type, const char *path, unsigned flags,\n \tmaybe_flush_or_die(stdout, \"hash to stdout\");\n }\n \n-static void hash_object(const char *path, const char *type, const char *vpath,\n-\t\t\tunsigned flags, int literally)\n+static void hash_object(const char *path, const char *type, size_t type_len,\n+\t\t\tconst char *vpath, unsigned flags, int literally)\n {\n \tint fd;\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0)\n \t\tdie_errno(\"Cannot open '%s'\", path);\n-\thash_fd(fd, type, vpath, flags, literally);\n+\thash_fd(fd, type, type_len, vpath, flags, literally);\n }\n \n-static void hash_stdin_paths(const char *type, int no_filters, unsigned flags,\n-\t\t\t     int literally)\n+static void hash_stdin_paths(const char *type, size_t type_len, int no_filters,\n+\t\t\t     unsigned flags, int literally)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n \tstruct strbuf unquoted = STRBUF_INIT;\n \n \twhile (strbuf_getline(&buf, stdin) != EOF) {\n+\t\tconst char *vpath;\n \t\tif (buf.buf[0] == '\"') {\n \t\t\tstrbuf_reset(&unquoted);\n \t\t\tif (unquote_c_style(&unquoted, buf.buf, NULL))\n \t\t\t\tdie(\"line is badly quoted\");\n \t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t}\n-\t\thash_object(buf.buf, type, no_filters ? NULL : buf.buf, flags,\n-\t\t\t    literally);\n+\t\tvpath = no_filters ? NULL : buf.buf;\n+\t\thash_object(buf.buf, type, type_len, vpath , flags, literally);\n \t}\n \tstrbuf_release(&buf);\n \tstrbuf_release(&unquoted);\n@@ -87,6 +88,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \t\tNULL\n \t};\n \tconst char *type = blob_type;\n+\tsize_t type_len;\n \tint hashstdin = 0;\n \tint stdin_paths = 0;\n \tint no_filters = 0;\n@@ -141,8 +143,9 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \t\tusage_with_options(hash_object_usage, hash_object_options);\n \t}\n \n+\ttype_len = strlen(type);\n \tif (hashstdin)\n-\t\thash_fd(0, type, vpath, flags, literally);\n+\t\thash_fd(0, type, type_len, vpath, flags, literally);\n \n \tfor (i = 0 ; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n@@ -150,13 +153,13 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \n \t\tif (prefix)\n \t\t\targ = to_free = prefix_filename(prefix, arg);\n-\t\thash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,\n+\t\thash_object(arg, type, type_len, no_filters ? NULL : vpath ? vpath : arg,\n \t\t\t    flags, literally);\n \t\tfree(to_free);\n \t}\n \n \tif (stdin_paths)\n-\t\thash_stdin_paths(type, no_filters, flags, literally);\n+\t\thash_stdin_paths(type, type_len, no_filters, flags, literally);\n \n \treturn 0;\n }\ndiff --git a/object-file.c b/object-file.c\nindex 398f2b60f9..b27ed57e0b 100644\n--- a/object-file.c\n+++ b/object-file.c\n@@ -1715,13 +1715,15 @@ void *read_object_with_reference(struct repository *r,\n \n static void write_object_file_prepare(const struct git_hash_algo *algo,\n \t\t\t\t      const void *buf, unsigned long len,\n-\t\t\t\t      const char *type, struct object_id *oid,\n-\t\t\t\t      char *hdr, int *hdrlen)\n+\t\t\t\t      const char *type, size_t type_len,\n+\t\t\t\t      struct object_id *oid, char *hdr,\n+\t\t\t\t      int *hdrlen)\n {\n \tgit_hash_ctx c;\n \n \t/* Generate the header */\n-\t*hdrlen = xsnprintf(hdr, *hdrlen, \"%s %\"PRIuMAX , type, (uintmax_t)len)+1;\n+\t*hdrlen = xsnprintf(hdr, *hdrlen, \"%.*s %\"PRIuMAX,\n+\t\t\t    (int)type_len, type, (uintmax_t)len) + 1;\n \n \t/* Sha1.. */\n \talgo->init_fn(&c);\n@@ -1786,7 +1788,8 @@ int hash_object_file(const struct git_hash_algo *algo, const void *buf,\n {\n \tchar hdr[MAX_HEADER_LEN];\n \tint hdrlen = sizeof(hdr);\n-\twrite_object_file_prepare(algo, buf, len, type, oid, hdr, &hdrlen);\n+\twrite_object_file_prepare(algo, buf, len, type, strlen(type), oid, hdr,\n+\t\t\t\t  &hdrlen);\n \treturn 0;\n }\n \n@@ -1940,29 +1943,30 @@ int write_object_file(const void *buf, unsigned long len, const char *type,\n {\n \tchar hdr[MAX_HEADER_LEN];\n \tint hdrlen = sizeof(hdr);\n+\tsize_t type_len = strlen(type);\n \n \t/* Normally if we have it in the pack then we do not bother writing\n \t * it out into .git/objects/??/?{38} file.\n \t */\n-\twrite_object_file_prepare(the_hash_algo, buf, len, type, oid, hdr,\n-\t\t\t\t  &hdrlen);\n+\twrite_object_file_prepare(the_hash_algo, buf, len, type, type_len, oid,\n+\t\t\t\t  hdr, &hdrlen);\n \tif (freshen_packed_object(oid) || freshen_loose_object(oid))\n \t\treturn 0;\n \treturn write_loose_object(oid, hdr, hdrlen, buf, len, 0);\n }\n \n int hash_object_file_literally(const void *buf, unsigned long len,\n-\t\t\t       const char *type, struct object_id *oid,\n-\t\t\t       unsigned flags)\n+\t\t\t       const char *type, size_t type_len,\n+\t\t\t       struct object_id *oid, unsigned flags)\n {\n \tchar *header;\n \tint hdrlen, status = 0;\n \n \t/* type string, SP, %lu of the length plus NUL must fit this */\n-\thdrlen = strlen(type) + MAX_HEADER_LEN;\n+\thdrlen = type_len + MAX_HEADER_LEN;\n \theader = xmalloc(hdrlen);\n-\twrite_object_file_prepare(the_hash_algo, buf, len, type, oid, header,\n-\t\t\t\t  &hdrlen);\n+\twrite_object_file_prepare(the_hash_algo, buf, len, type, type_len, oid,\n+\t\t\t\t  header, &hdrlen);\n \n \tif (!(flags & HASH_WRITE_OBJECT))\n \t\tgoto cleanup;\ndiff --git a/object-store.h b/object-store.h\nindex eab9674d08..8f043a6069 100644\n--- a/object-store.h\n+++ b/object-store.h\n@@ -220,8 +220,8 @@ int write_object_file(const void *buf, unsigned long len,\n \t\t      const char *type, struct object_id *oid);\n \n int hash_object_file_literally(const void *buf, unsigned long len,\n-\t\t\t       const char *type, struct object_id *oid,\n-\t\t\t       unsigned flags);\n+\t\t\t       const char *type, size_t type_len,\n+\t\t\t       struct object_id *oid, unsigned flags);\n \n /*\n  * Add an object file to the in-memory object store, without writing it\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422425","messageId":"patch-09.10-eaa1b8f44c-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 09/10] hash-object: show usage on invalid --type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:15Z","receivedAt":"2021-04-20T13:00:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the error displayed on \"hash-object -t bogus\" (without\n--literally) to show the usage_with_options(), like we do for the\nother usage errors.\n\nAs noted in a preceding commit it makes sense to pass the \"len\" down\nto the object.c code, so now that we're using\ntype_from_string_gently() let's do that.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/hash-object.c  | 44 ++++++++++++++++++++++++++++--------------\n t/t1007-hash-object.sh | 10 ++++++----\n 2 files changed, 35 insertions(+), 19 deletions(-)\n\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 4b337e0d25..705521bc7f 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -31,8 +31,9 @@ static int hash_literally(struct object_id *oid, int fd, const char *type, unsig\n \treturn ret;\n }\n \n-static void hash_fd(int fd, const char *type, size_t type_len,\n-\t\t    const char *path, unsigned flags, int literally)\n+static void hash_fd(int fd, enum object_type otype, const char *type,\n+\t\t    size_t type_len, const char *path, unsigned flags,\n+\t\t    int literally)\n {\n \tstruct stat st;\n \tstruct object_id oid;\n@@ -40,8 +41,8 @@ static void hash_fd(int fd, const char *type, size_t type_len,\n \tif (fstat(fd, &st) < 0 ||\n \t    (literally\n \t     ? hash_literally(&oid, fd, type, flags)\n-\t     : index_fd(the_repository->index, &oid, fd, &st,\n-\t\t\ttype_from_string(type), path, flags)))\n+\t     : index_fd(the_repository->index, &oid, fd, &st, otype, path,\n+\t\t\tflags)))\n \t\tdie((flags & HASH_WRITE_OBJECT)\n \t\t    ? \"Unable to add %s to database\"\n \t\t    : \"Unable to hash %s\", path);\n@@ -49,17 +50,19 @@ static void hash_fd(int fd, const char *type, size_t type_len,\n \tmaybe_flush_or_die(stdout, \"hash to stdout\");\n }\n \n-static void hash_object(const char *path, const char *type, size_t type_len,\n+static void hash_object(const char *path, enum object_type otype,\n+\t\t\tconst char *type, size_t type_len,\n \t\t\tconst char *vpath, unsigned flags, int literally)\n {\n \tint fd;\n \tfd = open(path, O_RDONLY);\n \tif (fd < 0)\n \t\tdie_errno(\"Cannot open '%s'\", path);\n-\thash_fd(fd, type, type_len, vpath, flags, literally);\n+\thash_fd(fd, otype, type, type_len, vpath, flags, literally);\n }\n \n-static void hash_stdin_paths(const char *type, size_t type_len, int no_filters,\n+static void hash_stdin_paths(enum object_type otype, const char *type,\n+\t\t\t     size_t type_len, int no_filters,\n \t\t\t     unsigned flags, int literally)\n {\n \tstruct strbuf buf = STRBUF_INIT;\n@@ -74,7 +77,7 @@ static void hash_stdin_paths(const char *type, size_t type_len, int no_filters,\n \t\t\tstrbuf_swap(&buf, &unquoted);\n \t\t}\n \t\tvpath = no_filters ? NULL : buf.buf;\n-\t\thash_object(buf.buf, type, type_len, vpath , flags, literally);\n+\t\thash_object(buf.buf, otype, type, type_len, vpath , flags, literally);\n \t}\n \tstrbuf_release(&buf);\n \tstrbuf_release(&unquoted);\n@@ -89,6 +92,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \t};\n \tconst char *type = blob_type;\n \tsize_t type_len;\n+\tenum object_type otype = OBJ_BAD;\n \tint hashstdin = 0;\n \tint stdin_paths = 0;\n \tint no_filters = 0;\n@@ -109,6 +113,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \t};\n \tint i;\n \tconst char *errstr = NULL;\n+\tint errstr_arg_type = 0;\n \n \targc = parse_options(argc, argv, prefix, hash_object_options,\n \t\t\t     hash_object_usage, 0);\n@@ -123,7 +128,12 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \n \tgit_config(git_default_config, NULL);\n \n-\tif (stdin_paths) {\n+\ttype_len = strlen(type);\n+\totype = type_from_string_gently(type, type_len);\n+\tif (otype < 0 && !literally) {\n+\t\terrstr = \"the object type \\\"%.*s\\\" is invalid, did you mean to use --literally?\";\n+\t\terrstr_arg_type = 1;\n+\t} else if (stdin_paths) {\n \t\tif (hashstdin)\n \t\t\terrstr = \"Can't use --stdin-paths with --stdin\";\n \t\telse if (argc)\n@@ -137,27 +147,31 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \t}\n \n \tif (errstr) {\n-\t\terror(\"%s\", errstr);\n+\t\tif (errstr_arg_type)\n+\t\t\terror(errstr, (int)type_len, type);\n+\t\telse\n+\t\t\terror(\"%s\", errstr);\n \t\tusage_with_options(hash_object_usage, hash_object_options);\n \t}\n \n-\ttype_len = strlen(type);\n \tif (hashstdin)\n-\t\thash_fd(0, type, type_len, vpath, flags, literally);\n+\t\thash_fd(0, otype, type, type_len, vpath, flags, literally);\n \n \tfor (i = 0 ; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n \t\tchar *to_free = NULL;\n+\t\tconst char *tmp;\n \n \t\tif (prefix)\n \t\t\targ = to_free = prefix_filename(prefix, arg);\n-\t\thash_object(arg, type, type_len, no_filters ? NULL : vpath ? vpath : arg,\n-\t\t\t    flags, literally);\n+\t\ttmp = no_filters ? NULL : vpath ? vpath : arg;\n+\t\thash_object(arg, otype, type, type_len, tmp, flags, literally);\n \t\tfree(to_free);\n \t}\n \n \tif (stdin_paths)\n-\t\thash_stdin_paths(type, type_len, no_filters, flags, literally);\n+\t\thash_stdin_paths(otype, type, type_len, no_filters, flags,\n+\t\t\t\t literally);\n \n \treturn 0;\n }\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex 74486f6f1a..cb1517bd90 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -230,17 +230,19 @@ test_expect_success 'corrupt tag' '\n '\n \n test_expect_success 'hash-object complains about bogus type name' '\n-\ttest_must_fail git hash-object -t bogus --stdin 2>actual </dev/null &&\n+\ttest_expect_code 129 git hash-object -t bogus --stdin 2>err </dev/null &&\n+\tgrep ^error err >actual &&\n \tcat >expect <<-\\EOF &&\n-\tfatal: invalid object type \"bogus\"\n+\terror: the object type \"bogus\" is invalid, did you mean to use --literally?\n \tEOF\n \ttest_cmp expect actual\n '\n \n test_expect_success 'hash-object complains about truncated type name' '\n-\ttest_must_fail git hash-object -t bl --stdin 2>actual </dev/null &&\n+\ttest_expect_code 129 git hash-object -t bl --stdin 2>err </dev/null &&\n+\tgrep ^error err >actual &&\n \tcat >expect <<-\\EOF &&\n-\tfatal: invalid object type \"bl\"\n+\terror: the object type \"bl\" is invalid, did you mean to use --literally?\n \tEOF\n \ttest_cmp expect actual\n '\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422426","messageId":"patch-08.10-7bf04edc74-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 08/10] hash-object: refactor nested else/if/if into else if/else if","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:14Z","receivedAt":"2021-04-20T13:00:44Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor code that was changed to this form in 4a3d85dcf67 (add\n--no-filters option to git hash-object, 2008-08-03), seemingly for no\ngood reason.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/hash-object.c | 10 ++++------\n 1 file changed, 4 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/hash-object.c b/builtin/hash-object.c\nindex 4d3b8c49d2..4b337e0d25 100644\n--- a/builtin/hash-object.c\n+++ b/builtin/hash-object.c\n@@ -130,12 +130,10 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)\n \t\t\terrstr = \"Can't specify files with --stdin-paths\";\n \t\telse if (vpath)\n \t\t\terrstr = \"Can't use --stdin-paths with --path\";\n-\t}\n-\telse {\n-\t\tif (hashstdin > 1)\n-\t\t\terrstr = \"Multiple --stdin arguments are not supported\";\n-\t\tif (vpath && no_filters)\n-\t\t\terrstr = \"Can't use --path with --no-filters\";\n+\t} else if (hashstdin > 1) {\n+\t\terrstr = \"Multiple --stdin arguments are not supported\";\n+\t} else if (vpath && no_filters) {\n+\t\terrstr = \"Can't use --path with --no-filters\";\n \t}\n \n \tif (errstr) {\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422427","messageId":"patch-10.10-cb0ea49279-20210420T125416Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com","subject":"[PATCH v2 10/10] object.c: move type_from_string() code to its last user","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:00:16Z","receivedAt":"2021-04-20T13:00:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"In commits leading up to this one various errors have been improved\nand bugs fixed by moving various callers to\ntype_from_string_gently(). Now that there's no caller left of\ntype_from_string() except cat-file.c, let's move this function over to\nit.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/cat-file.c | 4 +++-\n object.c           | 9 ---------\n object.h           | 1 -\n 3 files changed, 3 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 46fc7a32ba..20c60045f6 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -154,7 +154,9 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n \t\tbreak;\n \n \tcase 0:\n-\t\texp_type_id = type_from_string(exp_type);\n+\t\texp_type_id = type_from_string_gently(exp_type, strlen(exp_type));\n+\t\tif (exp_type_id < 0)\n+\t\t\tdie(_(\"invalid object type \\\"%s\\\"\"), exp_type);\n \t\tif (exp_type_id == OBJ_BLOB) {\n \t\t\tstruct object_id blob_oid;\n \t\t\tif (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {\ndiff --git a/object.c b/object.c\nindex 8f3ddfc8f4..3c962da6c9 100644\n--- a/object.c\n+++ b/object.c\n@@ -49,15 +49,6 @@ enum object_type type_from_string_gently(const char *str, size_t len)\n \treturn -1;\n }\n \n-enum object_type type_from_string(const char *str)\n-{\n-\tsize_t len = strlen(str);\n-\tenum object_type ret = type_from_string_gently(str, len);\n-\tif (ret < 0)\n-\t\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n-\treturn ret;\n-}\n-\n /*\n  * Return a numerical hash value between 0 and n-1 for the object with\n  * the specified sha1.  n must be a power of 2.  Please note that the\ndiff --git a/object.h b/object.h\nindex a4eca10d72..85e7491815 100644\n--- a/object.h\n+++ b/object.h\n@@ -94,7 +94,6 @@ struct object {\n \n const char *type_name(unsigned int type);\n enum object_type type_from_string_gently(const char *str, size_t len);\n-enum object_type type_from_string(const char *str);\n \n /*\n  * Return the current number of buckets in the object hashmap.\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422429","messageId":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com","subject":"[PATCH v2 0/8] object.c: add and use \"is expected\" utility function + object_as_type() use","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:52Z","receivedAt":"2021-04-20T13:37:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This relatively simple series builds on [1] and [2] to intorduce a\nutility function for the \"expected type X, got Y\" error messages. See\n[3] for the v1 of this series.\n\nThere was an embarrassing error in v1 where I left in some WIP\nassertion code, and we'd print a nonsensical error message in the\nlookup_commit_reference_gently() codepath.\n\nThat's now fixed gone, and there's a new test to assert the exact\noutput we get from a failure in\nlookup_commit_reference_gently(). Aside from not reading my own\npatches carefully enough before submission, I didn't catch that case\nbecause nothing tested for the output.\n\n1. https://lore.kernel.org/git/cover-00.10-0000000000-20210420T124428Z-avarab@gmail.com/\n2. https://lore.kernel.org/git/cover-00.10-0000000000-20210420T125415Z-avarab@gmail.com/\n3. https://lore.kernel.org/git/cover-0.7-0000000000-20210409T083436Z-avarab@gmail.com/\n\nÆvar Arnfjörð Bjarmason (8):\n  tree.c: fix misindentation in parse_tree_gently()\n  object.c: add a utility function for \"expected type X, got Y\"\n  object.c: add and use oid_is_type_or_die_msg() function\n  commit-graph: use obj->type, not object_as_type()\n  branch tests: assert lookup_commit_reference_gently() error\n  commit.c: don't use deref_tag() -> object_as_type()\n  object.c: normalize brace style in object_as_type()\n  object.c: remove \"quiet\" parameter from object_as_type()\n\n blob.c                     |  2 +-\n builtin/commit-graph.c     |  2 +-\n builtin/fsck.c             |  2 +-\n builtin/index-pack.c       |  9 +++----\n combine-diff.c             |  3 +--\n commit.c                   | 29 ++++++++++++++--------\n merge-recursive.c          |  5 +++-\n object.c                   | 51 +++++++++++++++++++++++++++++++-------\n object.h                   | 10 +++++++-\n refs.c                     |  2 +-\n t/helper/test-reach.c      |  2 +-\n t/t3201-branch-contains.sh |  8 +++++-\n tag.c                      |  2 +-\n tree.c                     | 15 +++++------\n 14 files changed, 98 insertions(+), 44 deletions(-)\n\nRange-diff against v1:\n1:  4bf9a4f7a1 = 1:  c39b235035 tree.c: fix misindentation in parse_tree_gently()\n2:  0be843e838 = 2:  1b472fcd85 object.c: add a utility function for \"expected type X, got Y\"\n3:  fb2e4feb3d = 3:  22e7d9a3db object.c: add and use oid_is_type_or_die_msg() function\n4:  995135c814 = 4:  8e43d44911 commit-graph: use obj->type, not object_as_type()\n-:  ---------- > 5:  8982c42127 branch tests: assert lookup_commit_reference_gently() error\n5:  754d5ae267 ! 6:  f337a5442d commit.c: don't use deref_tag() -> object_as_type()\n    @@ Commit message\n         of OBJ_{COMMIT,TREE,BLOB,TAG} here, not the bare-bones initialization\n         object_as_type() might be called on to do.\n     \n    +    Even though we can read deref_tag() and see that it won't return\n    +    OBJ_NONE and friends, let's add a BUG() assertion here to help future\n    +    maintenance.\n    +\n         Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n     \n      ## commit.c ##\n    @@ commit.c: const char *commit_type = \"commit\";\n      \t\treturn NULL;\n     -\treturn object_as_type(obj, OBJ_COMMIT, quiet);\n     +\n    ++\tif (obj->type <= 0)\n    ++\t\tBUG(\"should have initialized obj->type = OBJ_{COMMIT,TREE,BLOB,TAG} from deref_tag()\");\n     +\tif (obj->type != OBJ_COMMIT) {\n    -+\t\tenum object_type want = OBJ_COMMIT;\n    -+\t\tif (!quiet)\n    -+\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &want);\n    ++\t\tif (!quiet) {\n    ++\t\t\tenum object_type have = obj->type;\n    ++\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &have);\n    ++\t\t}\n     +\t\treturn NULL;\n     +\t}\n     +\treturn (struct commit *)obj;\n6:  e414cfe40c = 7:  893b178573 object.c: normalize brace style in object_as_type()\n7:  64360ac260 ! 8:  a47d23f1b1 object.c: remove \"quiet\" parameter from object_as_type()\n    @@ blob.c\n     @@ blob.c: struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n      \tstruct object *obj = lookup_object(r, oid);\n      \tif (!obj)\n    - \t\treturn create_object(r, oid, alloc_blob_node(r));\n    + \t\treturn create_blob(r, oid);\n     -\treturn object_as_type(obj, OBJ_BLOB, 0);\n     +\treturn object_as_type(obj, OBJ_BLOB);\n      }\n    - \n    - int parse_blob_buffer(struct blob *item)\n     \n      ## builtin/fsck.c ##\n     @@ builtin/fsck.c: static void mark_unreachable_referents(const struct object_id *oid)\n    @@ builtin/fsck.c: static void mark_unreachable_referents(const struct object_id *o\n      \toptions.walk = mark_used;\n     \n      ## commit.c ##\n    -@@ commit.c: struct commit *lookup_commit_reference_gently(struct repository *r,\n    - \t\treturn NULL;\n    - \n    - \tif (obj->type != OBJ_COMMIT) {\n    --\t\tenum object_type want = OBJ_COMMIT;\n    -+\t\tif (obj->type <= 0)\n    -+\t\t\tBUG(\"noes\");\n    - \t\tif (!quiet)\n    --\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &want);\n    -+\t\t\tfprintf(stderr, \"noes ohes\");/*\n    -+\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &obj->type);*/\n    - \t\treturn NULL;\n    - \t}\n    - \treturn (struct commit *)obj;\n     @@ commit.c: struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n      \tstruct object *obj = lookup_object(r, oid);\n      \tif (!obj)\n    - \t\treturn create_object(r, oid, alloc_commit_node(r));\n    + \t\treturn create_commit(r, oid);\n     -\treturn object_as_type(obj, OBJ_COMMIT, 0);\n     +\treturn object_as_type(obj, OBJ_COMMIT);\n      }\n    @@ tag.c\n     @@ tag.c: struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n      \tstruct object *obj = lookup_object(r, oid);\n      \tif (!obj)\n    - \t\treturn create_object(r, oid, alloc_tag_node(r));\n    + \t\treturn create_tag(r, oid);\n     -\treturn object_as_type(obj, OBJ_TAG, 0);\n     +\treturn object_as_type(obj, OBJ_TAG);\n      }\n    @@ tree.c\n     @@ tree.c: struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n      \tstruct object *obj = lookup_object(r, oid);\n      \tif (!obj)\n    - \t\treturn create_object(r, oid, alloc_tree_node(r));\n    + \t\treturn create_tree(r, oid);\n     -\treturn object_as_type(obj, OBJ_TREE, 0);\n     +\treturn object_as_type(obj, OBJ_TREE);\n      }\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422430","messageId":"patch-1.8-c39b235035-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 1/8] tree.c: fix misindentation in parse_tree_gently()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:53Z","receivedAt":"2021-04-20T13:37:10Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The variables declared in parse_tree_gently() had a single space after\nthe TAB. This dates back to their introduction in bd2c39f58f9 ([PATCH]\ndon't load and decompress objects twice with parse_object(),\n2005-05-06). Let's fix them to follow the style of the rest of the\nfile.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n tree.c | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/tree.c b/tree.c\nindex 00958c581e..e9d2bd7ffd 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -128,9 +128,9 @@ int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n \n int parse_tree_gently(struct tree *item, int quiet_on_missing)\n {\n-\t enum object_type type;\n-\t void *buffer;\n-\t unsigned long size;\n+\tenum object_type type;\n+\tvoid *buffer;\n+\tunsigned long size;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422431","messageId":"patch-2.8-1b472fcd85-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 2/8] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:54Z","receivedAt":"2021-04-20T13:37:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Refactor various \"Object X is not Y\" error messages so that they use\nthe same message as the long-standing object_as_type() error\nmessage. Now we'll consistently report e.g. that we got a commit when\nwe expected a tag, not just that the object is not a tag.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/index-pack.c |  9 +++------\n combine-diff.c       |  3 +--\n commit.c             | 10 ++++------\n merge-recursive.c    |  1 +\n object.c             | 25 ++++++++++++++++++++++++-\n object.h             |  5 +++++\n tree.c               |  7 ++++---\n 7 files changed, 42 insertions(+), 18 deletions(-)\n\ndiff --git a/builtin/index-pack.c b/builtin/index-pack.c\nindex c0e3768c32..eabd9d4677 100644\n--- a/builtin/index-pack.c\n+++ b/builtin/index-pack.c\n@@ -218,8 +218,8 @@ static int mark_link(struct object *obj, enum object_type type,\n \tif (!obj)\n \t\treturn -1;\n \n-\tif (type != OBJ_ANY && obj->type != type)\n-\t\tdie(_(\"object type mismatch at %s\"), oid_to_hex(&obj->oid));\n+\tif (type != OBJ_ANY)\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \n \tobj->flags |= FLAG_LINK;\n \treturn 0;\n@@ -241,10 +241,7 @@ static unsigned check_object(struct object *obj)\n \t\tif (type <= 0)\n \t\t\tdie(_(\"did not receive expected object %s\"),\n \t\t\t      oid_to_hex(&obj->oid));\n-\t\tif (type != obj->type)\n-\t\t\tdie(_(\"object %s: expected type %s, found %s\"),\n-\t\t\t    oid_to_hex(&obj->oid),\n-\t\t\t    type_name(obj->type), type_name(type));\n+\t\toid_is_type_or_die(&obj->oid, obj->type, &type);\n \t\tobj->flags |= FLAG_CHECKED;\n \t\treturn 1;\n \t}\ndiff --git a/combine-diff.c b/combine-diff.c\nindex 06635f91bc..aa767dbb8e 100644\n--- a/combine-diff.c\n+++ b/combine-diff.c\n@@ -333,8 +333,7 @@ static char *grab_blob(struct repository *r,\n \t\tfree_filespec(df);\n \t} else {\n \t\tblob = read_object_file(oid, &type, size);\n-\t\tif (type != OBJ_BLOB)\n-\t\t\tdie(\"object '%s' is not a blob!\", oid_to_hex(oid));\n+\t\toid_is_type_or_die(oid, OBJ_BLOB, &type);\n \t}\n \treturn blob;\n }\ndiff --git a/commit.c b/commit.c\nindex 3580c62b92..3d7f1fba0c 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -304,9 +304,7 @@ const void *repo_get_commit_buffer(struct repository *r,\n \t\tif (!ret)\n \t\t\tdie(\"cannot read commit object %s\",\n \t\t\t    oid_to_hex(&commit->object.oid));\n-\t\tif (type != OBJ_COMMIT)\n-\t\t\tdie(\"expected commit for %s, got %s\",\n-\t\t\t    oid_to_hex(&commit->object.oid), type_name(type));\n+\t\toid_is_type_or_die(&commit->object.oid, OBJ_COMMIT, &type);\n \t\tif (sizep)\n \t\t\t*sizep = size;\n \t}\n@@ -494,10 +492,10 @@ int repo_parse_commit_internal(struct repository *r,\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_COMMIT) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_COMMIT, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a commit\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \n \tret = parse_commit_buffer(r, item, buffer, size, 0);\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex 7618303f7b..b952106203 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2999,6 +2999,7 @@ static int read_oid_strbuf(struct merge_options *opt,\n \tif (!buf)\n \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n \tif (type != OBJ_BLOB) {\n+\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n \t\tfree(buf);\n \t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n \t}\ndiff --git a/object.c b/object.c\nindex 3c962da6c9..9e06c0ee92 100644\n--- a/object.c\n+++ b/object.c\n@@ -153,6 +153,29 @@ void *create_object(struct repository *r, const struct object_id *oid, void *o)\n \treturn obj;\n }\n \n+static const char *object_type_mismatch_msg = N_(\"object %s is a %s, not a %s\");\n+\n+void oid_is_type_or_die(const struct object_id *oid,\n+\t\t\tenum object_type want,\n+\t\t\tenum object_type *type)\n+{\n+\tif (want == *type)\n+\t\treturn;\n+\tdie(_(object_type_mismatch_msg), oid_to_hex(oid),\n+\t    type_name(*type), type_name(want));\n+}\n+\n+int oid_is_type_or_error(const struct object_id *oid,\n+\t\t\t enum object_type want,\n+\t\t\t enum object_type *type)\n+{\n+\tif (want == *type)\n+\t\treturn 0;\n+\treturn error(_(object_type_mismatch_msg),\n+\t\t     oid_to_hex(oid), type_name(*type),\n+\t\t     type_name(want));\n+}\n+\n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n \tif (obj->type == type)\n@@ -166,7 +189,7 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n \t}\n \telse {\n \t\tif (!quiet)\n-\t\t\terror(_(\"object %s is a %s, not a %s\"),\n+\t\t\terror(_(object_type_mismatch_msg),\n \t\t\t      oid_to_hex(&obj->oid),\n \t\t\t      type_name(obj->type), type_name(type));\n \t\treturn NULL;\ndiff --git a/object.h b/object.h\nindex 85e7491815..f8609a8518 100644\n--- a/object.h\n+++ b/object.h\n@@ -123,6 +123,11 @@ void *create_object(struct repository *r, const struct object_id *oid, void *obj\n \n void *object_as_type(struct object *obj, enum object_type type, int quiet);\n \n+void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n+\t\t\tenum object_type *type);\n+int oid_is_type_or_error(const struct object_id *oid, enum object_type want,\n+\t\t\t enum object_type *type);\n+\n /*\n  * Returns the object, having parsed it to find out what it is.\n  *\ndiff --git a/tree.c b/tree.c\nindex e9d2bd7ffd..f1c6e8f647 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -131,6 +131,7 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \tenum object_type type;\n \tvoid *buffer;\n \tunsigned long size;\n+\tint ret;\n \n \tif (item->object.parsed)\n \t\treturn 0;\n@@ -139,10 +140,10 @@ int parse_tree_gently(struct tree *item, int quiet_on_missing)\n \t\treturn quiet_on_missing ? -1 :\n \t\t\terror(\"Could not read %s\",\n \t\t\t     oid_to_hex(&item->object.oid));\n-\tif (type != OBJ_TREE) {\n+\tret = oid_is_type_or_error(&item->object.oid, OBJ_TREE, &type);\n+\tif (ret) {\n \t\tfree(buffer);\n-\t\treturn error(\"Object %s not a tree\",\n-\t\t\t     oid_to_hex(&item->object.oid));\n+\t\treturn ret;\n \t}\n \treturn parse_tree_buffer(item, buffer, size);\n }\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422432","messageId":"patch-3.8-22e7d9a3db-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 3/8] object.c: add and use oid_is_type_or_die_msg() function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:55Z","receivedAt":"2021-04-20T13:37:12Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add a oid_is_type_or_die_msg() function to go with the \"error\" and\n\"die\" forms for emitting \"expected type X, got Y\" messages. This is\nuseful for callers that want the message itself as a char *.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n merge-recursive.c |  6 ++++--\n object.c          | 12 ++++++++++++\n object.h          |  3 +++\n 3 files changed, 19 insertions(+), 2 deletions(-)\n\ndiff --git a/merge-recursive.c b/merge-recursive.c\nindex b952106203..c74239544f 100644\n--- a/merge-recursive.c\n+++ b/merge-recursive.c\n@@ -2999,9 +2999,11 @@ static int read_oid_strbuf(struct merge_options *opt,\n \tif (!buf)\n \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n \tif (type != OBJ_BLOB) {\n-\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n+\t\tchar *msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n+\t\tint ret = err(opt, msg);\n \t\tfree(buf);\n-\t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n+\t\tfree(msg);\n+\t\treturn ret;\n \t}\n \tstrbuf_attach(dst, buf, size, size + 1);\n \treturn 0;\ndiff --git a/object.c b/object.c\nindex 9e06c0ee92..0f07f976fb 100644\n--- a/object.c\n+++ b/object.c\n@@ -176,6 +176,18 @@ int oid_is_type_or_error(const struct object_id *oid,\n \t\t     type_name(want));\n }\n \n+char* oid_is_type_or_die_msg(const struct object_id *oid,\n+\t\t\t\t   enum object_type want,\n+\t\t\t\t   enum object_type *type)\n+{\n+\tstruct strbuf sb = STRBUF_INIT;\n+\tif (want == *type)\n+\t\tBUG(\"call this just to get the message!\");\n+\tstrbuf_addf(&sb, _(object_type_mismatch_msg), oid_to_hex(oid),\n+\t\t    type_name(*type), type_name(want));\n+\treturn strbuf_detach(&sb, NULL);\n+}\n+\n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n \tif (obj->type == type)\ndiff --git a/object.h b/object.h\nindex f8609a8518..7ae6407598 100644\n--- a/object.h\n+++ b/object.h\n@@ -127,6 +127,9 @@ void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n \t\t\tenum object_type *type);\n int oid_is_type_or_error(const struct object_id *oid, enum object_type want,\n \t\t\t enum object_type *type);\n+char* oid_is_type_or_die_msg(const struct object_id *oid,\n+\t\t\t     enum object_type want,\n+\t\t\t     enum object_type *type);\n \n /*\n  * Returns the object, having parsed it to find out what it is.\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422433","messageId":"patch-4.8-8e43d44911-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 4/8] commit-graph: use obj->type, not object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:56Z","receivedAt":"2021-04-20T13:37:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a check of a deref_tag() return value to just use obj->type\ninstead of object_as_type(). The object_as_type() function is for\nlow-level use by fsck, {commit,tree,blob,tag}.c and the like, here we\ncan just assume the object is fully initialized.\n\nAs can be seen in plenty of existing uses in our codebase the return\nvalue of deref_tag() won't be an obj->type == OBJ_NONE or\n!obj->parsed. Fixes code added in 2f00c355cb7 (commit-graph: drop\nCOMMIT_GRAPH_WRITE_CHECK_OIDS flag, 2020-05-13).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n builtin/commit-graph.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex cd86315221..347d65abc8 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -158,7 +158,7 @@ static int read_one_commit(struct oidset *commits, struct progress *progress,\n \t\t\t   NULL, 0);\n \tif (!result)\n \t\treturn error(_(\"invalid object: %s\"), hash);\n-\telse if (object_as_type(result, OBJ_COMMIT, 1))\n+\telse if (result->type == OBJ_COMMIT)\n \t\toidset_insert(commits, &result->oid);\n \n \tdisplay_progress(progress, oidset_size(commits));\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422434","messageId":"patch-5.8-8982c42127-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 5/8] branch tests: assert lookup_commit_reference_gently() error","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:57Z","receivedAt":"2021-04-20T13:37:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Assert the exact error returned by lookup_commit_reference_gently()\nand \"branch' itself in the non-quiet mode invoked by branch.c (via\nparse_opt_commits()). This will be used to assert a subsequent change\nthat changes the lookup_commit_reference_gently() code.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n t/t3201-branch-contains.sh | 8 +++++++-\n 1 file changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/t/t3201-branch-contains.sh b/t/t3201-branch-contains.sh\nindex 349a810cee..5bd4b05b6e 100755\n--- a/t/t3201-branch-contains.sh\n+++ b/t/t3201-branch-contains.sh\n@@ -166,7 +166,13 @@ test_expect_success 'implicit --list conflicts with modification options' '\n '\n \n test_expect_success 'Assert that --contains only works on commits, not trees & blobs' '\n-\ttest_must_fail git branch --contains main^{tree} &&\n+\ttree=$(git rev-parse main^{tree}) &&\n+\ttest_must_fail git branch --contains main^{tree} 2>actual &&\n+\tcat >expect <<-EOF &&\n+\terror: object $tree is a tree, not a commit\n+\terror: no such commit main^{tree}\n+\tEOF\n+\ttest_cmp expect actual &&\n \tblob=$(git hash-object -w --stdin <<-\\EOF\n \tSome blob\n \tEOF\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422435","messageId":"patch-6.8-f337a5442d-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 6/8] commit.c: don't use deref_tag() -> object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:58Z","receivedAt":"2021-04-20T13:37:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change a use of the object_as_type() function introduced in\n8ff226a9d5e (add object_as_type helper for casting objects,\n2014-07-13) to instead assume that we're not dealing with OBJ_NONE (or\nOBJ_BAD) from deref_tag().\n\nThis makes this code easier to read, as the reader isn't wondering why\nthe function would need to deal with that. We're simply doing a check\nof OBJ_{COMMIT,TREE,BLOB,TAG} here, not the bare-bones initialization\nobject_as_type() might be called on to do.\n\nEven though we can read deref_tag() and see that it won't return\nOBJ_NONE and friends, let's add a BUG() assertion here to help future\nmaintenance.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n commit.c | 17 +++++++++++++----\n 1 file changed, 13 insertions(+), 4 deletions(-)\n\ndiff --git a/commit.c b/commit.c\nindex 3d7f1fba0c..c3bc6cbec4 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -31,13 +31,22 @@ const char *commit_type = \"commit\";\n struct commit *lookup_commit_reference_gently(struct repository *r,\n \t\tconst struct object_id *oid, int quiet)\n {\n-\tstruct object *obj = deref_tag(r,\n-\t\t\t\t       parse_object(r, oid),\n-\t\t\t\t       NULL, 0);\n+\tstruct object *tmp = parse_object(r, oid);\n+\tstruct object *obj = deref_tag(r, tmp, NULL, 0);\n \n \tif (!obj)\n \t\treturn NULL;\n-\treturn object_as_type(obj, OBJ_COMMIT, quiet);\n+\n+\tif (obj->type <= 0)\n+\t\tBUG(\"should have initialized obj->type = OBJ_{COMMIT,TREE,BLOB,TAG} from deref_tag()\");\n+\tif (obj->type != OBJ_COMMIT) {\n+\t\tif (!quiet) {\n+\t\t\tenum object_type have = obj->type;\n+\t\t\toid_is_type_or_error(oid, OBJ_COMMIT, &have);\n+\t\t}\n+\t\treturn NULL;\n+\t}\n+\treturn (struct commit *)obj;\n }\n \n struct commit *lookup_commit_reference(struct repository *r, const struct object_id *oid)\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422436","messageId":"patch-7.8-893b178573-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 7/8] object.c: normalize brace style in object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:36:59Z","receivedAt":"2021-04-20T13:37:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Normalize the brace style in this function introduced in\n8ff226a9d5e (add object_as_type helper for casting objects,\n2014-07-13) to be in line with the coding style of the project.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n object.c | 7 +++----\n 1 file changed, 3 insertions(+), 4 deletions(-)\n\ndiff --git a/object.c b/object.c\nindex 0f07f976fb..f694db7e87 100644\n--- a/object.c\n+++ b/object.c\n@@ -190,16 +190,15 @@ char* oid_is_type_or_die_msg(const struct object_id *oid,\n \n void *object_as_type(struct object *obj, enum object_type type, int quiet)\n {\n-\tif (obj->type == type)\n+\tif (obj->type == type) {\n \t\treturn obj;\n-\telse if (obj->type == OBJ_NONE) {\n+\t} else if (obj->type == OBJ_NONE) {\n \t\tif (type == OBJ_COMMIT)\n \t\t\tinit_commit_node((struct commit *) obj);\n \t\telse\n \t\t\tobj->type = type;\n \t\treturn obj;\n-\t}\n-\telse {\n+\t} else {\n \t\tif (!quiet)\n \t\t\terror(_(object_type_mismatch_msg),\n \t\t\t      oid_to_hex(&obj->oid),\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422437","messageId":"patch-8.8-a47d23f1b1-20210420T133218Z-avarab@gmail.com","threadId":"1003","inReplyTo":"cover-0.8-0000000000-20210420T133218Z-avarab@gmail.com","subject":"[PATCH v2 8/8] object.c: remove \"quiet\" parameter from object_as_type()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-20T13:37:00Z","receivedAt":"2021-04-20T13:37:19Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Remove the now-unused \"quiet\" parameter from object_as_type(). As\nshown in preceding commits the previous users of this parameter were\nbetter off with higher-level APIs.\n\nThe \"quiet\" parameter was originally introduced when the\nobject_as_type() function was added in 8ff226a9d5e (add object_as_type\nhelper for casting objects,.  2014-07-13), but the commit.c use-case\nfor it is now gone.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n blob.c                | 2 +-\n builtin/fsck.c        | 2 +-\n commit.c              | 2 +-\n object.c              | 9 ++++-----\n object.h              | 2 +-\n refs.c                | 2 +-\n t/helper/test-reach.c | 2 +-\n tag.c                 | 2 +-\n tree.c                | 2 +-\n 9 files changed, 12 insertions(+), 13 deletions(-)\n\ndiff --git a/blob.c b/blob.c\nindex 1308299eab..f8d8f0b84e 100644\n--- a/blob.c\n+++ b/blob.c\n@@ -15,5 +15,5 @@ struct blob *lookup_blob(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_blob(r, oid);\n-\treturn object_as_type(obj, OBJ_BLOB, 0);\n+\treturn object_as_type(obj, OBJ_BLOB);\n }\ndiff --git a/builtin/fsck.c b/builtin/fsck.c\nindex 70ff95837a..5d534cf218 100644\n--- a/builtin/fsck.c\n+++ b/builtin/fsck.c\n@@ -221,7 +221,7 @@ static void mark_unreachable_referents(const struct object_id *oid)\n \t\tenum object_type type = oid_object_info(the_repository,\n \t\t\t\t\t\t\t&obj->oid, NULL);\n \t\tif (type > 0)\n-\t\t\tobject_as_type(obj, type, 0);\n+\t\t\tobject_as_type(obj, type);\n \t}\n \n \toptions.walk = mark_used;\ndiff --git a/commit.c b/commit.c\nindex c3bc6cbec4..918c7c7a66 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -76,7 +76,7 @@ struct commit *lookup_commit(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_commit(r, oid);\n-\treturn object_as_type(obj, OBJ_COMMIT, 0);\n+\treturn object_as_type(obj, OBJ_COMMIT);\n }\n \n struct commit *lookup_commit_reference_by_name(const char *name)\ndiff --git a/object.c b/object.c\nindex f694db7e87..9f6f36707b 100644\n--- a/object.c\n+++ b/object.c\n@@ -188,7 +188,7 @@ char* oid_is_type_or_die_msg(const struct object_id *oid,\n \treturn strbuf_detach(&sb, NULL);\n }\n \n-void *object_as_type(struct object *obj, enum object_type type, int quiet)\n+void *object_as_type(struct object *obj, enum object_type type)\n {\n \tif (obj->type == type) {\n \t\treturn obj;\n@@ -199,10 +199,9 @@ void *object_as_type(struct object *obj, enum object_type type, int quiet)\n \t\t\tobj->type = type;\n \t\treturn obj;\n \t} else {\n-\t\tif (!quiet)\n-\t\t\terror(_(object_type_mismatch_msg),\n-\t\t\t      oid_to_hex(&obj->oid),\n-\t\t\t      type_name(obj->type), type_name(type));\n+\t\terror(_(object_type_mismatch_msg),\n+\t\t      oid_to_hex(&obj->oid),\n+\t\t      type_name(obj->type), type_name(type));\n \t\treturn NULL;\n \t}\n }\ndiff --git a/object.h b/object.h\nindex 7ae6407598..bb65a6cd5a 100644\n--- a/object.h\n+++ b/object.h\n@@ -121,7 +121,7 @@ struct object *lookup_object(struct repository *r, const struct object_id *oid);\n \n void *create_object(struct repository *r, const struct object_id *oid, void *obj);\n \n-void *object_as_type(struct object *obj, enum object_type type, int quiet);\n+void *object_as_type(struct object *obj, enum object_type type);\n \n void oid_is_type_or_die(const struct object_id *oid, enum object_type want,\n \t\t\tenum object_type *type);\ndiff --git a/refs.c b/refs.c\nindex 261fd82beb..7f4ca3441c 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -341,7 +341,7 @@ enum peel_status peel_object(const struct object_id *name, struct object_id *oid\n \n \tif (o->type == OBJ_NONE) {\n \t\tint type = oid_object_info(the_repository, name, NULL);\n-\t\tif (type < 0 || !object_as_type(o, type, 0))\n+\t\tif (type < 0 || !object_as_type(o, type))\n \t\t\treturn PEEL_INVALID;\n \t}\n \ndiff --git a/t/helper/test-reach.c b/t/helper/test-reach.c\nindex cda804ed79..c9fd74b21f 100644\n--- a/t/helper/test-reach.c\n+++ b/t/helper/test-reach.c\n@@ -67,7 +67,7 @@ int cmd__reach(int ac, const char **av)\n \t\t\tdie(\"failed to load commit for input %s resulting in oid %s\\n\",\n \t\t\t    buf.buf, oid_to_hex(&oid));\n \n-\t\tc = object_as_type(peeled, OBJ_COMMIT, 0);\n+\t\tc = object_as_type(peeled, OBJ_COMMIT);\n \n \t\tif (!c)\n \t\t\tdie(\"failed to load commit for input %s resulting in oid %s\\n\",\ndiff --git a/tag.c b/tag.c\nindex 1bd81bf1d1..25d79c3db3 100644\n--- a/tag.c\n+++ b/tag.c\n@@ -109,7 +109,7 @@ struct tag *lookup_tag(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_tag(r, oid);\n-\treturn object_as_type(obj, OBJ_TAG, 0);\n+\treturn object_as_type(obj, OBJ_TAG);\n }\n \n static timestamp_t parse_tag_date(const char *buf, const char *tail)\ndiff --git a/tree.c b/tree.c\nindex f1c6e8f647..fd3ad18051 100644\n--- a/tree.c\n+++ b/tree.c\n@@ -112,7 +112,7 @@ struct tree *lookup_tree(struct repository *r, const struct object_id *oid)\n \tstruct object *obj = lookup_object(r, oid);\n \tif (!obj)\n \t\treturn create_tree(r, oid);\n-\treturn object_as_type(obj, OBJ_TREE, 0);\n+\treturn object_as_type(obj, OBJ_TREE);\n }\n \n int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)\n-- \n2.31.1.723.ga5d7868e4a\n\n"},{"id":"422634","messageId":"20210421220300.1022458-1-jonathantanmy@google.com","threadId":"1003","inReplyTo":"patch-2.8-1b472fcd85-20210420T133218Z-avarab@gmail.com","subject":"Re: [PATCH v2 2/8] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2021-04-21T22:02:59Z","receivedAt":"2021-04-21T22:04:33Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"> diff --git a/merge-recursive.c b/merge-recursive.c\n> index 7618303f7b..b952106203 100644\n> --- a/merge-recursive.c\n> +++ b/merge-recursive.c\n> @@ -2999,6 +2999,7 @@ static int read_oid_strbuf(struct merge_options *opt,\n>  \tif (!buf)\n>  \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n>  \tif (type != OBJ_BLOB) {\n> +\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n>  \t\tfree(buf);\n>  \t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n>  \t}\n\nStray extra line.\n\n> +void oid_is_type_or_die(const struct object_id *oid,\n> +\t\t\tenum object_type want,\n> +\t\t\tenum object_type *type)\n> +{\n\nThanks - this looks like a good simplification.\n\nWhy is type a pointer? Maybe it's to better distinguish the values at\nthe call site (one pointer, one not), but this solution is confusing\ntoo.\n\n> +int oid_is_type_or_error(const struct object_id *oid,\n> +\t\t\t enum object_type want,\n> +\t\t\t enum object_type *type)\n> +{\n\nSame comment.\n"},{"id":"422636","messageId":"20210421220728.1023248-1-jonathantanmy@google.com","threadId":"1003","inReplyTo":"patch-3.8-22e7d9a3db-20210420T133218Z-avarab@gmail.com","subject":"Re: [PATCH v2 3/8] object.c: add and use oid_is_type_or_die_msg() function","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2021-04-21T22:07:28Z","receivedAt":"2021-04-21T22:07:37Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"> +char* oid_is_type_or_die_msg(const struct object_id *oid,\n> +\t\t\t\t   enum object_type want,\n> +\t\t\t\t   enum object_type *type)\n> +{\n> +\tstruct strbuf sb = STRBUF_INIT;\n> +\tif (want == *type)\n> +\t\tBUG(\"call this just to get the message!\");\n> +\tstrbuf_addf(&sb, _(object_type_mismatch_msg), oid_to_hex(oid),\n> +\t\t    type_name(*type), type_name(want));\n> +\treturn strbuf_detach(&sb, NULL);\n> +}\n\nIt would be more convenient for the caller if this function also checks\nwant vs type and returns NULL if they match. That would also be more\nconsistent with the other functions, and the caller wouldn't need to\nremember that this function only works if want and type are different.\n"},{"id":"422637","messageId":"20210421222642.1025049-1-jonathantanmy@google.com","threadId":"1003","inReplyTo":"patch-6.8-f337a5442d-20210420T133218Z-avarab@gmail.com","subject":"Re: [PATCH v2 6/8] commit.c: don't use deref_tag() -> object_as_type()","fromName":"Jonathan Tan","fromEmail":"jonathantanmy@google.com","sentAt":"2021-04-21T22:26:42Z","receivedAt":"2021-04-21T22:26:46Z","isPatch":true,"sender":{"key":"jonathantanmy@fastmail.com","avatar":null},"body":"> Change a use of the object_as_type() function introduced in\n> 8ff226a9d5e (add object_as_type helper for casting objects,\n> 2014-07-13) to instead assume that we're not dealing with OBJ_NONE (or\n> OBJ_BAD) from deref_tag().\n> \n> This makes this code easier to read, as the reader isn't wondering why\n> the function would need to deal with that. We're simply doing a check\n> of OBJ_{COMMIT,TREE,BLOB,TAG} here, not the bare-bones initialization\n> object_as_type() might be called on to do.\n\nI think the benefit of using object_as_type() here (functionality that\nchecks the object type, with optional \"quiet\" behavior) outweighs the\ndrawback (additional functionality that we don't need). If we're worried\nthat the reader would wonder about the OBJ_NONE case, we can include the\nBUG check as you did.\n\n> Even though we can read deref_tag() and see that it won't return\n> OBJ_NONE and friends, let's add a BUG() assertion here to help future\n> maintenance.\n\nThis is reasonable.\n\n> diff --git a/commit.c b/commit.c\n> index 3d7f1fba0c..c3bc6cbec4 100644\n> --- a/commit.c\n> +++ b/commit.c\n> @@ -31,13 +31,22 @@ const char *commit_type = \"commit\";\n>  struct commit *lookup_commit_reference_gently(struct repository *r,\n>  \t\tconst struct object_id *oid, int quiet)\n>  {\n> -\tstruct object *obj = deref_tag(r,\n> -\t\t\t\t       parse_object(r, oid),\n> -\t\t\t\t       NULL, 0);\n> +\tstruct object *tmp = parse_object(r, oid);\n> +\tstruct object *obj = deref_tag(r, tmp, NULL, 0);\n\nThis change isn't unnecessary, I think. \"tmp\" isn't used anywhere else.\n"},{"id":"422642","messageId":"YIC1IcpKCXh3qoun@google.com","threadId":"1003","inReplyTo":"patch-3.8-22e7d9a3db-20210420T133218Z-avarab@gmail.com","subject":"Re: [PATCH v2 3/8] object.c: add and use oid_is_type_or_die_msg() function","fromName":"Josh Steadmon","fromEmail":"steadmon@google.com","sentAt":"2021-04-21T23:28:33Z","receivedAt":"2021-04-21T23:28:45Z","isPatch":true,"sender":{"key":"steadmon@google.com","avatar":"https://avatars.githubusercontent.com/u/2654920?v=4"},"body":"On 2021.04.20 15:36, Ævar Arnfjörð Bjarmason wrote:\n> diff --git a/object.c b/object.c\n> index 9e06c0ee92..0f07f976fb 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -176,6 +176,18 @@ int oid_is_type_or_error(const struct object_id *oid,\n>  \t\t     type_name(want));\n>  }\n>  \n> +char* oid_is_type_or_die_msg(const struct object_id *oid,\n\nIt's kind of a nitpick, but I found the function name to be confusing.\nIt sounds like you're going to die with a custom message. Maybe\nsomething like \"get_oid_type_mismatch_msg()\" would be more\nstraightforward.\n"},{"id":"422667","messageId":"877dku3l53.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"20210421220300.1022458-1-jonathantanmy@google.com","subject":"Re: [PATCH v2 2/8] object.c: add a utility function for \"expected type X, got Y\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-22T06:10:00Z","receivedAt":"2021-04-22T06:10:05Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Apr 22 2021, Jonathan Tan wrote:\n\n>> diff --git a/merge-recursive.c b/merge-recursive.c\n>> index 7618303f7b..b952106203 100644\n>> --- a/merge-recursive.c\n>> +++ b/merge-recursive.c\n>> @@ -2999,6 +2999,7 @@ static int read_oid_strbuf(struct merge_options *opt,\n>>  \tif (!buf)\n>>  \t\treturn err(opt, _(\"cannot read object %s\"), oid_to_hex(oid));\n>>  \tif (type != OBJ_BLOB) {\n>> +\t\tconst char* msg = oid_is_type_or_die_msg(oid, OBJ_BLOB, &type);\n>>  \t\tfree(buf);\n>>  \t\treturn err(opt, _(\"object %s is not a blob\"), oid_to_hex(oid));\n>>  \t}\n>\n> Stray extra line.\n>\n>> +void oid_is_type_or_die(const struct object_id *oid,\n>> +\t\t\tenum object_type want,\n>> +\t\t\tenum object_type *type)\n>> +{\n>\n> Thanks - this looks like a good simplification.\n>\n> Why is type a pointer? Maybe it's to better distinguish the values at\n> the call site (one pointer, one not), but this solution is confusing\n> too.\n\nYeah I came up with it because of that, so you wouldn't confuse the\nOBJ_COMMIT with (presumably) a variable with the same.\n\nBut in some other cases I end up having to do:\n\n    enum object_type type = OBJ_COMMIT;\n\nAnd then pass that &type in, do you think it's worth it? Maybe I should\njust change it...\n\n>> +int oid_is_type_or_error(const struct object_id *oid,\n>> +\t\t\t enum object_type want,\n>> +\t\t\t enum object_type *type)\n>> +{\n>\n> Same comment.\n\n"},{"id":"422698","messageId":"6081bbec7760c_11019208f5@natae.notmuch","threadId":"1003","inReplyTo":"xmqq8s67m8zi.fsf@gitster.g","subject":"Re: [PATCH v2 01/10] object.c: stop supporting len == -1 in type_from_string_gently()","fromName":"Felipe Contreras","fromEmail":"felipe.contreras@gmail.com","sentAt":"2021-04-22T18:09:48Z","receivedAt":"2021-04-22T18:09:56Z","isPatch":true,"sender":{"key":"felipe.contreras@gmail.com","avatar":"https://avatars.githubusercontent.com/u/8358?v=4"},"body":"Junio C Hamano wrote:\n> I am reasonably sure I and a few others on the list are net\n> suppliers of the reviewer bandwidth.  I do not expect all the\n> prolific contributors to become net suppliers; after all, designing\n> and writing their own stuff is always fun.  But I wish that the most\n> prominent contributors in the community to be reviewing others'\n> topics and ushering these topics to completion from time to time,\n> and I am hoping to see that happen more.\n\nThe problem is that the suppliers are a club who often agree on what\ncode is not ready to be merged, which is most of it, and also agree it's\nbetter to apply the reject hammer.\n\nThis club is by definition small.\n\nThere's a spectrum of perfectness, and the suppliers are on the far left\nside: code has to be perfect, while most of the consumers are on the\nright side, or even on the sensible middle side: do not let the perfect\nbe the enemy of the good.\n\nFor the suppliers club good is usually not good enough.\n\nI'm fairly confident most of the consumers would agree the bar on what\nconstitutes \"good enough\" is too damn high, so why would they spend time\nraising it any higher? They won't.\n\nIf anything they are more often going to dissagree with the suppliers\nclub, in order to increase the likelihood of perfectly good patches to\nbe merged.\n\nAs long as you keep insisting on making the perfect being the enemy of\nthe good, you are going to ensure the supply is *always* going to be\nlow.\n\nCheers.\n\n-- \nFelipe Contreras\n"},{"id":"423171","messageId":"xmqq7dkncaiu.fsf@gitster.g","threadId":"1003","inReplyTo":"YIC1IcpKCXh3qoun@google.com","subject":"Re: [PATCH v2 3/8] object.c: add and use oid_is_type_or_die_msg() function","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-28T04:12:41Z","receivedAt":"2021-04-28T04:12:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Josh Steadmon <steadmon@google.com> writes:\n\n> On 2021.04.20 15:36, Ævar Arnfjörð Bjarmason wrote:\n>> diff --git a/object.c b/object.c\n>> index 9e06c0ee92..0f07f976fb 100644\n>> --- a/object.c\n>> +++ b/object.c\n>> @@ -176,6 +176,18 @@ int oid_is_type_or_error(const struct object_id *oid,\n>>  \t\t     type_name(want));\n>>  }\n>>  \n>> +char* oid_is_type_or_die_msg(const struct object_id *oid,\n>\n> It's kind of a nitpick, but I found the function name to be confusing.\n> It sounds like you're going to die with a custom message. Maybe\n> something like \"get_oid_type_mismatch_msg()\" would be more\n> straightforward.\n\nYeah, in an older round I found this function's name was confusing,\ntoo.\n\nAlso, there is a style (in our codebase, asterisk to signal the\npointer-ness sticks to the identifier, not to the type name).\n\nThanks.\n"},{"id":"423237","messageId":"xmqqim459163.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-01.10-5818eca45d-20210420T124428Z-avarab@gmail.com","subject":"Re: [PATCH v2 01/10] cat-file tests: test for bogus type name handling","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T04:15:16Z","receivedAt":"2021-04-29T04:15:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Add a test of how \"cat-file\" behaves when given a bogus type in its\n> \"git cat-file <TYPE> <OBJECT>\" mode. There were existing tests (just\n> below this one) for \"-t bogus\" or \"--allow-unknown-type\" modes, but\n> none for the switch-less mode.\n>\n> This test is similar to the one that exists for \"git hash-object\"\n> already, see b7994af0f92 (type_from_string_gently: make sure length\n> matches, 2015-04-17).\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  t/t1006-cat-file.sh | 16 ++++++++++++++++\n>  1 file changed, 16 insertions(+)\n>\n> diff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\n> index 5d2dc99b74..908797dcae 100755\n> --- a/t/t1006-cat-file.sh\n> +++ b/t/t1006-cat-file.sh\n> @@ -315,6 +315,22 @@ test_expect_success '%(deltabase) reports packed delta bases' '\n>  \t}\n>  '\n>  \n> +test_expect_success 'cat-file complains about bogus type name' '\n> +\ttest_must_fail git cat-file co HEAD >out 2>err &&\n> +\ttest_must_be_empty out &&\n> +\tcat >expected <<-\\EOF &&\n> +\tfatal: invalid object type \"co\"\n> +\tEOF\n> +\ttest_cmp expected err &&\n> +\n> +\ttest_must_fail git cat-file bogus HEAD >out 2>err &&\n> +\ttest_must_be_empty out &&\n> +\tcat >expected <<-\\EOF &&\n> +\tfatal: invalid object type \"bogus\"\n> +\tEOF\n> +\ttest_cmp expected err\n> +'\n\nI am not 100% sure if it is worth testing both \"co\" and \"bogus\", but\nif it were, then I'd prefer to have these two as independent test\npieces, because a convincing \"we need to have both of these tested\nfor this reason\" would very much likely say that these two kinds of\nbugs can come from different/independent bug sources.\n\nFWIW, the commit b7994af0 (type_from_string_gently: make sure length\nmatches, 2015-04-17) used as a model for this patch uses two\nseparate tests (one for truncated, the other for bogus).\n\n>  bogus_type=\"bogus\"\n>  bogus_content=\"bogus\"\n>  bogus_size=$(strlen \"$bogus_content\")\n"},{"id":"423238","messageId":"xmqqeeet905b.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-04.10-48aca62864-20210420T124428Z-avarab@gmail.com","subject":"Re: [PATCH v2 04/10] object-file.c: take type id, not string, in read_object_with_reference()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T04:37:20Z","receivedAt":"2021-04-29T04:38:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Make the read_object_with_reference() function take \"enum object_type\"\n> instead of a \"const char *\" with a type name that it converted via\n> type_from_string().\n>\n> Out of the nine callers of this function, only one wanted to pass a\n> \"const char *\". The others were simply passing along the\n> {commit,tree}_type string constants.\n\ns/wanted to pass a/wanted to pass an arbitrary/, I would think.\nOther than that, nicely analyzed.\n\n> That one caller in builtin/cat-file.c did not expect to pass a \"raw\"\n> type (i.e. in invalid \"--literally\" type, but one gotten from\n> type_from_string().\n\nIt is unclear what you are trying to say here.  Missing closing ')'\nthat should close '(i.e.' does not help, either, because it muddles\nwhat you wanted to imply by bringing up the \"--literally\" option.\n\n    The one caller in builtin/cat-file.c passes the typename the\n    end-user typed on the command line i.e. \"git cat-file <TYPE>\n    <NAME>\", but read_object_with_reference() called in the codepath\n    is *NOT* expected to deal with objects with unknown/bogus type\n    crafted with \"hash-object --literally\" (note: \"git cat-file\"\n    does have the \"--allow-unknown-type\" option, but it can only be\n    used with the \"-s\" and \"-t\" options).  It won't result in loss\n    of functionality if we restricted the required_type parameter\n    given to read_object_with_reference() to the four known types by\n    changing the function signature to take the enum instead of\n    string.\n\nis probably what you meant to say, but I am only guessing.\n\n> diff --git a/builtin/cat-file.c b/builtin/cat-file.c\n> index 5ebf13359e..46fc7a32ba 100644\n> --- a/builtin/cat-file.c\n> +++ b/builtin/cat-file.c\n> @@ -66,7 +66,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \t\t\tint unknown_type)\n>  {\n>  \tstruct object_id oid;\n> -\tenum object_type type;\n> +\tenum object_type type, exp_type_id;\n>  \tchar *buf;\n>  \tunsigned long size;\n>  \tstruct object_context obj_context;\n> @@ -154,7 +154,8 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \t\tbreak;\n>  \n>  \tcase 0:\n> -\t\tif (type_from_string(exp_type) == OBJ_BLOB) {\n> +\t\texp_type_id = type_from_string(exp_type);\n> +\t\tif (exp_type_id == OBJ_BLOB) {\n>  \t\t\tstruct object_id blob_oid;\n>  \t\t\tif (oid_object_info(the_repository, &oid, NULL) == OBJ_TAG) {\n>  \t\t\t\tchar *buffer = read_object_file(&oid, &type,\n> @@ -177,7 +178,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name,\n>  \t\t\t */\n>  \t\t}\n>  \t\tbuf = read_object_with_reference(the_repository,\n> -\t\t\t\t\t\t &oid, exp_type, &size, NULL);\n> +\t\t\t\t\t\t &oid, exp_type_id, &size, NULL);\n>  \t\tbreak;\n>  \n>  \tdefault:\n\nAnd this is the caller we just discussed.\n\n> diff --git a/object-file.c b/object-file.c\n> index 624af408cd..d2f223dcef 100644\n> --- a/object-file.c\n> +++ b/object-file.c\n> @@ -1669,25 +1669,24 @@ void *read_object_file_extended(struct repository *r,\n>  \n>  void *read_object_with_reference(struct repository *r,\n>  \t\t\t\t const struct object_id *oid,\n> -\t\t\t\t const char *required_type_name,\n> +\t\t\t\t enum object_type object_type,\n>  \t\t\t\t unsigned long *size,\n>  \t\t\t\t struct object_id *actual_oid_return)\n>  {\n> -\tenum object_type type, required_type;\n>  \tvoid *buffer;\n>  \tunsigned long isize;\n>  \tstruct object_id actual_oid;\n>  \n> -\trequired_type = type_from_string(required_type_name);\n>  \toidcpy(&actual_oid, oid);\n>  \twhile (1) {\n>  \t\tint ref_length = -1;\n>  \t\tconst char *ref_type = NULL;\n> +\t\tenum object_type type;\n>  \n>  \t\tbuffer = repo_read_object_file(r, &actual_oid, &type, &isize);\n>  \t\tif (!buffer)\n>  \t\t\treturn NULL;\n> -\t\tif (type == required_type) {\n> +\t\tif (type == object_type) {\n>  \t\t\t*size = isize;\n>  \t\t\tif (actual_oid_return)\n>  \t\t\t\toidcpy(actual_oid_return, &actual_oid);\n\nI do not think it is a good change to effectively rename\nrequired_type to object_type.  Swapping the required_type_name\nparameter with required_type parameter of type \"enum object_type\"\nand dropping the now unneeded type_from_string() call would have\nbeen much easier to follow.\n\n"},{"id":"423239","messageId":"xmqqa6ph8zsc.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-05.10-5213d500b9-20210420T124428Z-avarab@gmail.com","subject":"Re: [PATCH v2 05/10] {commit,tree,blob,tag}.c: add a create_{commit,tree,blob,tag}()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T04:45:07Z","receivedAt":"2021-04-29T04:45:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Add a create_*() function for our built-in types as a handy but\n> trivial wrapper around their calls to create_object().\n>\n> This allows for slightly simplifying code added in\n> 96af91d410c (commit-graph: verify objects exist, 2018-06-27). The\n> remaining three functions are added for consistency for now.\n\n\"for now\" puzzles me.  As file-scope static functions, they do not\nhurt all that much, but on the other hand, having to say\n\"create_object(r, oid, alloc_blob_node(r))\" is not hurting at all.\n\nThe worst part of this \"consistency\" is that callers cannot call\ncreate_blob() because it is not external, even though they learn\ncreate_commit() as a handy way to use the create_object() API, which\nis not consistent at all.\n\nAnd since most callers should be calling lookup_blob() etc., and\nshould not be calling create_blob(), we shouldn't tempt people to\npush for making them externally available.\n\nWhich in turn makes me wonder if the use of create_object() added to\nthe commit-graph.c was a good idea to begin with.\n"},{"id":"423240","messageId":"xmqq5z058zht.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-06.10-02c8d2a9ba-20210420T124428Z-avarab@gmail.com","subject":"Re: [PATCH v2 06/10] blob.c: remove parse_blob_buffer()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T04:51:26Z","receivedAt":"2021-04-29T04:51:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> -int parse_blob_buffer(struct blob *item, void *buffer, unsigned long size)\n> -{\n> -\titem->object.parsed = 1;\n> -\treturn 0;\n> -}\n\nUnderstandable.\n\n> diff --git a/object.c b/object.c\n> index 78343781ae..f4e419e5c3 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -195,8 +195,7 @@ struct object *parse_object_buffer(struct repository *r, const struct object_id\n>  \tif (type == OBJ_BLOB) {\n>  \t\tstruct blob *blob = lookup_blob(r, oid);\n>  \t\tif (blob) {\n> -\t\t\tif (parse_blob_buffer(blob, buffer, size))\n> -\t\t\t\treturn NULL;\n> +\t\t\tblob->object.parsed = 1;\n>  \t\t\tobj = &blob->object;\n>  \t\t}\n\nUnderstandable, too.\n\n>  \t} else if (type == OBJ_TREE) {\n> @@ -262,12 +261,16 @@ struct object *parse_object(struct repository *r, const struct object_id *oid)\n>  \tif ((obj && obj->type == OBJ_BLOB && repo_has_object_file(r, oid)) ||\n>  \t    (!obj && repo_has_object_file(r, oid) &&\n>  \t     oid_object_info(r, oid, NULL) == OBJ_BLOB)) {\n> +\t\tif (!obj) {\n> +\t\t\tstruct blob *blob = create_blob(r, oid);\n> +\t\t\tobj = &blob->object;\n> +\t\t}\n\nI do not recall this change explained or justified in the log\nmessage.  What am I missing?\n\n>  \t\tif (check_object_signature(r, repl, NULL, 0, NULL) < 0) {\n>  \t\t\terror(_(\"hash mismatch %s\"), oid_to_hex(oid));\n>  \t\t\treturn NULL;\n>  \t\t}\n> -\t\tparse_blob_buffer(lookup_blob(r, oid), NULL, 0);\n> -\t\treturn lookup_object(r, oid);\n> +\t\tobj->parsed = 1;\n> +\t\treturn obj;\n\nLikewise.  Why isn't it just a call to lookup_blob() followed by\nsetting of its .parsed bit?  \n\nIn other words, it is not clear why we need to expose create_blob().\n\n>  \t}\n>  \n>  \tbuffer = repo_read_object_file(r, oid, &type, &size);\n"},{"id":"423241","messageId":"xmqq1rat8zbh.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-08.10-f652d0fb5c-20210420T124428Z-avarab@gmail.com","subject":"Re: [PATCH v2 08/10] object.c: don't go past \"len\" under die() in type_from_string_gently()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T04:55:14Z","receivedAt":"2021-04-29T04:55:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Fix a bug that's been with us ever since type_from_string_gently() was\n> split off from type_from_string() in fe8e3b71805 (Refactor\n> type_from_string() to allow continuing after detecting an error,\n> 2014-09-10).\n>\n> When the type was invalid and we were in the non-gently mode we'd die,\n> and then proceed to run off past the \"len\" of the buffer we were\n> provided with.\n>\n> Luckily, I think that nothing ever used this function in that way. Any\n> non-gentle invocation came via type_from_string(), which was passing a\n> buffer with a NIL at the same place as the \"len\" would take us (we got\n> it via strlen()).\n\nNIL???\n\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  object.c | 2 +-\n>  1 file changed, 1 insertion(+), 1 deletion(-)\n>\n> diff --git a/object.c b/object.c\n> index 70af833ca1..bad9e17f25 100644\n> --- a/object.c\n> +++ b/object.c\n> @@ -50,7 +50,7 @@ int type_from_string_gently(const char *str, ssize_t len, int gentle)\n>  \tif (gentle)\n>  \t\treturn -1;\n>  \n> -\tdie(_(\"invalid object type \\\"%s\\\"\"), str);\n> +\tdie(_(\"invalid object type \\\"%.*s\\\"\"), (int)len, str);\n>  }\n\nThis makes total sense.  This is one of the reasons why I hate to\nreview your topics---many patches in them seem unwarranted churn,\nbut there are clear gems like this commit buried in late steps in\nthem so I need to read through them to find these anyway :-)\n\n\n"},{"id":"423242","messageId":"xmqqwnsl7kga.fsf@gitster.g","threadId":"1003","inReplyTo":"patch-09.10-e463fe5f6a-20210420T124428Z-avarab@gmail.com","subject":"Re: [PATCH v2 09/10] mktree: stop setting *ntr++ to NIL","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2021-04-29T05:01:41Z","receivedAt":"2021-04-29T05:01:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> Since 58ce21b819e (builtin/mktree: remove hard-coded constant,\n> 2018-10-15) we have not made any subsequent use of the ntr variable\n> itself, but we did rely on it to NIL-delimit the string we were about\n> to feed to type_from_string().\n>\n> Using type_from_string() here results in needless work, as we'd do a\n> strlen() on it, just to find point at which we had a SPC\n> character (now NIL) earlier in this function.\n\nSince when do we write in LISP? ;-)  The name of the ASCII character\nwith value 0 is NUL (null).\n\n> We can instead skip incrementing the ntr pointer, then pass the\n> pointer and length to the type_from_string() function instead.\n\nMakes sense.  Not clobbering the input buffer is good.\n"},{"id":"423262","messageId":"875z05z46j.fsf@evledraar.gmail.com","threadId":"1003","inReplyTo":"xmqqa6ph8zsc.fsf@gitster.g","subject":"Re: [PATCH v2 05/10] {commit,tree,blob,tag}.c: add a create_{commit,tree,blob,tag}()","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2021-04-29T12:01:47Z","receivedAt":"2021-04-29T12:05:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, Apr 29 2021, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> Add a create_*() function for our built-in types as a handy but\n>> trivial wrapper around their calls to create_object().\n>>\n>> This allows for slightly simplifying code added in\n>> 96af91d410c (commit-graph: verify objects exist, 2018-06-27). The\n>> remaining three functions are added for consistency for now.\n>\n> \"for now\" puzzles me.  As file-scope static functions, they do not\n> hurt all that much, but on the other hand, having to say\n> \"create_object(r, oid, alloc_blob_node(r))\" is not hurting at all.\n>\n> The worst part of this \"consistency\" is that callers cannot call\n> create_blob() because it is not external, even though they learn\n> create_commit() as a handy way to use the create_object() API, which\n> is not consistent at all.\n>\n> And since most callers should be calling lookup_blob() etc., and\n> should not be calling create_blob(), we shouldn't tempt people to\n> push for making them externally available.\n\nThe API is for our own internal use. So I figured it was better to leave\nthe ones that aren't used elsewhere \"static\" for now, and if anyone\nneeded them in the future that commit could remove the \"static\".\n\n> Which in turn makes me wonder if the use of create_object() added to\n> the commit-graph.c was a good idea to begin with.\n\nYes we could just drop this and inline the various \"alloc\", i.e. not\nthis & similar in the future:\n\n-\t\todb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));\n+\t\todb_commit = create_commit(r, &cur_oid);\n\nIt just seemed like a net improvement for maintenance/readability to\nhave the simpler wrapper for the allocation / object creation v.s. the\nexisting alloc_X_node() + cast.\n"}]}