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@novalis.org> Reported-by: Eric Wong <e@80x24.org> Signed-off-by: Junio C Hamano <gitster@pobox.com>

David Turner committed Jan 17, 2019 at 23:19 UTC d1dd94b308607d0a37aa8a013fd20678956d3531
6 files changed +62 -49
Documentation/git-cat-file.txt
+6
@@ -252,6 +252,12 @@ the repository, then `cat-file` will ignore any custom format and print:
252 <object> SP missing LF
253 ------------
254
255 +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:
256 +
257 +------------
258 +<object> SP ambiguous LF
259 +------------
260 +
261 If --follow-symlinks is used, and a symlink in the repository points
262 outside the repository, then `cat-file` will ignore any custom format
263 and print:
builtin/cat-file.c
+4 -1
@@ -380,7 +380,7 @@ static void batch_one_object(const char *obj_name,
380 {
381 struct object_context ctx;
382 int flags = opt->follow_symlinks ? GET_OID_FOLLOW_SYMLINKS : 0;
383 - enum follow_symlinks_result result;
383 + enum get_oid_result result;
384
385 result = get_oid_with_context(obj_name, flags, &data->oid, &ctx);
386 if (result != FOUND) {
@@ -388,6 +388,9 @@ static void batch_one_object(const char *obj_name,
388 case MISSING_OBJECT:
389 printf("%s missing\n", obj_name);
390 break;
391 + case SHORT_NAME_AMBIGUOUS:
392 + printf("%s ambiguous\n", obj_name);
393 + break;
394 case DANGLING_SYMLINK:
395 printf("dangling %"PRIuMAX"\n%s\n",
396 (uintmax_t)strlen(obj_name), obj_name);
cache.h
+19 -1
@@ -1332,6 +1332,24 @@ struct object_context {
1332 GET_OID_TREE | GET_OID_TREEISH | \
1333 GET_OID_BLOB)
1334
1335 +enum get_oid_result {
1336 + FOUND = 0,
1337 + MISSING_OBJECT = -1, /* The requested object is missing */
1338 + SHORT_NAME_AMBIGUOUS = -2,
1339 + /* The following only apply when symlinks are followed */
1340 + DANGLING_SYMLINK = -4, /*
1341 + * The initial symlink is there, but
1342 + * (transitively) points to a missing
1343 + * in-tree file
1344 + */
1345 + SYMLINK_LOOP = -5,
1346 + NOT_DIR = -6, /*
1347 + * Somewhere along the symlink chain, a path is
1348 + * requested which contains a file as a
1349 + * non-final element.
1350 + */
1351 +};
1352 +
1353 extern int get_oid(const char *str, struct object_id *oid);
1354 extern int get_oid_commit(const char *str, struct object_id *oid);
1355 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);
1357 extern int get_oid_treeish(const char *str, struct object_id *oid);
1358 extern int get_oid_blob(const char *str, struct object_id *oid);
1359 extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
1342 -extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
1360 +extern enum get_oid_result get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
1361
1362
1363 typedef int each_abbrev_fn(const struct object_id *oid, void *);
sha1-name.c
+30 -28
@@ -190,9 +190,6 @@ static void find_short_packed_object(struct disambiguate_state *ds)
190 unique_in_pack(p, ds);
191 }
192
193 -#define SHORT_NAME_NOT_FOUND (-1)
194 -#define SHORT_NAME_AMBIGUOUS (-2)
195 -
193 static int finish_object_disambiguation(struct disambiguate_state *ds,
194 struct object_id *oid)
195 {
@@ -200,7 +197,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,
197 return SHORT_NAME_AMBIGUOUS;
198
199 if (!ds->candidate_exists)
203 - return SHORT_NAME_NOT_FOUND;
200 + return MISSING_OBJECT;
201
202 if (!ds->candidate_checked)
203 /*
@@ -414,8 +411,9 @@ static int sort_ambiguous(const void *a, const void *b)
411 return a_type_sort > b_type_sort ? 1 : -1;
412 }
413
417 -static int get_short_oid(const char *name, int len, struct object_id *oid,
418 - unsigned flags)
414 +static enum get_oid_result get_short_oid(const char *name, int len,
415 + struct object_id *oid,
416 + unsigned flags)
417 {
418 int status;
419 struct disambiguate_state ds;
@@ -733,7 +731,7 @@ static inline int push_mark(const char *string, int len)
731 return at_mark(string, len, suffix, ARRAY_SIZE(suffix));
732 }
733
736 -static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags);
734 +static enum get_oid_result get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags);
735 static int interpret_nth_prior_checkout(const char *name, int namelen, struct strbuf *buf);
736
737 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,
881 return 0;
882 }
883
886 -static int get_parent(const char *name, int len,
887 - struct object_id *result, int idx)
884 +static enum get_oid_result get_parent(const char *name, int len,
885 + struct object_id *result, int idx)
886 {
887 struct object_id oid;
890 - int ret = get_oid_1(name, len, &oid, GET_OID_COMMITTISH);
888 + enum get_oid_result ret = get_oid_1(name, len, &oid,
889 + GET_OID_COMMITTISH);
890 struct commit *commit;
891 struct commit_list *p;
892
@@ -895,24 +894,25 @@ static int get_parent(const char *name, int len,
894 return ret;
895 commit = lookup_commit_reference(the_repository, &oid);
896 if (parse_commit(commit))
898 - return -1;
897 + return MISSING_OBJECT;
898 if (!idx) {
899 oidcpy(result, &commit->object.oid);
901 - return 0;
900 + return FOUND;
901 }
902 p = commit->parents;
903 while (p) {
904 if (!--idx) {
905 oidcpy(result, &p->item->object.oid);
907 - return 0;
906 + return FOUND;
907 }
908 p = p->next;
909 }
911 - return -1;
910 + return MISSING_OBJECT;
911 }
912
914 -static int get_nth_ancestor(const char *name, int len,
915 - struct object_id *result, int generation)
913 +static enum get_oid_result get_nth_ancestor(const char *name, int len,
914 + struct object_id *result,
915 + int generation)
916 {
917 struct object_id oid;
918 struct commit *commit;
@@ -923,15 +923,15 @@ static int get_nth_ancestor(const char *name, int len,
923 return ret;
924 commit = lookup_commit_reference(the_repository, &oid);
925 if (!commit)
926 - return -1;
926 + return MISSING_OBJECT;
927
928 while (generation--) {
929 if (parse_commit(commit) || !commit->parents)
930 - return -1;
930 + return MISSING_OBJECT;
931 commit = commit->parents->item;
932 }
933 oidcpy(result, &commit->object.oid);
934 - return 0;
934 + return FOUND;
935 }
936
937 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)
1077 return -1;
1078 }
1079
1080 -static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned lookup_flags)
1080 +static enum get_oid_result get_oid_1(const char *name, int len,
1081 + struct object_id *oid,
1082 + unsigned lookup_flags)
1083 {
1084 int ret, has_suffix;
1085 const char *cp;
@@ -1111,16 +1113,16 @@ static int get_oid_1(const char *name, int len, struct object_id *oid, unsigned
1113
1114 ret = peel_onion(name, len, oid, lookup_flags);
1115 if (!ret)
1114 - return 0;
1116 + return FOUND;
1117
1118 ret = get_oid_basic(name, len, oid, lookup_flags);
1119 if (!ret)
1118 - return 0;
1120 + return FOUND;
1121
1122 /* It could be describe output that is "SOMETHING-gXXXX" */
1123 ret = get_describe_name(name, len, oid);
1124 if (!ret)
1123 - return 0;
1125 + return FOUND;
1126
1127 return get_short_oid(name, len, oid, lookup_flags);
1128 }
@@ -1664,11 +1666,11 @@ static char *resolve_relative_path(const char *rel)
1666 rel);
1667 }
1668
1667 -static int get_oid_with_context_1(const char *name,
1668 - unsigned flags,
1669 - const char *prefix,
1670 - struct object_id *oid,
1671 - struct object_context *oc)
1669 +static enum get_oid_result get_oid_with_context_1(const char *name,
1670 + unsigned flags,
1671 + const char *prefix,
1672 + struct object_id *oid,
1673 + struct object_context *oc)
1674 {
1675 int ret, bracket_depth;
1676 int namelen = strlen(name);
tree-walk.c
+2 -2
@@ -579,10 +579,10 @@ int get_tree_entry(const struct object_id *tree_oid, const char *name, struct ob
579 * with the sha1 of the found object, and *mode will hold the mode of
580 * the object.
581 *
582 - * See the code for enum follow_symlink_result for a description of
582 + * See the code for enum get_oid_result for a description of
583 * the return values.
584 */
585 -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)
585 +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)
586 {
587 int retval = MISSING_OBJECT;
588 struct dir_state *parents = NULL;
tree-walk.h
+1 -17
@@ -51,23 +51,7 @@ struct traverse_info;
51 typedef int (*traverse_callback_t)(int n, unsigned long mask, unsigned long dirmask, struct name_entry *entry, struct traverse_info *);
52 int traverse_trees(struct index_state *istate, int n, struct tree_desc *t, struct traverse_info *info);
53
54 -enum follow_symlinks_result {
55 - FOUND = 0, /* This includes out-of-tree links */
56 - MISSING_OBJECT = -1, /* The initial symlink is missing */
57 - DANGLING_SYMLINK = -2, /*
58 - * The initial symlink is there, but
59 - * (transitively) points to a missing
60 - * in-tree file
61 - */
62 - SYMLINK_LOOP = -3,
63 - NOT_DIR = -4, /*
64 - * Somewhere along the symlink chain, a path is
65 - * requested which contains a file as a
66 - * non-final element.
67 - */
68 -};
69 -
70 -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);
54 +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);
55
56 struct traverse_info {
57 const char *traverse_path;