Skip to content

Commit 106ef55

Browse files
committed
Merge branch 'jc/refactor-diff-stdin' into maint
"git diff", "git status" and anything that internally uses the comparison machinery was utterly broken when the difference involved a file with "-" as its name. This was due to the way "git diff --no-index" was incorrectly bolted on to the system, making any comparison that involves a file "-" at the root level incorrectly read from the standard input. * jc/refactor-diff-stdin: diff-index.c: "git diff" has no need to read blob from the standard input diff-index.c: unify handling of command line paths diff-index.c: do not pretend paths are pathspecs
2 parents 07873ca + 4682d85 commit 106ef55

File tree

4 files changed

+67
-50
lines changed

4 files changed

+67
-50
lines changed

diff-no-index.c

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ static int read_directory(const char *path, struct string_list *list)
3232
return 0;
3333
}
3434

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+
3542
static int get_mode(const char *path, int *mode)
3643
{
3744
struct stat st;
@@ -42,7 +49,7 @@ static int get_mode(const char *path, int *mode)
4249
else if (!strcasecmp(path, "nul"))
4350
*mode = 0;
4451
#endif
45-
else if (!strcmp(path, "-"))
52+
else if (path == file_from_standard_input)
4653
*mode = create_ce_mode(0666);
4754
else if (lstat(path, &st))
4855
return error("Could not access '%s'", path);
@@ -51,6 +58,36 @@ static int get_mode(const char *path, int *mode)
5158
return 0;
5259
}
5360

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+
5491
static int queue_diff(struct diff_options *o,
5592
const char *name1, const char *name2)
5693
{
@@ -137,15 +174,8 @@ static int queue_diff(struct diff_options *o,
137174
tmp_c = name1; name1 = name2; name2 = tmp_c;
138175
}
139176

140-
if (!name1)
141-
name1 = "/dev/null";
142-
if (!name2)
143-
name2 = "/dev/null";
144-
d1 = alloc_filespec(name1);
145-
d2 = alloc_filespec(name2);
146-
fill_filespec(d1, null_sha1, mode1);
147-
fill_filespec(d2, null_sha1, mode2);
148-
177+
d1 = noindex_filespec(name1, mode1);
178+
d2 = noindex_filespec(name2, mode2);
149179
diff_queue(&diff_queued_diff, d1, d2);
150180
return 0;
151181
}
@@ -155,9 +185,10 @@ void diff_no_index(struct rev_info *revs,
155185
int argc, const char **argv,
156186
int nongit, const char *prefix)
157187
{
158-
int i;
188+
int i, prefixlen;
159189
int no_index = 0;
160190
unsigned options = 0;
191+
const char *paths[2];
161192

162193
/* Were we asked to do --no-index explicitly? */
163194
for (i = 1; i < argc; i++) {
@@ -207,26 +238,19 @@ void diff_no_index(struct rev_info *revs,
207238
}
208239
}
209240

210-
if (prefix) {
211-
int len = strlen(prefix);
212-
const char *paths[3];
213-
memset(paths, 0, sizeof(paths));
214-
215-
for (i = 0; i < 2; i++) {
216-
const char *p = argv[argc - 2 + i];
241+
prefixlen = prefix ? strlen(prefix) : 0;
242+
for (i = 0; i < 2; i++) {
243+
const char *p = argv[argc - 2 + i];
244+
if (!strcmp(p, "-"))
217245
/*
218-
* stdin should be spelled as '-'; if you have
219-
* path that is '-', spell it as ./-.
246+
* stdin should be spelled as "-"; if you have
247+
* path that is "-", spell it as "./-".
220248
*/
221-
p = (strcmp(p, "-")
222-
? xstrdup(prefix_filename(prefix, len, p))
223-
: p);
224-
paths[i] = p;
225-
}
226-
diff_tree_setup_paths(paths, &revs->diffopt);
249+
p = file_from_standard_input;
250+
else if (prefixlen)
251+
p = xstrdup(prefix_filename(prefix, prefixlen, p));
252+
paths[i] = p;
227253
}
228-
else
229-
diff_tree_setup_paths(argv + argc - 2, &revs->diffopt);
230254
revs->diffopt.skip_stat_unmatch = 1;
231255
if (!revs->diffopt.output_format)
232256
revs->diffopt.output_format = DIFF_FORMAT_PATCH;
@@ -240,8 +264,7 @@ void diff_no_index(struct rev_info *revs,
240264
setup_diff_pager(&revs->diffopt);
241265
DIFF_OPT_SET(&revs->diffopt, EXIT_WITH_STATUS);
242266

243-
if (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0],
244-
revs->diffopt.pathspec.raw[1]))
267+
if (queue_diff(&revs->diffopt, paths[0], paths[1]))
245268
exit(1);
246269
diff_set_mnemonic_prefix(&revs->diffopt, "1/", "2/");
247270
diffcore_std(&revs->diffopt);

diff.c

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2619,22 +2619,6 @@ static int reuse_worktree_file(const char *name, const unsigned char *sha1, int
26192619
return 0;
26202620
}
26212621

2622-
static int populate_from_stdin(struct diff_filespec *s)
2623-
{
2624-
struct strbuf buf = STRBUF_INIT;
2625-
size_t size = 0;
2626-
2627-
if (strbuf_read(&buf, 0, 0) < 0)
2628-
return error("error while reading from stdin %s",
2629-
strerror(errno));
2630-
2631-
s->should_munmap = 0;
2632-
s->data = strbuf_detach(&buf, &size);
2633-
s->size = size;
2634-
s->should_free = 1;
2635-
return 0;
2636-
}
2637-
26382622
static int diff_populate_gitlink(struct diff_filespec *s, int size_only)
26392623
{
26402624
int len;
@@ -2684,9 +2668,6 @@ int diff_populate_filespec(struct diff_filespec *s, int size_only)
26842668
struct stat st;
26852669
int fd;
26862670

2687-
if (!strcmp(s->path, "-"))
2688-
return populate_from_stdin(s);
2689-
26902671
if (lstat(s->path, &st) < 0) {
26912672
if (errno == ENOENT) {
26922673
err_empty:
@@ -3048,7 +3029,7 @@ static void diff_fill_sha1_info(struct diff_filespec *one)
30483029
if (DIFF_FILE_VALID(one)) {
30493030
if (!one->sha1_valid) {
30503031
struct stat st;
3051-
if (!strcmp(one->path, "-")) {
3032+
if (one->is_stdin) {
30523033
hashcpy(one->sha1, null_sha1);
30533034
return;
30543035
}

diffcore.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct diff_filespec {
4343
unsigned should_free : 1; /* data should be free()'ed */
4444
unsigned should_munmap : 1; /* data should be munmap()'ed */
4545
unsigned dirty_submodule : 2; /* For submodules: its work tree is dirty */
46+
unsigned is_stdin : 1;
4647
#define DIRTY_SUBMODULE_UNTRACKED 1
4748
#define DIRTY_SUBMODULE_MODIFIED 2
4849
unsigned has_more_entries : 1; /* only appear in combined diff */

t/t7501-commit.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -487,4 +487,16 @@ test_expect_success 'amend can copy notes' '
487487
488488
'
489489

490+
test_expect_success 'commit a file whose name is a dash' '
491+
git reset --hard &&
492+
for i in 1 2 3 4 5
493+
do
494+
echo $i
495+
done >./- &&
496+
git add ./- &&
497+
test_tick &&
498+
git commit -m "add dash" >output </dev/null &&
499+
test_i18ngrep " changed, 5 insertions" output
500+
'
501+
490502
test_done

0 commit comments

Comments
 (0)