Skip to content

Commit 81e50ea

Browse files
Junio C HamanoLinus Torvalds
authored andcommitted
[PATCH] The diff-raw format updates.
Update the diff-raw format as Linus and I discussed, except that it does not use sequence of underscore '_' letters to express nonexistence. All '0' mode is used for that purpose instead. The new diff-raw format can express rename/copy, and the earlier restriction that -M and -C _must_ be used with the patch format output is no longer necessary. The patch makes -M and -C flags independent of -p flag, so you need to say git-whatchanged -M -p to get the diff/patch format. Updated are both documentations and tests. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
1 parent 38c6f78 commit 81e50ea

16 files changed

+322
-313
lines changed

Documentation/diff-format.txt

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,30 @@ git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]::
1616
git-diff-files [<pattern>...]::
1717
compares the cache and the files on the filesystem.
1818

19-
The following desription uses "old" and "new" to mean those
20-
compared entities.
2119

22-
For files in old but not in new (i.e. removed):
20+
An output line is formatted this way:
2321

24-
-<mode> \t <type> \t <object> \t <path>
22+
':' <mode> ' ' <mode> ' ' <sha1> ' ' <sha1> I <path> I <path> L
2523

26-
For files not in old but in new (i.e. added):
24+
By default, I and L are '\t' and '\n' respectively. When '-z'
25+
flag is in effect, both I and L are '\0'.
2726

28-
+<mode> \t <type> \t <object> \t <path>
27+
In each <mode>, <sha1> and <path> pair, left hand side describes
28+
the left hand side of what is being compared (<tree-ish> in
29+
git-diff-cache, <tree-ish-1> in git-diff-tree, cache contents in
30+
git-diff-files). Non-existence is shown by having 000000 in the
31+
<mode> column. That is, 000000 appears as the first <mode> for
32+
newly created files, and as the second <mode> for deleted files.
2933

30-
For files that differ:
34+
Usually two <path> are the same. When rename/copy detection is
35+
used, however, an "create" and another "delete" records can be
36+
merged into a single record that has two <path>, old name and
37+
new name.
3138

32-
*<old-mode>-><new-mode> \t <type> \t <old-sha1>-><new-sha1> \t <path>
39+
<sha1> is shown as all 0's if new is a file on the filesystem
40+
and it is out of sync with the cache. Example:
3341

34-
<new-sha1> is shown as all 0's if new is a file on the
35-
filesystem and it is out of sync with the cache. Example:
36-
37-
*100644->100644 blob 5be4a4.......->000000....... file.c
42+
:100644 100644 5be4a4...... 000000...... file.c file.c
3843

3944

4045
Generating patches with -p

Documentation/git-diff-cache.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,10 @@ OPTIONS
3434
\0 line termination on output
3535

3636
-M::
37-
Detect renames; implies -p.
37+
Detect renames.
3838

3939
-C::
40-
Detect copies as well as renames; implies -p.
40+
Detect copies as well as renames.
4141

4242
-S<string>::
4343
Look for differences that contains the change in <string>.

Documentation/git-diff-files.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ OPTIONS
3030
Output diff in reverse.
3131

3232
-M::
33-
Detect renames; implies -p.
33+
Detect renames.
3434

3535
-C::
36-
Detect copies as well as renames; implies -p.
36+
Detect copies as well as renames.
3737

3838
-S<string>::
3939
Look for differences that contains the change in <string>.

Documentation/git-diff-tree.txt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,10 @@ OPTIONS
3434
git-diff-tree, this flag implies '-r' as well.
3535

3636
-M::
37-
Detect renames; implies -p, in turn implying also '-r'.
37+
Detect renames.
3838

3939
-C::
40-
Detect copies as well as renames; implies -p, in turn
41-
implying also '-r'.
40+
Detect copies as well as renames.
4241

4342
-R::
4443
Output diff in reverse.

diff-cache.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
#include "diff.h"
33

