diff-index.c: "git diff" has no need to read blob from the standard input

Only "diff --no-index -" does. Bolting the logic into the low-level function diff_populate_filespec() was a layering violation from day one. Move populate_from_stdin() function out of the generic diff.c to its only user, diff-index.c. Also make sure "-" from the command line stays a special token "read from the standard input", even if we later decide to sanitize the result from prefix_filename() function in a few obvious ways, e.g. removing unnecessary "./" prefix, duplicated slashes "//" in the middle, etc. Signed-off-by: Junio C Hamano <gitster@pobox.com>

Junio C Hamano committed Jun 27, 2012 at 20:14 UTC 4682d8521c3ce9d722bd214fd7d5fc92063fdacb
4 files changed +55 -31
diff-no-index.c
+41 -11
@@ -32,6 +32,13 @@ static int read_directory(const char *path, struct string_list *list)
32 return 0;
33 }
34
35 +/*
36 + * This should be "(standard input)" or something, but it will
37 + * probably expose many more breakages in the way no-index code
38 + * is bolted onto the diff callchain.
39 + */
40 +static const char file_from_standard_input[] = "-";
41 +
42 static int get_mode(const char *path, int *mode)
43 {
44 struct stat st;
@@ -42,7 +49,7 @@ static int get_mode(const char *path, int *mode)
49 else if (!strcasecmp(path, "nul"))
50 *mode = 0;
51 #endif
45 - else if (!strcmp(path, "-"))
52 + else if (path == file_from_standard_input)
53 *mode = create_ce_mode(0666);
54 else if (lstat(path, &st))
55 return error("Could not access '%s'", path);
@@ -51,6 +58,36 @@ static int get_mode(const char *path, int *mode)
58 return 0;
59 }
60
61 +static int populate_from_stdin(struct diff_filespec *s)
62 +{
63 + struct strbuf buf = STRBUF_INIT;
64 + size_t size = 0;
65 +
66 + if (strbuf_read(&buf, 0, 0) < 0)
67 + return error("error while reading from stdin %s",
68 + strerror(errno));
69 +
70 + s->should_munmap = 0;
71 + s->data = strbuf_detach(&buf, &size);
72 + s->size = size;
73 + s->should_free = 1;
74 + s->is_stdin = 1;
75 + return 0;
76 +}
77 +
78 +static struct diff_filespec *noindex_filespec(const char *name, int mode)
79 +{
80 + struct diff_filespec *s;
81 +
82 + if (!name)
83 + name = "/dev/null";
84 + s = alloc_filespec(name);
85 + fill_filespec(s, null_sha1, mode);
86 + if (name == file_from_standard_input)
87 + populate_from_stdin(s);
88 + return s;
89 +}
90 +
91 static int queue_diff(struct diff_options *o,
92 const char *name1, const char *name2)
93 {
@@ -135,15 +172,8 @@ static int queue_diff(struct diff_options *o,
172 tmp_c = name1; name1 = name2; name2 = tmp_c;
173 }
174
138 - if (!name1)
139 - name1 = "/dev/null";
140 - if (!name2)
141 - name2 = "/dev/null";
142 - d1 = alloc_filespec(name1);
143 - d2 = alloc_filespec(name2);
144 - fill_filespec(d1, null_sha1, mode1);
145 - fill_filespec(d2, null_sha1, mode2);
146 -
175 + d1 = noindex_filespec(name1, mode1);
176 + d2 = noindex_filespec(name2, mode2);
177 diff_queue(&diff_queued_diff, d1, d2);
178 return 0;
179 }
@@ -238,7 +268,7 @@ void diff_no_index(struct rev_info *revs,
268 * stdin should be spelled as "-"; if you have
269 * path that is "-", spell it as "./-".
270 */
241 - p = p;
271 + p = file_from_standard_input;
272 else if (prefixlen)
273 p = xstrdup(prefix_filename(prefix, prefixlen, p));
274 paths[i] = p;
diff.c
+1 -20
@@ -2426,22 +2426,6 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
2426 return 0;
2427 }
2428
2429 -static int populate_from_stdin(struct diff_filespec *s)
2430 -{
2431 - struct strbuf buf = STRBUF_INIT;
2432 - size_t size = 0;
2433 -
2434 - if (strbuf_read(&buf, 0, 0) < 0)
2435 - return error("error while reading from stdin %s",
2436 - strerror(errno));
2437 -
2438 - s->should_munmap = 0;
2439 - s->data = strbuf_detach(&buf, &size);
2440 - s->size = size;
2441 - s->should_free = 1;
2442 - return 0;
2443 -}
2444 -
2429 static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
2430 {
2431 int len;
@@ -2491,9 +2475,6 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
2475 struct stat st;
2476 int fd;
2477
2494 - if (!strcmp(s->path, "-"))
2495 - return populate_from_stdin(s);
2496 -
2478 if (lstat(s->path, &st) < 0) {
2479 if (errno == ENOENT) {
2480 err_empty:
@@ -2855,7 +2836,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
2836 if (DIFF_FILE_VALID(one)) {
2837 if (!one->sha1_valid) {
2838 struct stat st;
2858 - if (!strcmp(one->path, "-")) {
2839 + if (one->is_stdin) {
2840 hashcpy(one->sha1, null_sha1);
2841 return;
2842 }
diffcore.h
+1
@@ -43,6 +43,7 @@ struct diff_filespec {
43 unsigned should_free : 1; /* data should be free()'ed */
44 unsigned should_munmap : 1; /* data should be munmap()'ed */
45 unsigned dirty_submodule : 2; /* For submodules: its work tree is dirty */
46 + unsigned is_stdin : 1;
47 #define DIRTY_SUBMODULE_UNTRACKED 1
48 #define DIRTY_SUBMODULE_MODIFIED 2
49
t/t7501-commit.sh
+12
@@ -458,4 +458,16 @@ test_expect_success 'amend can copy notes' '
458
459 '
460
461 +test_expect_success 'commit a file whose name is a dash' '
462 + git reset --hard &&
463 + for i in 1 2 3 4 5
464 + do
465 + echo $i
466 + done >./- &&
467 + git add ./- &&
468 + test_tick &&
469 + git commit -m "add dash" >output </dev/null &&
470 + test_i18ngrep " changed, 5 insertions" output
471 +'
472 +
473 test_done