Let's try this version. On Fri, 2019-01-18 at 10:45 +0000, Eric Wong wrote: > David Turner <novalis@xxxxxxxxxxx> wrote: > > It appears that get_oid_with_context calls into get_short_oid for > > that > > case, and get_short_oid returns SHORT_NAME_AMBIGUOUS, which is > > -2. We > > treat that as DANGLING_SYMLINK, which also seems to have the value > > -2. > > So, it's an ambiguity in ambiguity resolution. > > > > Fix attached. > > Thanks for the quick response. Unfortunately, the patch makes > the situation worse for me... > > > diff --git a/builtin/cat-file.c b/builtin/cat-file.c > > index 2ca56fd086..f2344b199f 100644 > > --- a/builtin/cat-file.c > > +++ b/builtin/cat-file.c > > @@ -380,7 +380,7 @@ static void batch_one_object(const char > > *obj_name, > > { > > struct object_context ctx; > > int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0; > > - enum follow_symlinks_result result; > > + enum get_oid_result result; > > > > result = get_oid_with_context(obj_name, flags, &data->oid, > > &ctx); > > if (result != FOUND) { > > @@ -388,6 +388,9 @@ static void batch_one_object(const char > > *obj_name, > > case MISSING_OBJECT: > > printf("%s missing\n", obj_name); > > break; > > + case SHORT_NAME_AMBIGUOUS: > > + /* We've already printed the ambiguous message > > */ > > + break; > > Because the message about ambiguity only goes to stderr. > Something needs to go to stdout, or else the reader process > would hang forever. > > I've already updated my code[1] to work around "dangling", > but maybe printing "ambiguous" similar to the "missing" message > would be appropriate? Something like: > > case SHORT_NAME_AMBIGUOUS: > printf("%s ambiguous\n", obj_name); > break; > > (Along with a manpage update) > > > [1] new stuff for public-inbox on the way :> >
From b152b3463477a8260d2b8c0ab46ad76562feed37 Mon Sep 17 00:00:00 2001 From: David Turner <novalis@xxxxxxxxxxx> Date: Thu, 17 Jan 2019 23:19:43 -0500 Subject: [PATCH v2] Do not print 'dangling' for cat-file in case of ambiguity The return values -1 and -2 from get_oid could mean two different things, depending on whether they were from an enum returned by get_tree_entry_follow_symlinks, or from a different code path. This caused 'dangling' to be printed from a git cat-file in the case of an ambiguous (-2) result. Unify the results of get_oid* and get_tree_entry_follow_symlinks to be one common type, with unambiguous values. Signed-off-by: David Turner <novalis@xxxxxxxxxxx> Reported-by: Eric Wong <e@xxxxxxxxx> --- Documentation/git-cat-file.txt | 6 ++++ builtin/cat-file.c | 5 ++- cache.h | 20 +++++++++++- sha1-name.c | 58 ++++++++++++++++++---------------- tree-walk.c | 4 +-- tree-walk.h | 18 +---------- 6 files changed, 62 insertions(+), 49 deletions(-) diff --git a/Documentation/git-cat-file.txt b/Documentation/git-cat-file.txt index 74013335a1..e27a940985 100644 --- a/Documentation/git-cat-file.txt +++ b/Documentation/git-cat-file.txt @@ -252,6 +252,12 @@ the repository, then `cat-file` will ignore any custom format and print: <object> SP missing LF ------------ +If a name is specified that might refer to more than one object (an ambiguous short sha), then `cat-file` will ignore any custom format and print: + +------------ +<object> SP ambiguous LF +------------ + If --follow-symlinks is used, and a symlink in the repository points outside the repository, then `cat-file` will ignore any custom format and print: diff --git a/builtin/cat-file.c b/builtin/cat-file.c index 2ca56fd086..cebc6d7f8a 100644 --- a/builtin/cat-file.c +++ b/builtin/cat-file.c @@ -380,7 +380,7 @@ static void batch_one_object(const char *obj_name, { struct object_context ctx; int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0; - enum follow_symlinks_result result; + enum get_oid_result result; result = get_oid_with_context(obj_name, flags, &data->oid, &ctx); if (result != FOUND) { @@ -388,6 +388,9 @@ static void batch_one_object(const char *obj_name, case MISSING_OBJECT: printf("%s missing\n", obj_name); break; + case SHORT_NAME_AMBIGUOUS: + printf("%s ambiguous\n", obj_name); + break; case DANGLING_SYMLINK: printf("dangling %"PRIuMAX"\n%s\n", (uintmax_t)strlen(obj_name), obj_name); diff --git a/cache.h b/cache.h index 49713cc5a5..70652e99dc 100644 --- a/cache.h +++ b/cache.h @@ -1332,6 +1332,24 @@ struct object_context { GET_OID_TREE | GET_OID_TREEISH | \ GET_OID_BLOB) +enum get_oid_result { + FOUND = 0, + MISSING_OBJECT = -1, /* The requested object is missing */ + SHORT_NAME_AMBIGUOUS = -2, + /* The following only apply when symlinks are followed */ + DANGLING_SYMLINK = -4, /* + * The initial symlink is there, but + * (transitively) points to a missing + * in-tree file + */ + SYMLINK_LOOP = -5, + NOT_DIR = -6, /* + * Somewhere along the symlink chain, a path is + * requested which contains a file as a + * non-final element. + */ +}; + extern int get_oid(const char *str, struct object_id *oid); extern int get_oid_commit(const char *str, struct object_id *oid); extern int get_oid_committish(const char *str, struct object_id *oid); @@ -1339,7 +1357,7 @@ extern int get_oid_tree(const char *str, struct object_id *oid); extern int get_oid_treeish(const char *str, struct object_id *oid); extern int get_oid_blob(const char *str, struct object_id *oid); extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix); -extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc); +extern enum get_oid_result get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc); typedef int each_abbrev_fn(const struct object_id *oid, void *); diff --git a/sha1-name.c b/sha1-name.c index b24502811b..12313165d0 100644 --- a/sha1-name.c +++ b/sha1-name.c @@ -190,9 +190,6 @@ static void find_short_packed_object(struct disambiguate_state *ds) unique_in_pack(p, ds); } -#define SHORT_NAME_NOT_FOUND (-1) -#define SHORT_NAME_AMBIGUOUS (-2) - static int finish_object_disambiguation(struct disambiguate_state *ds, struct object_id *oid) { @@ -200,7 +197,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds, return SHORT_NAME_AMBIGUOUS; if (!ds->candidate_exists) - return SHORT_NAME_NOT_FOUND; + return MISSING_OBJECT; if (!ds->candidate_checked) /* @@ -414,8 +411,9 @@ static int sort_ambiguous(const void *a, const void *b) return a_type_sort > b_type_sort ? 1 : -1; } -static int get_short_oid(const char *name, int len, struct object_id *oid, - unsigned flags) +static enum get_oid_result get_short_oid(const char *name, int len, + struct object_id *oid, + unsigned flags) { int status; struct disambiguate_state ds; @@ -733,7 +731,7 @@ static inline int push_mark(const char *string, int len) return at_mark(string, len, suffix, ARRAY_SIZE(suffix)); } -static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags); +static enum get_oid_result get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags); static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf); static int get_oid_basic(const char *str, int len, struct object_id *oid, @@ -883,11 +881,12 @@ static int get_oid_basic(const char *str, int len, struct object_id *oid, return 0; } -static int get_parent(const char *name, int len, - struct object_id *result, int idx) +static enum get_oid_result get_parent(const char *name, int len, + struct object_id *result, int idx) { struct object_id oid; - int ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH); + enum get_oid_result ret = get_oid_1(name, len, &oid, + GET_OID_COMMITTISH); struct commit *commit; struct commit_list *p; @@ -895,24 +894,25 @@ static int get_parent(const char *name, int len, return ret; commit = lookup_commit_reference(the_repository, &oid); if (parse_commit(commit)) - return -1; + return MISSING_OBJECT; if (!idx) { oidcpy(result, &commit->object.oid); - return 0; + return FOUND; } p = commit->parents; while (p) { if (!--idx) { oidcpy(result, &p->item->object.oid); - return 0; + return FOUND; } p = p->next; } - return -1; + return MISSING_OBJECT; } -static int get_nth_ancestor(const char *name, int len, - struct object_id *result, int generation) +static enum get_oid_result get_nth_ancestor(const char *name, int len, + struct object_id *result, + int generation) { struct object_id oid; struct commit *commit; @@ -923,15 +923,15 @@ static int get_nth_ancestor(const char *name, int len, return ret; commit = lookup_commit_reference(the_repository, &oid); if (!commit) - return -1; + return MISSING_OBJECT; while (generation--) { if (parse_commit(commit) || !commit->parents) - return -1; + return MISSING_OBJECT; commit = commit->parents->item; } oidcpy(result, &commit->object.oid); - return 0; + return FOUND; } struct object *peel_to_type(const char *name, int namelen, @@ -1077,7 +1077,9 @@ static int get_describe_name(const char *name, int len, struct object_id *oid) return -1; } -static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags) +static enum get_oid_result get_oid_1(const char *name, int len, + struct object_id *oid, + unsigned lookup_flags) { int ret, has_suffix; const char *cp; @@ -1111,16 +1113,16 @@ static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned ret = peel_onion(name, len, oid, lookup_flags); if (!ret) - return 0; + return FOUND; ret = get_oid_basic(name, len, oid, lookup_flags); if (!ret) - return 0; + return FOUND; /* It could be describe output that is "SOMETHING-gXXXX" */ ret = get_describe_name(name, len, oid); if (!ret) - return 0; + return FOUND; return get_short_oid(name, len, oid, lookup_flags); } @@ -1664,11 +1666,11 @@ static char *resolve_relative_path(const char *rel) rel); } -static int get_oid_with_context_1(const char *name, - unsigned flags, - const char *prefix, - struct object_id *oid, - struct object_context *oc) +static enum get_oid_result get_oid_with_context_1(const char *name, + unsigned flags, + const char *prefix, + struct object_id *oid, + struct object_context *oc) { int ret, bracket_depth; int namelen = strlen(name); diff --git a/tree-walk.c b/tree-walk.c index 08210a4109..fb7959b21d 100644 --- a/tree-walk.c +++ b/tree-walk.c @@ -579,10 +579,10 @@ int get_tree_entry(const struct object_id *tree_oid, const char *name, struct ob * with the sha1 of the found object, and *mode will hold the mode of * the object. * - * See the code for enum follow_symlink_result for a description of + * See the code for enum get_oid_result for a description of * the return values. */ -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) +enum get_oid_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 retval = MISSING_OBJECT; struct dir_state *parents = NULL; diff --git a/tree-walk.h b/tree-walk.h index eefd26bb62..de6b95179d 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -51,23 +51,7 @@ struct traverse_info; typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *); int traverse_trees(struct index_state *istate, int n, struct tree_desc *t, struct traverse_info *info); -enum follow_symlinks_result { - FOUND = 0, /* This includes out-of-tree links */ - MISSING_OBJECT = -1, /* The initial symlink is missing */ - DANGLING_SYMLINK = -2, /* - * The initial symlink is there, but - * (transitively) points to a missing - * in-tree file - */ - SYMLINK_LOOP = -3, - NOT_DIR = -4, /* - * Somewhere along the symlink chain, a path is - * requested which contains a file as a - * non-final element. - */ -}; - -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); +enum get_oid_result get_tree_entry_follow_symlinks(struct object_id *tree_oid, const char *name, struct object_id *result, struct strbuf *result_path, unsigned *mode); struct traverse_info { const char *traverse_path; -- 2.19.1