44
static int cached_only = 0;
5-
static int generate_patch = 0;
5+
static int diff_output_format = DIFF_FORMAT_HUMAN;
66
static int match_nonexisting = 0;
7-
static int line_termination = '\n';
87
static int detect_rename = 0;
98
static int reverse_diff = 0;
109
static int diff_score_opt = 0;
@@ -174,22 +173,21 @@ int main(int argc, char **argv)
174173
continue;
175174
}
176175
if (!strcmp(arg, "-p")) {
177-
generate_patch = 1;
176+
diff_output_format = DIFF_FORMAT_PATCH;
178177
continue;
179178
}
180179
if (!strncmp(arg, "-M", 2)) {
181-
generate_patch = detect_rename = 1;
180+
detect_rename = 1;
182181
diff_score_opt = diff_scoreopt_parse(arg);
183182
continue;
184183
}
185184
if (!strncmp(arg, "-C", 2)) {
186-
generate_patch = 1;
187185
detect_rename = 2;
188186
diff_score_opt = diff_scoreopt_parse(arg);
189187
continue;
190188
}
191189
if (!strcmp(arg, "-z")) {
192-
line_termination = '\0';
190+
diff_output_format = DIFF_FORMAT_MACHINE;
193191
continue;
194192
}
195193
if (!strcmp(arg, "-R")) {
@@ -214,7 +212,7 @@ int main(int argc, char **argv)
214212
if (argc != 2 || get_sha1(argv[1], tree_sha1))
215213
usage(diff_cache_usage);
216214

217-
diff_setup(reverse_diff, (generate_patch ? -1 : line_termination));
215+
diff_setup(reverse_diff, diff_output_format);
218216

219217
mark_merge_entries();
220218

diff-files.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
static const char *diff_files_usage =
1010
"git-diff-files [-p] [-q] [-r] [-z] [-M] [-C] [-R] [-S<string>] [paths...]";
1111

12-
static int generate_patch = 0;
13-
static int line_termination = '\n';
12+
static int diff_output_format = DIFF_FORMAT_HUMAN;
1413
static int detect_rename = 0;
1514
static int reverse_diff = 0;
1615
static int diff_score_opt = 0;
@@ -57,27 +56,26 @@ int main(int argc, char **argv)
5756

5857
while (1 < argc && argv[1][0] == '-') {
5958
if (!strcmp(argv[1], "-p"))
60-
generate_patch = 1;
59+
diff_output_format = DIFF_FORMAT_PATCH;
6160
else if (!strcmp(argv[1], "-q"))
6261
silent = 1;
6362
else if (!strcmp(argv[1], "-r"))
6463
; /* no-op */
6564
else if (!strcmp(argv[1], "-s"))
6665
; /* no-op */
6766
else if (!strcmp(argv[1], "-z"))
68-
line_termination = 0;
67+
diff_output_format = DIFF_FORMAT_MACHINE;
6968
else if (!strcmp(argv[1], "-R"))
7069
reverse_diff = 1;
7170
else if (!strcmp(argv[1], "-S"))
7271
pickaxe = argv[1] + 2;
7372
else if (!strncmp(argv[1], "-M", 2)) {
7473
diff_score_opt = diff_scoreopt_parse(argv[1]);
75-
detect_rename = generate_patch = 1;
74+
detect_rename = 1;
7675
}
7776
else if (!strncmp(argv[1], "-C", 2)) {
7877
diff_score_opt = diff_scoreopt_parse(argv[1]);
7978
detect_rename = 2;
80-
generate_patch = 1;
8179
}
8280
else
8381
usage(diff_files_usage);
@@ -92,7 +90,7 @@ int main(int argc, char **argv)
9290
exit(1);
9391
}
9492

95-
diff_setup(reverse_diff, (generate_patch ? -1 : line_termination));
93+
diff_setup(reverse_diff, diff_output_format);
9694

9795
for (i = 0; i < entries; i++) {
9896
struct stat st;

diff-helper.c

Lines changed: 69 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -8,108 +8,74 @@
88

99
static int detect_rename = 0;
1010
static int diff_score_opt = 0;
11-
static int generate_patch = 1;
1211
static const char *pickaxe = NULL;
12+
static int diff_output_style = DIFF_FORMAT_PATCH;
13+
static int line_termination = '\n';
14+
static int inter_name_termination = '\t';
1315

14-
static int parse_oneside_change(const char *cp, int *mode,
15-
unsigned char *sha1, char *path)
16+
static int parse_diff_raw(char *buf1, char *buf2, char *buf3)
1617
{
17-
int ch, m;
18+
char old_path[PATH_MAX];
19+
unsigned char old_sha1[20], new_sha1[20];
20+
char *ep;
21+
char *cp = buf1;
22+
int ch, old_mode, new_mode;
1823

19-
m = 0;
20-
while ((ch = *cp) && '0' <= ch && ch <= '7') {
21-
m = (m << 3) | (ch - '0');
24+
old_mode = new_mode = 0;
25+
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
26+
old_mode = (old_mode << 3) | (ch - '0');
27+
cp++;
28+
}
29+
if (*cp++ != ' ')
30+
return -1;
31+
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
32+
new_mode = (new_mode << 3) | (ch - '0');
2233
cp++;
2334
}
24-
*mode = m;
25-
if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6) &&
26-
strncmp(cp, "\ttree\t", 6) && strncmp(cp, " tree ", 6))
35+
if (*cp++ != ' ')
2736
return -1;
28-
cp += 6;
29-
if (get_sha1_hex(cp, sha1))
37+
if (get_sha1_hex(cp, old_sha1))
3038
return -1;
3139
cp += 40;
32-
if ((*cp != '\t') && *cp != ' ')
40+
if (*cp++ != ' ')
3341
return -1;
34-
strcpy(path, ++cp);
35-
return 0;
36-
}
37-
38-
static int parse_diff_raw_output(const char *buf)
39-
{
40-
char path[PATH_MAX];
41-
unsigned char old_sha1[20], new_sha1[20];
42-
const char *cp = buf;
43-
int ch, old_mode, new_mode;
44-
45-
switch (*cp++) {
46-
case 'U':
47-
diff_unmerge(cp + 1);
48-
break;
49-
case '+':
50-
if (parse_oneside_change(cp, &new_mode, new_sha1, path))
51-
return -1;
52-
diff_addremove('+', new_mode, new_sha1, path, NULL);
53-
break;
54-
case '-':
55-
if (parse_oneside_change(cp, &old_mode, old_sha1, path))
56-
return -1;
57-
diff_addremove('-', old_mode, old_sha1, path, NULL);
58-
break;
59-
case '*':
60-
old_mode = new_mode = 0;
61-
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
62-
old_mode = (old_mode << 3) | (ch - '0');
63-
cp++;
64-
}
65-
if (strncmp(cp, "->", 2))
66-
return -1;
67-
cp += 2;
68-
while ((ch = *cp) && ('0' <= ch && ch <= '7')) {
69-
new_mode = (new_mode << 3) | (ch - '0');
70-
cp++;
71-
}
72-
if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6) &&
73-
strncmp(cp, "\ttree\t", 6) && strncmp(cp, " tree ", 6))
74-
return -1;
75-
cp += 6;
76-
if (get_sha1_hex(cp, old_sha1))
77-
return -1;
78-
cp += 40;
79-
if (strncmp(cp, "->", 2))
80-
return -1;
81-
cp += 2;
82-
if (get_sha1_hex(cp, new_sha1))
83-
return -1;
84-
cp += 40;
85-
if ((*cp != '\t') && *cp != ' ')
86-
return -1;
87-
strcpy(path, ++cp);
88-
diff_change(old_mode, new_mode, old_sha1, new_sha1, path, NULL);
89-
break;
90-
default:
42+
if (get_sha1_hex(cp, new_sha1))
9143
return -1;
92-
}
44+
cp += 40;
45+
if (*cp++ != inter_name_termination)
46+
return -1;
47+
if (buf2)
48+
cp = buf2;
49+
ep = strchr(cp, inter_name_termination);
50+
if (!ep)
51+
return -1;
52+
*ep++ = 0;
53+
strcpy(old_path, cp);
54+
diff_guif(old_mode, new_mode, old_sha1, new_sha1,
55+
old_path, buf3 ? buf3 : ep);
9356
return 0;
9457
}
9558

