{"thread":{"id":"48896","subject":"[RFC PATCH 5/6] sha1-name: Teach `get_oid_with_context[_1]()` to be gentle","startedAt":"2018-07-17T12:06:55Z","lastAt":"2018-07-18T23:14:21Z","messageCount":13,"participants":["Paul-Sebastian Ungureanu","Duy Nguyen","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"352766","messageId":"dc1abfca46cd536f060b9097b9f2d1a64988f932.1531778417.git.ungureanupaulsebastian@gmail.com","threadId":"48896","inReplyTo":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"[RFC PATCH 5/6] sha1-name: Teach `get_oid_with_context[_1]()` to be gentle","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-17T12:06:35Z","receivedAt":"2018-07-17T12:06:55Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"This commit makes `get_oid_with_context()` and `get_oid_with_context_1()`\nto recognize the `GET_OID_GENTLY` flag.\n\nThe `gentle` flag does not imply `quiet` and we might need to reconsider\nwhether we should display any message if `GET_OID_GENTLY` is given.\n\nSigned-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>\n---\n sha1-name.c | 103 ++++++++++++++++++++++++++++++++++++++++++----------\n 1 file changed, 83 insertions(+), 20 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 74ecbd550..a5d4e0dc7 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -1521,11 +1521,12 @@ int get_oid_blob(const char *name, struct object_id *oid)\n }\n \n /* Must be called only when object_name:filename doesn't exist. */\n-static void diagnose_invalid_oid_path(const char *prefix,\n+static int diagnose_invalid_oid_path(const char *prefix,\n \t\t\t\t      const char *filename,\n \t\t\t\t      const struct object_id *tree_oid,\n \t\t\t\t      const char *object_name,\n-\t\t\t\t      int object_name_len)\n+\t\t\t\t      int object_name_len,\n+\t\t\t\t      int gentle)\n {\n \tstruct object_id oid;\n \tunsigned mode;\n@@ -1533,12 +1534,19 @@ static void diagnose_invalid_oid_path(const char *prefix,\n \tif (!prefix)\n \t\tprefix = \"\";\n \n-\tif (file_exists(filename))\n+\tif (file_exists(filename)) {\n+\t\tif (gentle)\n+\t\t\treturn -1;\n \t\tdie(\"Path '%s' exists on disk, but not in '%.*s'.\",\n \t\t    filename, object_name_len, object_name);\n+\t}\n \tif (is_missing_file_error(errno)) {\n \t\tchar *fullname = xstrfmt(\"%s%s\", prefix, filename);\n-\n+\t\tif (gentle) {\n+\t\t\twarning(_(\"%s or %s does not exist.\"), fullname,\n+\t\t\t\tfilename);\n+\t\t\treturn -1;\n+\t\t}\n \t\tif (!get_tree_entry(tree_oid, fullname, &oid, &mode)) {\n \t\t\tdie(\"Path '%s' exists, but not '%s'.\\n\"\n \t\t\t    \"Did you mean '%.*s:%s' aka '%.*s:./%s'?\",\n@@ -1552,12 +1560,14 @@ static void diagnose_invalid_oid_path(const char *prefix,\n \t\tdie(\"Path '%s' does not exist in '%.*s'\",\n \t\t    filename, object_name_len, object_name);\n \t}\n+\treturn 0;\n }\n \n /* Must be called only when :stage:filename doesn't exist. */\n-static void diagnose_invalid_index_path(int stage,\n+static int diagnose_invalid_index_path(int stage,\n \t\t\t\t\tconst char *prefix,\n-\t\t\t\t\tconst char *filename)\n+\t\t\t\t\tconst char *filename,\n+\t\t\t\t\tint gentle)\n {\n \tconst struct cache_entry *ce;\n \tint pos;\n@@ -1574,11 +1584,20 @@ static void diagnose_invalid_index_path(int stage,\n \tif (pos < active_nr) {\n \t\tce = active_cache[pos];\n \t\tif (ce_namelen(ce) == namelen &&\n-\t\t    !memcmp(ce->name, filename, namelen))\n+\t\t    !memcmp(ce->name, filename, namelen)) {\n+\t\t\tif (gentle) {\n+\t\t\t\twarning(\"Path '%s' is in the index \"\n+\t\t\t\t\t\"but not at stage %d.\\n\"\n+\t\t\t\t\t\"Did you mean ':%d:%s'?\",\n+\t\t\t\t\tfilename, stage,\n+\t\t\t\t\tce_stage(ce), filename);\n+\t\t\t\treturn -1;\n+\t\t\t}\n \t\t\tdie(\"Path '%s' is in the index, but not at stage %d.\\n\"\n \t\t\t    \"Did you mean ':%d:%s'?\",\n \t\t\t    filename, stage,\n \t\t\t    ce_stage(ce), filename);\n+\t\t}\n \t}\n \n \t/* Confusion between relative and absolute filenames? */\n@@ -1590,31 +1609,58 @@ static void diagnose_invalid_index_path(int stage,\n \tif (pos < active_nr) {\n \t\tce = active_cache[pos];\n \t\tif (ce_namelen(ce) == fullname.len &&\n-\t\t    !memcmp(ce->name, fullname.buf, fullname.len))\n+\t\t    !memcmp(ce->name, fullname.buf, fullname.len)) {\n+\t\t\tif (gentle)\n+\t\t\t\treturn -1;\n \t\t\tdie(\"Path '%s' is in the index, but not '%s'.\\n\"\n \t\t\t    \"Did you mean ':%d:%s' aka ':%d:./%s'?\",\n \t\t\t    fullname.buf, filename,\n \t\t\t    ce_stage(ce), fullname.buf,\n \t\t\t    ce_stage(ce), filename);\n+\t\t}\n \t}\n \n-\tif (file_exists(filename))\n+\tif (file_exists(filename)) {\n+\t\tif (gentle)\n+\t\t\treturn -1;\n \t\tdie(\"Path '%s' exists on disk, but not in the index.\", filename);\n-\tif (is_missing_file_error(errno))\n+\t}\n+\tif (is_missing_file_error(errno)) {\n+\t\tif (gentle)\n+\t\t\treturn -1;\n \t\tdie(\"Path '%s' does not exist (neither on disk nor in the index).\",\n \t\t    filename);\n+\t}\n \n \tstrbuf_release(&fullname);\n+\treturn 0;\n }\n \n+static const char *resolve_error = \"dummy\";\n \n-static char *resolve_relative_path(const char *rel)\n+static char *resolve_relative_path_gently(const char *rel, int gentle)\n {\n \tif (!starts_with(rel, \"./\") && !starts_with(rel, \"../\"))\n \t\treturn NULL;\n \n-\tif (!is_inside_work_tree())\n+\tif (!is_inside_work_tree()) {\n+\t\t/*\n+\t\t * `resolve_error` is a dummy variable and it is used to verify\n+\t\t * if there was any problem inside this function. This is\n+\t\t * returned only in the case we want to perform gently,\n+\t\t * otherwise, `exit()` or `die()` can be called.\n+\t\t */\n+\t\tif (gentle)\n+\t\t\treturn (char*) resolve_error;\n \t\tdie(\"relative path syntax can't be used outside working tree.\");\n+\t}\n+\n+\tif (gentle) {\n+\t\treturn prefix_path_gently(startup_info->prefix,\n+\t\t\t\t\t  startup_info->prefix ?\n+\t\t\t\t\t  strlen(startup_info->prefix) : 0,\n+\t\t\t\t\t  NULL, rel);\n+\t}\n \n \t/* die() inside prefix_path() if resolved path is outside worktree */\n \treturn prefix_path(startup_info->prefix,\n@@ -1669,7 +1715,16 @@ static int get_oid_with_context_1(const char *name,\n \t\t\tstage = name[1] - '0';\n \t\t\tcp = name + 3;\n \t\t}\n-\t\tnew_path = resolve_relative_path(cp);\n+\t\t/*\n+\t\t * Note that `resolve_relative_path_gently()` may die if\n+\t\t * the second parameter is zero. If it is a non-zero value,\n+\t\t * the function will return `resolve_error` on failure. This\n+\t\t * dummy variable is defined as a `static const char *`.\n+\t\t */\n+\t\tnew_path = resolve_relative_path_gently(cp, flags & GET_OID_GENTLY);\n+\t\tif (new_path == resolve_error)\n+\t\t\treturn -1;\n+\n \t\tif (!new_path) {\n \t\t\tnamelen = namelen - (cp - name);\n \t\t} else {\n@@ -1698,8 +1753,11 @@ static int get_oid_with_context_1(const char *name,\n \t\t\t}\n \t\t\tpos++;\n \t\t}\n-\t\tif (only_to_die && name[1] && name[1] != '/')\n-\t\t\tdiagnose_invalid_index_path(stage, prefix, cp);\n+\t\tif (only_to_die && name[1] && name[1] != '/' &&\n+\t\t\tdiagnose_invalid_index_path(stage, prefix, cp,\n+\t\t\t\t\t\t    flags & GET_OID_GENTLY))\n+\t\t\treturn -1;\n+\n \t\tfree(new_path);\n \t\treturn -1;\n \t}\n@@ -1723,7 +1781,10 @@ static int get_oid_with_context_1(const char *name,\n \t\t\tconst char *filename = cp+1;\n \t\t\tchar *new_filename = NULL;\n \n-\t\t\tnew_filename = resolve_relative_path(filename);\n+\t\t\tnew_filename = resolve_relative_path_gently(filename,\n+\t\t\t\t\t\t\t\t    flags & GET_OID_GENTLY);\n+\t\t\tif (new_filename == resolve_error)\n+\t\t\t\treturn -1;\n \t\t\tif (new_filename)\n \t\t\t\tfilename = new_filename;\n \t\t\tif (flags & GET_OID_FOLLOW_SYMLINKS) {\n@@ -1731,13 +1792,14 @@ static int get_oid_with_context_1(const char *name,\n \t\t\t\t\tfilename, oid, &oc->symlink_path,\n \t\t\t\t\t&oc->mode, flags);\n \t\t\t} else {\n-\t\t\t\tret = get_tree_entry(&tree_oid, filename, oid,\n-\t\t\t\t\t\t     &oc->mode);\n+\t\t\t\tret = get_tree_entry_gently(&tree_oid, filename,\n+\t\t\t\t\t\t\t    oid, &oc->mode,\n+\t\t\t\t\t\t\t    flags & GET_OID_GENTLY);\n \t\t\t\tif (ret && only_to_die) {\n \t\t\t\t\tdiagnose_invalid_oid_path(prefix,\n \t\t\t\t\t\t\t\t   filename,\n \t\t\t\t\t\t\t\t   &tree_oid,\n-\t\t\t\t\t\t\t\t   name, len);\n+\t\t\t\t\t\t\t\t   name, len, 0);\n \t\t\t\t}\n \t\t\t}\n \t\t\tif (flags & GET_OID_RECORD_PATH)\n@@ -1769,7 +1831,8 @@ void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)\n \n int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)\n {\n-\tif (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)\n+\tif (flags & (GET_OID_FOLLOW_SYMLINKS | GET_OID_GENTLY) &&\n+\t    flags & GET_OID_ONLY_TO_DIE)\n \t\tBUG(\"incompatible flags for get_sha1_with_context\");\n \treturn get_oid_with_context_1(str, flags, NULL, oid, oc);\n }\n-- \n2.18.0.rc2.184.ga79db55c2.dirty\n\n"},{"id":"352767","messageId":"046f5f7a3495acbbb53ee2b7007d5c058f18cc0b.1531778417.git.ungureanupaulsebastian@gmail.com","threadId":"48896","inReplyTo":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"[RFC PATCH 6/6] sha1-name: Add gentle alternative for `get_oid()`","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-17T12:06:36Z","receivedAt":"2018-07-17T12:06:55Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"Add `get_oid_gently()` to be a gentle alternative to `get_oid()`.\n\nSigned-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>\n---\n cache.h     | 1 +\n sha1-name.c | 6 ++++++\n 2 files changed, 7 insertions(+)\n\ndiff --git a/cache.h b/cache.h\nindex cb8803e2f..36e196202 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1321,6 +1321,7 @@ struct object_context {\n \tGET_OID_TREE | GET_OID_TREEISH | \\\n \tGET_OID_BLOB)\n \n+extern int get_oid_gently(const char *str, struct object_id *oid);\n extern int get_oid(const char *str, struct object_id *oid);\n extern int get_oid_commit(const char *str, struct object_id *oid);\n extern int get_oid_committish(const char *str, struct object_id *oid);\ndiff --git a/sha1-name.c b/sha1-name.c\nindex a5d4e0dc7..6ee48fdf7 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -1474,6 +1474,12 @@ int get_oid(const char *name, struct object_id *oid)\n \treturn get_oid_with_context(name, 0, oid, &unused);\n }\n \n+int get_oid_gently(const char *name, struct object_id *oid)\n+{\n+\tstruct object_context unused;\n+\treturn get_oid_with_context(name, GET_OID_GENTLY, oid, &unused);\n+}\n+\n \n /*\n  * Many callers know that the user meant to name a commit-ish by\n-- \n2.18.0.rc2.184.ga79db55c2.dirty\n\n"},{"id":"352768","messageId":"d91384ff0e23cd845bcfdf170c8a162ec5551f6b.1531778417.git.ungureanupaulsebastian@gmail.com","threadId":"48896","inReplyTo":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"[RFC PATCH 4/6] sha1-name: Teach `get_oid_basic()` to be gentle","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-17T12:06:34Z","receivedAt":"2018-07-17T12:07:43Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"After teaching `read_ref_at()` we need to teach `get_oid_basic()`\nthat `read_ref_at()` might not call `exit()`, but report an\nerror through the return value.\n\nSigned-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>\n---\n sha1-name.c | 16 ++++++++++++----\n 1 file changed, 12 insertions(+), 4 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex d741e1129..74ecbd550 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -778,6 +778,7 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid,\n \t\ttimestamp_t at_time;\n \t\ttimestamp_t co_time;\n \t\tint co_tz, co_cnt;\n+\t\tint ret;\n \n \t\t/* Is it asking for N-th entry, or approxidate? */\n \t\tfor (i = nth = 0; 0 <= nth && i < reflog_len; i++) {\n@@ -802,8 +803,12 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid,\n \t\t\t\treturn -1;\n \t\t\t}\n \t\t}\n-\t\tif (read_ref_at(real_ref, flags, at_time, nth, oid, NULL,\n-\t\t\t\t&co_time, &co_tz, &co_cnt)) {\n+\n+\t\tret = read_ref_at(real_ref, flags, at_time, nth, oid, NULL,\n+\t\t\t\t&co_time, &co_tz, &co_cnt);\n+\t\tif (ret == -1)\n+\t\t\treturn -1;\n+\t\tif (ret) {\n \t\t\tif (!len) {\n \t\t\t\tif (starts_with(real_ref, \"refs/heads/\")) {\n \t\t\t\t\tstr = real_ref + 11;\n@@ -821,9 +826,12 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid,\n \t\t\t\t\t\tshow_date(co_time, co_tz, DATE_MODE(RFC2822)));\n \t\t\t\t}\n \t\t\t} else {\n-\t\t\t\tif (flags & GET_OID_QUIETLY) {\n-\t\t\t\t\texit(128);\n+\t\t\t\tif (flags & GET_OID_GENTLY) {\n+\t\t\t\t\tfree(real_ref);\n+\t\t\t\t\treturn -1;\n \t\t\t\t}\n+\t\t\t\tif (flags & GET_OID_QUIETLY)\n+\t\t\t\t\texit(128);\n \t\t\t\tdie(\"Log for '%.*s' only has %d entries.\",\n \t\t\t\t    len, str, co_cnt);\n \t\t\t}\n-- \n2.18.0.rc2.184.ga79db55c2.dirty\n\n"},{"id":"352769","messageId":"c62fecd41db87b22d3605029685eb0281d67fc96.1531778417.git.ungureanupaulsebastian@gmail.com","threadId":"48896","inReplyTo":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"[RFC PATCH 3/6] refs.c: Teach `read_ref_at()` to accept `GET_OID_GENTLY` flag","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-17T12:06:33Z","receivedAt":"2018-07-17T12:07:57Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"This commit introduces a way to call `read_ref_at()` without\nexiting on failure.\n\nSigned-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>\n---\n refs.c | 2 ++\n 1 file changed, 2 insertions(+)\n\ndiff --git a/refs.c b/refs.c\nindex 0eb379f93..4a470158e 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -932,6 +932,8 @@ int read_ref_at(const char *refname, unsigned int flags, timestamp_t at_time, in\n \tfor_each_reflog_ent_reverse(refname, read_ref_at_ent, &cb);\n \n \tif (!cb.reccnt) {\n+\t\tif (flags & GET_OID_GENTLY)\n+\t\t\treturn -1;\n \t\tif (flags & GET_OID_QUIETLY)\n \t\t\texit(128);\n \t\telse\n-- \n2.18.0.rc2.184.ga79db55c2.dirty\n\n"},{"id":"352770","messageId":"b1f385105f790cafc65c26699282919a2735d4bd.1531778417.git.ungureanupaulsebastian@gmail.com","threadId":"48896","inReplyTo":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"[RFC PATCH 2/6] tree-walk: Add three new gentle helpers","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-17T12:06:32Z","receivedAt":"2018-07-17T12:08:23Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"Add `get_tree_entry_gently()`, `find_tree_entry_gently()`\nand `get_tree_entry_follow_symlinks_gently()`, which will\nmake `get_oid()` to be more gently.\n\nSince `get_tree_entry()` is used in more than 20 places,\nadding a new parameter will make this commit harder to read.\nIn every place it is called there will need to be an additional\n0 parameter at the end of the call. The solution to avoid this is\nto rename the function in `get_tree_entry_gently()` which gets\nan additional `flags` variable. A new `get_tree_entry()`\nwill call `get_tree_entry_gently()` with `flags` being 0.\nThis way, no additional changes will be needed.\n\nSigned-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>\n---\n sha1-name.c |   2 +-\n tree-walk.c | 108 +++++++++++++++++++++++++++++++++++++++++++---------\n tree-walk.h |   3 +-\n 3 files changed, 94 insertions(+), 19 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 60d9ef3c7..d741e1129 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -1721,7 +1721,7 @@ static int get_oid_with_context_1(const char *name,\n \t\t\tif (flags & GET_OID_FOLLOW_SYMLINKS) {\n \t\t\t\tret = get_tree_entry_follow_symlinks(&tree_oid,\n \t\t\t\t\tfilename, oid, &oc->symlink_path,\n-\t\t\t\t\t&oc->mode);\n+\t\t\t\t\t&oc->mode, flags);\n \t\t\t} else {\n \t\t\t\tret = get_tree_entry(&tree_oid, filename, oid,\n \t\t\t\t\t\t     &oc->mode);\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 8f5090862..2925eaec2 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -491,7 +491,9 @@ struct dir_state {\n \tstruct object_id oid;\n };\n \n-static int find_tree_entry(struct tree_desc *t, const char *name, struct object_id *result, unsigned *mode)\n+static int find_tree_entry(struct tree_desc *t, const char *name,\n+\t\t\t\t  struct object_id *result, unsigned *mode,\n+\t\t\t\t  int flags)\n {\n \tint namelen = strlen(name);\n \twhile (t->size) {\n@@ -501,7 +503,11 @@ static int find_tree_entry(struct tree_desc *t, const char *name, struct object_\n \n \t\toid = tree_entry_extract(t, &entry, mode);\n \t\tentrylen = tree_entry_len(&t->entry);\n-\t\tupdate_tree_entry(t);\n+\n+\t\tif (!(flags & GET_OID_GENTLY))\n+\t\t\tupdate_tree_entry(t);\n+\t\telse if (update_tree_entry_gently(t))\n+\t\t\treturn -1;\n \t\tif (entrylen > namelen)\n \t\t\tcontinue;\n \t\tcmp = memcmp(name, entry, entrylen);\n@@ -521,19 +527,28 @@ static int find_tree_entry(struct tree_desc *t, const char *name, struct object_\n \t\t\toidcpy(result, oid);\n \t\t\treturn 0;\n \t\t}\n-\t\treturn get_tree_entry(oid, name + entrylen, result, mode);\n+\t\treturn get_tree_entry_gently(oid, name + entrylen, result, mode, flags);\n \t}\n \treturn -1;\n }\n \n-int get_tree_entry(const struct object_id *tree_oid, const char *name, struct object_id *oid, unsigned *mode)\n+int get_tree_entry_gently(const struct object_id *tree_oid, const char *name,\n+\t\t\t  struct object_id *oid, unsigned *mode, int flags)\n {\n \tint retval;\n \tvoid *tree;\n \tunsigned long size;\n \tstruct object_id root;\n \n-\ttree = read_object_with_reference(tree_oid, tree_type, &size, &root);\n+\tif (!(flags & GET_OID_GENTLY)) {\n+\t\ttree = read_object_with_reference(tree_oid, tree_type, &size, &root);\n+\t} else {\n+\t\tstruct object_info oi = OBJECT_INFO_INIT;\n+\n+\t\toi.contentp = tree;\n+\t\tif (oid_object_info_extended(the_repository, tree_oid, &oi, 0) < 0)\n+\t\t\treturn -1;\n+\t}\n \tif (!tree)\n \t\treturn -1;\n \n@@ -547,13 +562,27 @@ int get_tree_entry(const struct object_id *tree_oid, const char *name, struct ob\n \t\tretval = -1;\n \t} else {\n \t\tstruct tree_desc t;\n-\t\tinit_tree_desc(&t, tree, size);\n-\t\tretval = find_tree_entry(&t, name, oid, mode);\n+\t\tif (!(flags & GET_OID_GENTLY)) {\n+\t\t\tinit_tree_desc(&t, tree, size);\n+\t\t} else {\n+\t\t\tif (init_tree_desc_gently(&t, tree, size)) {\n+\t\t\t\tretval = -1;\n+\t\t\t\tgoto done;\n+\t\t\t}\n+\t\t}\n+\t\tretval = find_tree_entry(&t, name, oid, mode, flags);\n \t}\n+done:\n \tfree(tree);\n \treturn retval;\n }\n \n+int get_tree_entry(const struct object_id *tree_oid, const char *name,\n+\t\t   struct object_id *oid, unsigned *mode)\n+{\n+\treturn get_tree_entry_gently(tree_oid, name, oid, mode, 0);\n+}\n+\n /*\n  * This is Linux's built-in max for the number of symlinks to follow.\n  * That limit, of course, does not affect git, but it's a reasonable\n@@ -576,7 +605,7 @@ int get_tree_entry(const struct object_id *tree_oid, const char *name, struct ob\n  * See the code for enum follow_symlink_result for a description of\n  * the return values.\n  */\n-enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode)\n+enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode, int flags)\n {\n \tint retval = MISSING_OBJECT;\n \tstruct dir_state *parents = NULL;\n@@ -600,9 +629,21 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n \t\t\tvoid *tree;\n \t\t\tstruct object_id root;\n \t\t\tunsigned long size;\n-\t\t\ttree = read_object_with_reference(&current_tree_oid,\n-\t\t\t\t\t\t\t  tree_type, &size,\n-\t\t\t\t\t\t\t  &root);\n+\t\t\tif (!(flags & GET_OID_GENTLY)) {\n+\t\t\t\ttree = read_object_with_reference(&current_tree_oid,\n+\t\t\t\t\t\t\t\t  tree_type, &size,\n+\t\t\t\t\t\t\t\t  &root);\n+\t\t\t} else {\n+\t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n+\n+\t\t\t\toi.contentp = tree;\n+\t\t\t\tif (oid_object_info_extended(the_repository,\n+\t\t\t\t    &current_tree_oid, &oi, 0) < 0) {\n+\t\t\t\t\tretval = MISSING_OBJECT;\n+\t\t\t\t\tgoto done;\n+\t\t\t\t}\n+\t\t\t}\n+\n \t\t\tif (!tree)\n \t\t\t\tgoto done;\n \n@@ -622,7 +663,14 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n \t\t\t\tgoto done;\n \n \t\t\t/* descend */\n-\t\t\tinit_tree_desc(&t, tree, size);\n+\t\t\tif (!(flags & GET_OID_GENTLY)) {\n+\t\t\t\tinit_tree_desc(&t, tree, size);\n+\t\t\t} else {\n+\t\t\t\tif (init_tree_desc_gently(&t, tree, size)) {\n+\t\t\t\t\tretval = MISSING_OBJECT;\n+\t\t\t\t\tgoto done;\n+\t\t\t\t}\n+\t\t\t}\n \t\t}\n \n \t\t/* Handle symlinks to e.g. a//b by removing leading slashes */\n@@ -656,7 +704,15 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n \t\t\tfree(parent->tree);\n \t\t\tparents_nr--;\n \t\t\tparent = &parents[parents_nr - 1];\n-\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n+\t\t\tif (!(flags & GET_OID_GENTLY)) {\n+\t\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n+\t\t\t} else {\n+\t\t\t\tif (init_tree_desc_gently(&t, parent->tree,\n+\t\t\t\t    parent->size)) {\n+\t\t\t\t\tretval = MISSING_OBJECT;\n+\t\t\t\t\tgoto done;\n+\t\t\t\t}\n+\t\t\t}\n \t\t\tstrbuf_remove(&namebuf, 0, remainder ? 3 : 2);\n \t\t\tcontinue;\n \t\t}\n@@ -670,7 +726,7 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n \n \t\t/* Look up the first (or only) path component in the tree. */\n \t\tfind_result = find_tree_entry(&t, namebuf.buf,\n-\t\t\t\t\t      &current_tree_oid, mode);\n+\t\t\t\t\t      &current_tree_oid, mode, flags);\n \t\tif (find_result) {\n \t\t\tgoto done;\n \t\t}\n@@ -713,8 +769,19 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n \t\t\t */\n \t\t\tretval = DANGLING_SYMLINK;\n \n-\t\t\tcontents = read_object_file(&current_tree_oid, &type,\n-\t\t\t\t\t\t    &link_len);\n+\t\t\tif (!(flags & GET_OID_GENTLY)) {\n+\t\t\t\tcontents = read_object_file(&current_tree_oid,\n+\t\t\t\t\t\t\t    &type, &link_len);\n+\t\t\t} else {\n+\t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n+\t\t\t\toi.contentp = (void*) contents;\n+\n+\t\t\t\tif (oid_object_info_extended(the_repository,\n+\t\t\t\t    &current_tree_oid, &oi, 0) < 0) {\n+\t\t\t\t\tretval = MISSING_OBJECT;\n+\t\t\t\t\tgoto done;\n+\t\t\t\t}\n+\t\t\t}\n \n \t\t\tif (!contents)\n \t\t\t\tgoto done;\n@@ -735,7 +802,14 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n \t\t\tcontents_start = contents;\n \n \t\t\tparent = &parents[parents_nr - 1];\n-\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n+\t\t\tif (!(flags & GET_OID_GENTLY)) {\n+\t\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n+\t\t\t} else {\n+\t\t\t\tif (init_tree_desc_gently(&t, parent->tree, parent->size)) {\n+\t\t\t\t\tretval = MISSING_OBJECT;\n+\t\t\t\t\tgoto done;\n+\t\t\t\t}\n+\t\t\t}\n \t\t\tstrbuf_splice(&namebuf, 0, len,\n \t\t\t\t      contents_start, link_len);\n \t\t\tif (remainder)\ndiff --git a/tree-walk.h b/tree-walk.h\nindex 805f58f00..6f043af6e 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -64,7 +64,7 @@ enum follow_symlinks_result {\n \t\t       */\n };\n \n-enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode);\n+enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode, int flags);\n \n struct traverse_info {\n \tconst char *traverse_path;\n@@ -79,6 +79,7 @@ struct traverse_info {\n \tint show_all_errors;\n };\n \n+int get_tree_entry_gently(const struct object_id *, const char *, struct object_id *, unsigned *, int);\n int get_tree_entry(const struct object_id *, const char *, struct object_id *, unsigned *);\n extern char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n);\n extern void setup_traverse_info(struct traverse_info *info, const char *base);\n-- \n2.18.0.rc2.184.ga79db55c2.dirty\n\n"},{"id":"352771","messageId":"973c4d380743b4a0491ec63909fef862413db065.1531778417.git.ungureanupaulsebastian@gmail.com","threadId":"48896","inReplyTo":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"[RFC PATCH 1/6] sha1-name: Add `GET_OID_GENTLY` flag","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-17T12:06:31Z","receivedAt":"2018-07-17T12:08:44Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"The current API does not provide a method to call\n`get_oid()` and avoid `exit()` to be called. This commit\nintention is to introduce a flag in order to make `get_oid()`\nable to get the sha1 safely, without exiting the program.\n\nSince `get_oid()` calls a lot of functions, which call other\nfunctions as well (and so on), there are a lot of cases in which\n`exit()` could be called. To make this idea more clear, here\nis one example, which could cause `get_oid()` to die.\n\n  get_oid() -> get_oid_with_context() -> get_oid_with_context_1()\n  -> get_oid_1() -> read_ref_at() -> exit()\n\nWhere `function1() -> function2()` means that `function1()` might\ncall `function2()` at some point.\n\nSigned-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>\n---\n cache.h | 1 +\n 1 file changed, 1 insertion(+)\n\ndiff --git a/cache.h b/cache.h\nindex d49092d94..cb8803e2f 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1314,6 +1314,7 @@ struct object_context {\n #define GET_OID_FOLLOW_SYMLINKS 0100\n #define GET_OID_RECORD_PATH     0200\n #define GET_OID_ONLY_TO_DIE    04000\n+#define GET_OID_GENTLY\t      010000\n \n #define GET_OID_DISAMBIGUATORS \\\n \t(GET_OID_COMMIT | GET_OID_COMMITTISH | \\\n-- \n2.18.0.rc2.184.ga79db55c2.dirty\n\n"},{"id":"352772","messageId":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","threadId":"48896","inReplyTo":null,"subject":"[RFC PATCH 0/6] Add gentle alternative for `get_oid()`","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-17T12:06:30Z","receivedAt":"2018-07-17T12:09:12Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"At the moment, `get_oid()` might call `die()` in some cases. To\nprevent that from happening, this patches introduces a new flag\ncalled `GET_OID_GENTLY` and a new function `get_oid_gently()`,\nwhich passes the mentioned flag further to `get_oid_with_context()`.\n\nThe call graph of `get_oid()` is pretty complex and I hope I covered\nall the cases where `exit()` might be called. Although I believe this\nseries of patches will not introduce any regression and work as\nintended, I think that is better to mark it with [RFC].\n\nThis patch would be useful for converting `git stash` to C. At the\nmoment, `git stash` spawns a child process to avoid `get_oid()` to\ndie. If this series turns out to be good enough to be accepted, do\nI need to wait until it gets merged in `master` to use it in the\nother project mentioned before?\n\nThanks,\nPaul\n\nPaul-Sebastian Ungureanu (6):\n  sha1-name: Add `GET_OID_GENTLY` flag\n  tree-walk: Add three new gentle helpers\n  refs.c: Teach `read_ref_at()` to accept `GET_OID_GENTLY` flag\n  sha1-name: Teach `get_oid_basic()` to be gentle\n  sha1-name: Teach `get_oid_with_context[_1]()` to be gentle\n  sha1-name: Add gentle alternative for `get_oid()`\n\n cache.h     |   2 +\n refs.c      |   2 +\n sha1-name.c | 127 +++++++++++++++++++++++++++++++++++++++++-----------\n tree-walk.c | 108 +++++++++++++++++++++++++++++++++++++-------\n tree-walk.h |   3 +-\n 5 files changed, 199 insertions(+), 43 deletions(-)\n\n-- \n2.18.0.rc2.184.ga79db55c2.dirty\n\n"},{"id":"352806","messageId":"CACsJy8AEDmyg1XpgXc5KgKdG33t2SeOHw56tEgL_VVXh1Bcprg@mail.gmail.com","threadId":"48896","inReplyTo":"cover.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"Re: [RFC PATCH 0/6] Add gentle alternative for `get_oid()`","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-07-17T17:45:17Z","receivedAt":"2018-07-17T17:45:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, Jul 17, 2018 at 2:10 PM Paul-Sebastian Ungureanu\n<ungureanupaulsebastian@gmail.com> wrote:\n>\n> At the moment, `get_oid()` might call `die()` in some cases. To\n> prevent that from happening, this patches introduces a new flag\n> called `GET_OID_GENTLY` and a new function `get_oid_gently()`,\n> which passes the mentioned flag further to `get_oid_with_context()`.\n\nSince get_oid() callers must handle failure when it returns non-zero,\nI would say \"gently\" is already implied by get_oid() and we could just\nconvert those die() to error() or warning(). Unless some of those\ndie() are very special that we need to choose which call sites should\ngo \"even gentler\" where some sites should still die()?\n-- \nDuy\n"},{"id":"352817","messageId":"xmqqin5dofor.fsf@gitster-ct.c.googlers.com","threadId":"48896","inReplyTo":"b1f385105f790cafc65c26699282919a2735d4bd.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"Re: [RFC PATCH 2/6] tree-walk: Add three new gentle helpers","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-17T18:55:16Z","receivedAt":"2018-07-17T18:55:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com> writes:\n\n> Add `get_tree_entry_gently()`, `find_tree_entry_gently()`\n> and `get_tree_entry_follow_symlinks_gently()`, which will\n> make `get_oid()` to be more gently.\n>\n> Since `get_tree_entry()` is used in more than 20 places,\n> adding a new parameter will make this commit harder to read.\n> In every place it is called there will need to be an additional\n> 0 parameter at the end of the call. The solution to avoid this is\n> to rename the function in `get_tree_entry_gently()` which gets\n> an additional `flags` variable. A new `get_tree_entry()`\n> will call `get_tree_entry_gently()` with `flags` being 0.\n> This way, no additional changes will be needed.\n\nAnd that is the right way to introduce a new feature to existing API\nwith many callers in general.\n\nI wonder if the GENTLY option should apply to update_tree_entry()\nthe same way as it would to the other codepaths that currently die\nto express \"we were handed this string by the caller and told to\ngive back object ID the string represents, and we found no good\nanswer\".  In this one (and the \"bad ref\" one), the existing failures\nin these two codepaths are not \"we got a string and that does not\nresolve to an object name\", but \"we didn't have the data to work on\nto begin with (either a corrupt tree object or a corrupt ref\").\n\nIn other words, it's not like \"We were given HEAD:no-such-path and\nthere is no such path in that tree\"; it is \"We tried to read HEAD:\ntree for no-such-path in it, but the tree was corrupt and we couldn't\neven tell if such a path is or is not in it\", no?\n\n> Signed-off-by: Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com>\n> ---\n>  sha1-name.c |   2 +-\n>  tree-walk.c | 108 +++++++++++++++++++++++++++++++++++++++++++---------\n>  tree-walk.h |   3 +-\n>  3 files changed, 94 insertions(+), 19 deletions(-)\n>\n> diff --git a/sha1-name.c b/sha1-name.c\n> index 60d9ef3c7..d741e1129 100644\n> --- a/sha1-name.c\n> +++ b/sha1-name.c\n> @@ -1721,7 +1721,7 @@ static int get_oid_with_context_1(const char *name,\n>  \t\t\tif (flags & GET_OID_FOLLOW_SYMLINKS) {\n>  \t\t\t\tret = get_tree_entry_follow_symlinks(&tree_oid,\n>  \t\t\t\t\tfilename, oid, &oc->symlink_path,\n> -\t\t\t\t\t&oc->mode);\n> +\t\t\t\t\t&oc->mode, flags);\n>  \t\t\t} else {\n>  \t\t\t\tret = get_tree_entry(&tree_oid, filename, oid,\n>  \t\t\t\t\t\t     &oc->mode);\n> diff --git a/tree-walk.c b/tree-walk.c\n> index 8f5090862..2925eaec2 100644\n> --- a/tree-walk.c\n> +++ b/tree-walk.c\n> @@ -491,7 +491,9 @@ struct dir_state {\n>  \tstruct object_id oid;\n>  };\n>  \n> -static int find_tree_entry(struct tree_desc *t, const char *name, struct object_id *result, unsigned *mode)\n> +static int find_tree_entry(struct tree_desc *t, const char *name,\n> +\t\t\t\t  struct object_id *result, unsigned *mode,\n> +\t\t\t\t  int flags)\n>  {\n>  \tint namelen = strlen(name);\n>  \twhile (t->size) {\n> @@ -501,7 +503,11 @@ static int find_tree_entry(struct tree_desc *t, const char *name, struct object_\n>  \n>  \t\toid = tree_entry_extract(t, &entry, mode);\n>  \t\tentrylen = tree_entry_len(&t->entry);\n> -\t\tupdate_tree_entry(t);\n> +\n> +\t\tif (!(flags & GET_OID_GENTLY))\n> +\t\t\tupdate_tree_entry(t);\n> +\t\telse if (update_tree_entry_gently(t))\n> +\t\t\treturn -1;\n>  \t\tif (entrylen > namelen)\n>  \t\t\tcontinue;\n>  \t\tcmp = memcmp(name, entry, entrylen);\n> @@ -521,19 +527,28 @@ static int find_tree_entry(struct tree_desc *t, const char *name, struct object_\n>  \t\t\toidcpy(result, oid);\n>  \t\t\treturn 0;\n>  \t\t}\n> -\t\treturn get_tree_entry(oid, name + entrylen, result, mode);\n> +\t\treturn get_tree_entry_gently(oid, name + entrylen, result, mode, flags);\n>  \t}\n>  \treturn -1;\n>  }\n>  \n> -int get_tree_entry(const struct object_id *tree_oid, const char *name, struct object_id *oid, unsigned *mode)\n> +int get_tree_entry_gently(const struct object_id *tree_oid, const char *name,\n> +\t\t\t  struct object_id *oid, unsigned *mode, int flags)\n>  {\n>  \tint retval;\n>  \tvoid *tree;\n>  \tunsigned long size;\n>  \tstruct object_id root;\n>  \n> -\ttree = read_object_with_reference(tree_oid, tree_type, &size, &root);\n> +\tif (!(flags & GET_OID_GENTLY)) {\n> +\t\ttree = read_object_with_reference(tree_oid, tree_type, &size, &root);\n> +\t} else {\n> +\t\tstruct object_info oi = OBJECT_INFO_INIT;\n> +\n> +\t\toi.contentp = tree;\n> +\t\tif (oid_object_info_extended(the_repository, tree_oid, &oi, 0) < 0)\n> +\t\t\treturn -1;\n> +\t}\n>  \tif (!tree)\n>  \t\treturn -1;\n>  \n> @@ -547,13 +562,27 @@ int get_tree_entry(const struct object_id *tree_oid, const char *name, struct ob\n>  \t\tretval = -1;\n>  \t} else {\n>  \t\tstruct tree_desc t;\n> -\t\tinit_tree_desc(&t, tree, size);\n> -\t\tretval = find_tree_entry(&t, name, oid, mode);\n> +\t\tif (!(flags & GET_OID_GENTLY)) {\n> +\t\t\tinit_tree_desc(&t, tree, size);\n> +\t\t} else {\n> +\t\t\tif (init_tree_desc_gently(&t, tree, size)) {\n> +\t\t\t\tretval = -1;\n> +\t\t\t\tgoto done;\n> +\t\t\t}\n> +\t\t}\n> +\t\tretval = find_tree_entry(&t, name, oid, mode, flags);\n>  \t}\n> +done:\n>  \tfree(tree);\n>  \treturn retval;\n>  }\n>  \n> +int get_tree_entry(const struct object_id *tree_oid, const char *name,\n> +\t\t   struct object_id *oid, unsigned *mode)\n> +{\n> +\treturn get_tree_entry_gently(tree_oid, name, oid, mode, 0);\n> +}\n> +\n>  /*\n>   * This is Linux's built-in max for the number of symlinks to follow.\n>   * That limit, of course, does not affect git, but it's a reasonable\n> @@ -576,7 +605,7 @@ int get_tree_entry(const struct object_id *tree_oid, const char *name, struct ob\n>   * See the code for enum follow_symlink_result for a description of\n>   * the return values.\n>   */\n> -enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode)\n> +enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode, int flags)\n>  {\n>  \tint retval = MISSING_OBJECT;\n>  \tstruct dir_state *parents = NULL;\n> @@ -600,9 +629,21 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n>  \t\t\tvoid *tree;\n>  \t\t\tstruct object_id root;\n>  \t\t\tunsigned long size;\n> -\t\t\ttree = read_object_with_reference(&current_tree_oid,\n> -\t\t\t\t\t\t\t  tree_type, &size,\n> -\t\t\t\t\t\t\t  &root);\n> +\t\t\tif (!(flags & GET_OID_GENTLY)) {\n> +\t\t\t\ttree = read_object_with_reference(&current_tree_oid,\n> +\t\t\t\t\t\t\t\t  tree_type, &size,\n> +\t\t\t\t\t\t\t\t  &root);\n> +\t\t\t} else {\n> +\t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n> +\n> +\t\t\t\toi.contentp = tree;\n> +\t\t\t\tif (oid_object_info_extended(the_repository,\n> +\t\t\t\t    &current_tree_oid, &oi, 0) < 0) {\n> +\t\t\t\t\tretval = MISSING_OBJECT;\n> +\t\t\t\t\tgoto done;\n> +\t\t\t\t}\n> +\t\t\t}\n> +\n>  \t\t\tif (!tree)\n>  \t\t\t\tgoto done;\n>  \n> @@ -622,7 +663,14 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n>  \t\t\t\tgoto done;\n>  \n>  \t\t\t/* descend */\n> -\t\t\tinit_tree_desc(&t, tree, size);\n> +\t\t\tif (!(flags & GET_OID_GENTLY)) {\n> +\t\t\t\tinit_tree_desc(&t, tree, size);\n> +\t\t\t} else {\n> +\t\t\t\tif (init_tree_desc_gently(&t, tree, size)) {\n> +\t\t\t\t\tretval = MISSING_OBJECT;\n> +\t\t\t\t\tgoto done;\n> +\t\t\t\t}\n> +\t\t\t}\n>  \t\t}\n>  \n>  \t\t/* Handle symlinks to e.g. a//b by removing leading slashes */\n> @@ -656,7 +704,15 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n>  \t\t\tfree(parent->tree);\n>  \t\t\tparents_nr--;\n>  \t\t\tparent = &parents[parents_nr - 1];\n> -\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n> +\t\t\tif (!(flags & GET_OID_GENTLY)) {\n> +\t\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n> +\t\t\t} else {\n> +\t\t\t\tif (init_tree_desc_gently(&t, parent->tree,\n> +\t\t\t\t    parent->size)) {\n> +\t\t\t\t\tretval = MISSING_OBJECT;\n> +\t\t\t\t\tgoto done;\n> +\t\t\t\t}\n> +\t\t\t}\n>  \t\t\tstrbuf_remove(&namebuf, 0, remainder ? 3 : 2);\n>  \t\t\tcontinue;\n>  \t\t}\n> @@ -670,7 +726,7 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n>  \n>  \t\t/* Look up the first (or only) path component in the tree. */\n>  \t\tfind_result = find_tree_entry(&t, namebuf.buf,\n> -\t\t\t\t\t      &current_tree_oid, mode);\n> +\t\t\t\t\t      &current_tree_oid, mode, flags);\n>  \t\tif (find_result) {\n>  \t\t\tgoto done;\n>  \t\t}\n> @@ -713,8 +769,19 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n>  \t\t\t */\n>  \t\t\tretval = DANGLING_SYMLINK;\n>  \n> -\t\t\tcontents = read_object_file(&current_tree_oid, &type,\n> -\t\t\t\t\t\t    &link_len);\n> +\t\t\tif (!(flags & GET_OID_GENTLY)) {\n> +\t\t\t\tcontents = read_object_file(&current_tree_oid,\n> +\t\t\t\t\t\t\t    &type, &link_len);\n> +\t\t\t} else {\n> +\t\t\t\tstruct object_info oi = OBJECT_INFO_INIT;\n> +\t\t\t\toi.contentp = (void*) contents;\n> +\n> +\t\t\t\tif (oid_object_info_extended(the_repository,\n> +\t\t\t\t    &current_tree_oid, &oi, 0) < 0) {\n> +\t\t\t\t\tretval = MISSING_OBJECT;\n> +\t\t\t\t\tgoto done;\n> +\t\t\t\t}\n> +\t\t\t}\n>  \n>  \t\t\tif (!contents)\n>  \t\t\t\tgoto done;\n> @@ -735,7 +802,14 @@ enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tre\n>  \t\t\tcontents_start = contents;\n>  \n>  \t\t\tparent = &parents[parents_nr - 1];\n> -\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n> +\t\t\tif (!(flags & GET_OID_GENTLY)) {\n> +\t\t\t\tinit_tree_desc(&t, parent->tree, parent->size);\n> +\t\t\t} else {\n> +\t\t\t\tif (init_tree_desc_gently(&t, parent->tree, parent->size)) {\n> +\t\t\t\t\tretval = MISSING_OBJECT;\n> +\t\t\t\t\tgoto done;\n> +\t\t\t\t}\n> +\t\t\t}\n>  \t\t\tstrbuf_splice(&namebuf, 0, len,\n>  \t\t\t\t      contents_start, link_len);\n>  \t\t\tif (remainder)\n> diff --git a/tree-walk.h b/tree-walk.h\n> index 805f58f00..6f043af6e 100644\n> --- a/tree-walk.h\n> +++ b/tree-walk.h\n> @@ -64,7 +64,7 @@ enum follow_symlinks_result {\n>  \t\t       */\n>  };\n>  \n> -enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode);\n> +enum follow_symlinks_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode, int flags);\n>  \n>  struct traverse_info {\n>  \tconst char *traverse_path;\n> @@ -79,6 +79,7 @@ struct traverse_info {\n>  \tint show_all_errors;\n>  };\n>  \n> +int get_tree_entry_gently(const struct object_id *, const char *, struct object_id *, unsigned *, int);\n>  int get_tree_entry(const struct object_id *, const char *, struct object_id *, unsigned *);\n>  extern char *make_traverse_path(char *path, const struct traverse_info *info, const struct name_entry *n);\n>  extern void setup_traverse_info(struct traverse_info *info, const char *base);\n"},{"id":"352819","messageId":"xmqqefg1oeuk.fsf@gitster-ct.c.googlers.com","threadId":"48896","inReplyTo":"dc1abfca46cd536f060b9097b9f2d1a64988f932.1531778417.git.ungureanupaulsebastian@gmail.com","subject":"Re: [RFC PATCH 5/6] sha1-name: Teach `get_oid_with_context[_1]()` to be gentle","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-07-17T19:13:23Z","receivedAt":"2018-07-17T19:13:27Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Paul-Sebastian Ungureanu <ungureanupaulsebastian@gmail.com> writes:\n\n> @@ -1769,7 +1831,8 @@ void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)\n>  \n>  int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc)\n>  {\n> -\tif (flags & GET_OID_FOLLOW_SYMLINKS && flags & GET_OID_ONLY_TO_DIE)\n> +\tif (flags & (GET_OID_FOLLOW_SYMLINKS | GET_OID_GENTLY) &&\n> +\t    flags & GET_OID_ONLY_TO_DIE)\n>  \t\tBUG(\"incompatible flags for get_sha1_with_context\");\n>  \treturn get_oid_with_context_1(str, flags, NULL, oid, oc);\n>  }\n\nThis points us back to \"only-to-die\" which was \"gently\" before\n2e83b66c (\"fix overslow :/no-such-string-ever-existed diagnostics\",\n2011-05-10).  I think we have to keep them both, as only-to-die\nmeans more than just being not gentle, and we cannot revert the\nrenaming s/!gently/only-to-die/ done by 2e83b66c and teach GENTLY to\nmore codepaths, I think.  But I might be mistaken and we may be able\nto get rid of only-to-die at the end of this series.  I dunno.\n\nIn any case, what's the reason why this new \"gentle\" option is\nincompatible with \"only-to-die\"?\n"},{"id":"353002","messageId":"8ebfad3c-7009-d0cc-2ef8-54ebac6783f9@gmail.com","threadId":"48896","inReplyTo":"CACsJy8AEDmyg1XpgXc5KgKdG33t2SeOHw56tEgL_VVXh1Bcprg@mail.gmail.com","subject":"Re: [RFC PATCH 0/6] Add gentle alternative for `get_oid()`","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-18T23:03:29Z","receivedAt":"2018-07-18T23:03:33Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"Hello,\n\nOn 17.07.2018 20:45, Duy Nguyen wrote:\n> Since get_oid() callers must handle failure when it returns non-zero,\n> I would say \"gently\" is already implied by get_oid() and we could just\n> convert those die() to error() or warning(). Unless some of those\n> die() are very special that we need to choose which call sites should\n> go \"even gentler\" where some sites should still die()?\n\nOf course, \"gently\" is already implied by `get_oid()` to some extent.\n\n From the beginning I tried to follow the safer method to do that.\nChanging `die()` into `error()` or `warning()` and handling the\nerror in the caller function not only would mean a harder patch\nto read, but could also introduce some regressions since some of\nthe functions in the call graph of `get_oid()` are used by other\nfunctions as well.\n\nI think that it might be a good idea, but I am not entirely sure.\nThe codebase is pretty complex and this might make it harder to\nfollow. I am not able to give a clear answer, but thank you for\ntaking time to look over these patches!\n\nBest,\nPaul\n"},{"id":"353003","messageId":"ba38bdd0-c1c3-cded-0e18-f21e0d7fd9a8@gmail.com","threadId":"48896","inReplyTo":"xmqqin5dofor.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC PATCH 2/6] tree-walk: Add three new gentle helpers","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-18T23:11:49Z","receivedAt":"2018-07-18T23:11:54Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"Hello,\n\nOn 17.07.2018 21:55, Junio C Hamano wrote:\n> I wonder if the GENTLY option should apply to update_tree_entry()\n> the same way as it would to the other codepaths that currently die\n> to express \"we were handed this string by the caller and told to\n> give back object ID the string represents, and we found no good\n> answer\".  In this one (and the \"bad ref\" one), the existing failures\n> in these two codepaths are not \"we got a string and that does not\n> resolve to an object name\", but \"we didn't have the data to work on\n> to begin with (either a corrupt tree object or a corrupt ref\").\n> \n> In other words, it's not like \"We were given HEAD:no-such-path and\n> there is no such path in that tree\"; it is \"We tried to read HEAD:\n> tree for no-such-path in it, but the tree was corrupt and we couldn't\n> even tell if such a path is or is not in it\", no?\n\nI can definitely say there is a clear difference between these\ntwo cases, but I am not entirely sure how `GENTLY` should apply to\n`update_tree_entry()`.\n\nOn one side, even before this patch, there was the gentle version\nof this function, `update_tree_entry_gently()`, which could still die.\nAnd it makes sense. It should be ok to call `die()` when there was\ndetected a \"bigger\" issue.\n\nOn the other side, in some cases like `read_ref_at()` I think that it\ncould be useful if the caller could handle any error (which is what \npatches 3/6 and 4/6 try to accomplish).\n\nI really do not know which way would be the best in this particular case.\n\nBest,\nPaul\n"},{"id":"353005","messageId":"2763ef16-cbbd-e371-4522-9948a1f05812@gmail.com","threadId":"48896","inReplyTo":"xmqqefg1oeuk.fsf@gitster-ct.c.googlers.com","subject":"Re: [RFC PATCH 5/6] sha1-name: Teach `get_oid_with_context[_1]()` to be gentle","fromName":"Paul-Sebastian Ungureanu","fromEmail":"ungureanupaulsebastian@gmail.com","sentAt":"2018-07-18T23:14:17Z","receivedAt":"2018-07-18T23:14:21Z","isPatch":true,"sender":{"key":"ungureanupaulsebastian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/24317622?v=4"},"body":"Hello,\n\n> This points us back to \"only-to-die\" which was \"gently\" before\n> 2e83b66c (\"fix overslow :/no-such-string-ever-existed diagnostics\",\n> 2011-05-10).  I think we have to keep them both, as only-to-die\n> means more than just being not gentle, and we cannot revert the\n> renaming s/!gently/only-to-die/ done by 2e83b66c and teach GENTLY to\n> more codepaths, I think.  But I might be mistaken and we may be able\n> to get rid of only-to-die at the end of this series.  I dunno.\n> \n> In any case, what's the reason why this new \"gentle\" option is\n> incompatible with \"only-to-die\"?\n\n\"GET_OID_GENTLY\" would be used in the case we want to handle\nfatal errors, while \"GET_OID_ONLY_TO_DIE\" means that if\nthere is any fatal error, we can just exit. They are not compatible\nbecause that would mean that if there is any fatal error, the\nprogram should die and not die at the same time.\n\nThank you for taking time to look over these patches!\n\nBest,\nPaul\n"}]}