verify_filename(): ask the caller to chose the kind of diagnosis

verify_filename() can be called in two different contexts. Either we just tried to interpret a string as an object name, and it fails, so we try looking for a working tree file (i.e. we finished looking at revs that come earlier on the command line, and the next argument must be a pathname), or we _know_ that we are looking for a pathname, and shouldn't even try interpreting the string as an object name. For example, with this change, we get: $ git log COPYING HEAD:inexistant fatal: HEAD:inexistant: no such path in the working tree. Use '-- <path>...' to specify paths that do not exist locally. $ git log HEAD:inexistant fatal: Path 'inexistant' does not exist in 'HEAD' Signed-off-by: Matthieu Moy <Matthieu.Moy@imag.fr> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Matthieu Moy committed Jun 18, 2012 at 20:18 UTC 023e37c37780d6a56f2870a979c8eb3a9ee9a44d
7 files changed +33 -10
builtin/grep.c
+1 -1
@@ -1045,7 +1045,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)
1045 if (!seen_dashdash) {
1046 int j;
1047 for (j = i; j < argc; j++)
1048 - verify_filename(prefix, argv[j]);
1048 + verify_filename(prefix, argv[j], j == i);
1049 }
1050
1051 paths = get_pathspec(prefix, argv + i);
builtin/reset.c
+1 -1
@@ -285,7 +285,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)
285 rev = argv[i++];
286 } else {
287 /* Otherwise we treat this as a filename */
288 - verify_filename(prefix, argv[i]);
288 + verify_filename(prefix, argv[i], 1);
289 }
290 }
291
builtin/rev-parse.c
+2 -2
@@ -486,7 +486,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
486
487 if (as_is) {
488 if (show_file(arg) && as_is < 2)
489 - verify_filename(prefix, arg);
489 + verify_filename(prefix, arg, 0);
490 continue;
491 }
492 if (!strcmp(arg,"-n")) {
@@ -732,7 +732,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
732 as_is = 1;
733 if (!show_file(arg))
734 continue;
735 - verify_filename(prefix, arg);
735 + verify_filename(prefix, arg, 1);
736 }
737 if (verify) {
738 if (revs_count == 1) {
cache.h
+3 -1
@@ -452,7 +452,9 @@ extern const char *setup_git_directory(void);
452 extern char *prefix_path(const char *prefix, int len, const char *path);
453 extern const char *prefix_filename(const char *prefix, int len, const char *path);
454 extern int check_filename(const char *prefix, const char *name);
455 -extern void verify_filename(const char *prefix, const char *name);
455 +extern void verify_filename(const char *prefix,
456 + const char *name,
457 + int diagnose_misspelt_rev);
458 extern void verify_non_filename(const char *prefix, const char *name);
459
460 #define INIT_DB_QUIET 0x0001
revision.c
+1 -1
@@ -1755,7 +1755,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s
1755 * but the latter we have checked in the main loop.
1756 */
1757 for (j = i; j < argc; j++)
1758 - verify_filename(revs->prefix, argv[j]);
1758 + verify_filename(revs->prefix, argv[j], j == i);
1759
1760 append_prune_data(&prune_data, argv + i);
1761 break;
setup.c
+24 -3
@@ -53,11 +53,17 @@ int check_filename(const char *prefix, const char *arg)
53 die_errno("failed to stat '%s'", arg);
54 }
55
56 -static void NORETURN die_verify_filename(const char *prefix, const char *arg)
56 +static void NORETURN die_verify_filename(const char *prefix,
57 + const char *arg,
58 + int diagnose_misspelt_rev)
59 {
60 unsigned char sha1[20];
61 unsigned mode;
62
63 + if (!diagnose_misspelt_rev)
64 + die("%s: no such path in the working tree.\n"
65 + "Use '-- <path>...' to specify paths that do not exist locally.",
66 + arg);
67 /*
68 * Saying "'(icase)foo' does not exist in the index" when the
69 * user gave us ":(icase)foo" is just stupid. A magic pathspec
@@ -80,14 +86,29 @@ static void NORETURN die_verify_filename(const char *prefix, const char *arg)
86 * as true, because even if such a filename were to exist, we want
87 * it to be preceded by the "--" marker (or we want the user to
88 * use a format like "./-filename")
89 + *
90 + * The "diagnose_misspelt_rev" is used to provide a user-friendly
91 + * diagnosis when dying upon finding that "name" is not a pathname.
92 + * If set to 1, the diagnosis will try to diagnose "name" as an
93 + * invalid object name (e.g. HEAD:foo). If set to 0, the diagnosis
94 + * will only complain about an inexisting file.
95 + *
96 + * This function is typically called to check that a "file or rev"
97 + * argument is unambiguous. In this case, the caller will want
98 + * diagnose_misspelt_rev == 1 when verifying the first non-rev
99 + * argument (which could have been a revision), and
100 + * diagnose_misspelt_rev == 0 for the next ones (because we already
101 + * saw a filename, there's not ambiguity anymore).
102 */
84 -void verify_filename(const char *prefix, const char *arg)
103 +void verify_filename(const char *prefix,
104 + const char *arg,
105 + int diagnose_misspelt_rev)
106 {
107 if (*arg == '-')
108 die("bad flag '%s' used after filename", arg);
109 if (check_filename(prefix, arg))
110 return;
90 - die_verify_filename(prefix, arg);
111 + die_verify_filename(prefix, arg, diagnose_misspelt_rev);
112 }
113
114 /*
t/t1506-rev-parse-diagnosis.sh
+1 -1
@@ -174,7 +174,7 @@ test_expect_success 'relative path when startup_info is NULL' '
174 test_expect_success '<commit>:file correctly diagnosed after a pathname' '
175 test_must_fail git rev-parse file.txt HEAD:file.txt 1>actual 2>error &&
176 test_i18ngrep ! "exists on disk" error &&
177 - test_i18ngrep "unknown revision or path not in the working tree" error &&
177 + test_i18ngrep "no such path in the working tree" error &&
178 cat >expect <<-\EOF &&
179 file.txt
180 HEAD:file.txt