9659
static const char *diff_helper_usage =
9760
"git-diff-helper [-z] [-R] [-M] [-C] [-S<string>] paths...";
9861

9962
int main(int ac, const char **av) {
100-
struct strbuf sb;
101-
int reverse = 0;
102-
int line_termination = '\n';
63+
struct strbuf sb1, sb2, sb3;
64+
int reverse_diff = 0;
10365

104-
strbuf_init(&sb);
66+
strbuf_init(&sb1);
67+
strbuf_init(&sb2);
68+
strbuf_init(&sb3);
10569

10670
while (1 < ac && av[1][0] == '-') {
10771
if (av[1][1] == 'R')
108-
reverse = 1;
72+
reverse_diff = 1;
10973
else if (av[1][1] == 'z')
110-
line_termination = 0;
74+
line_termination = inter_name_termination = 0;
11175
else if (av[1][1] == 'p') /* hidden from the help */
112-
generate_patch = 0;
76+
diff_output_style = DIFF_FORMAT_HUMAN;
77+
else if (av[1][1] == 'P') /* hidden from the help */
78+
diff_output_style = DIFF_FORMAT_MACHINE;
11379
else if (av[1][1] == 'M') {
11480
detect_rename = 1;
11581
diff_score_opt = diff_scoreopt_parse(av[1]);
@@ -127,19 +93,38 @@ int main(int ac, const char **av) {
12793
}
12894
/* the remaining parameters are paths patterns */
12995

130-
diff_setup(reverse, (generate_patch ? -1 : line_termination));
96+
diff_setup(reverse_diff, diff_output_style);
13197
while (1) {
13298
int status;
133-
read_line(&sb, stdin, line_termination);
134-
if (sb.eof)
99+
read_line(&sb1, stdin, line_termination);
100+
if (sb1.eof)
135101
break;
136-
status = parse_diff_raw_output(sb.buf);
102+
switch (sb1.buf[0]) {
103+
case 'U':
104+
diff_unmerge(sb1.buf + 2);
105+
continue;
106+
case ':':
107+
break;
108+
default:
109+
goto unrecognized;
110+
}
111+
if (!line_termination) {
112+
read_line(&sb2, stdin, line_termination);
113+
if (sb2.eof)
114+
break;
115+
read_line(&sb3, stdin, line_termination);
116+
if (sb3.eof)
117+
break;
118+
status = parse_diff_raw(sb1.buf+1, sb2.buf, sb3.buf);
119+
}
120+
else
121+
status = parse_diff_raw(sb1.buf+1, NULL, NULL);
137122
if (status) {
123+
unrecognized:
138124
diff_flush(av+1, ac-1);
139-
printf("%s%c", sb.buf, line_termination);
125+
printf("%s%c", sb1.buf, line_termination);
140126
}
141127
}
142-
143128
if (detect_rename)
144129
diff_detect_rename(detect_rename, diff_score_opt);
145130
if (pickaxe)

0 commit comments

Comments
 (0)