Skip to content

Commit 427dcb4

Browse files
Junio C HamanoLinus Torvalds
authored andcommitted
[PATCH] Diff overhaul, adding half of copy detection.
This introduces the diff-core, the layer between the diff-tree family and the external diff interface engine. The calls to the interface diff-tree family uses (diff_change and diff_addremove) have not changed and will not change. The purpose of the diff-core layer is to provide an infrastructure to transform the set of differences sent from the applications, before sending them to the external diff interface. The recently introduced rename detection code has been rewritten to use the diff-core facility. When applications send in separate creates and deletes, matching ones are transformed into a single rename-and-edit diff, and sent out to the external diff interface as such. This patch also enhances the rename detection code further to be able to detect copies. Currently this happens only as long as copy sources appear as part of the modified files, but there already is enough provision for callers to report unmodified files to diff-core, so that they can be also used as copy source candidates. Extending the callers this way will be done in a separate patch. Please see and marvel at how well this works by trying out the newly added t/t4003-diff-rename-1.sh test script. Signed-off-by: Junio C Hamano <junkio@cox.net> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
1 parent c8265ac commit 427dcb4

16 files changed

+944
-432
lines changed

Documentation/git-diff-cache.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-diff-cache - Compares content and mode of blobs between the cache and reposi
99

1010
SYNOPSIS
1111
--------
12-
'git-diff-cache' [-p] [-r] [-z] [-m] [-M] [-R] [--cached] <tree-ish>
12+
'git-diff-cache' [-p] [-r] [-z] [-m] [-M] [-R] [-C] [--cached] <tree-ish>
1313

1414
DESCRIPTION
1515
-----------
@@ -36,6 +36,9 @@ OPTIONS
3636
-M::
3737
Detect renames; implies -p.
3838

39+
-C::
40+
Detect copies as well as renames; implies -p.
41+
3942
-R::
4043
Output diff in reverse.
4144

Documentation/git-diff-files.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-diff-files - Compares files in the working tree and the cache
99

1010
SYNOPSIS
1111
--------
12-
'git-diff-files' [-p] [-q] [-r] [-z] [-M] [-R] [<pattern>...]
12+
'git-diff-files' [-p] [-q] [-r] [-z] [-M] [-C] [-R] [<pattern>...]
1313

1414
DESCRIPTION
1515
-----------
@@ -32,6 +32,9 @@ OPTIONS
3232
-M::
3333
Detect renames; implies -p.
3434

35+
-C::
36+
Detect copies as well as renames; implies -p.
37+
3538
-r::
3639
This flag does not mean anything. It is there only to match
3740
git-diff-tree. Unlike git-diff-tree, git-diff-files always looks

Documentation/git-diff-helper.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-diff-helper - Generates patch format output for git-diff-*
99

1010
SYNOPSIS
1111
--------
12-
'git-diff-helper' [-z] [-R] [-M]
12+
'git-diff-helper' [-z] [-R] [-M] [-C]
1313

1414
DESCRIPTION
1515
-----------
@@ -34,6 +34,8 @@ OPTIONS
3434
-M::
3535
Detect renames.
3636

37+
-C::
38+
Detect copies as well as renames.
3739

3840
See Also
3941
--------

Documentation/git-diff-tree.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ git-diff-tree - Compares the content and mode of blobs found via two tree object
99

1010
SYNOPSIS
1111
--------
12-
'git-diff-tree' [-p] [-r] [-z] [--stdin] [-M] [-R] [-m] [-s] [-v] <tree-ish> <tree-ish> [<pattern>]\*
12+
'git-diff-tree' [-p] [-r] [-z] [--stdin] [-M] [-R] [-C] [-m] [-s] [-v] <tree-ish> <tree-ish> [<pattern>]\*
1313

1414
DESCRIPTION
1515
-----------
@@ -36,6 +36,10 @@ OPTIONS
3636
-M::
3737
Detect renames; implies -p, in turn implying also '-r'.
3838

39+
-C::
40+
Detect copies as well as renames; implies -p, in turn
41+
implying also '-r'.
42+
3943
-R::
4044
Output diff in reverse.
4145

Makefile

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ LIB_H += strbuf.h
4545
LIB_OBJS += strbuf.o
4646

4747
LIB_H += diff.h
48-
LIB_OBJS += diff.o
48+
LIB_OBJS += diff.o diffcore-rename.o
4949

5050
LIB_OBJS += gitenv.o
5151

@@ -121,9 +121,10 @@ object.o: $(LIB_H)
121121
read-cache.o: $(LIB_H)
122122
sha1_file.o: $(LIB_H)
123123
usage.o: $(LIB_H)
124-
diff.o: $(LIB_H)
125124
strbuf.o: $(LIB_H)
126125
gitenv.o: $(LIB_H)
126+
diff.o: $(LIB_H)
127+
diffcore-rename.o : $(LIB_H)
127128

128129
test: all
129130
make -C t/ all

diff-cache.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ static void mark_merge_entries(void)
153153
}
154154

155155
static char *diff_cache_usage =
156-
"git-diff-cache [-p] [-r] [-z] [-m] [-M] [-R] [--cached] <tree-ish>";
156+
"git-diff-cache [-p] [-r] [-z] [-m] [-M] [-C] [-R] [--cached] <tree-ish>";
157157

158158
int main(int argc, char **argv)
159159
{
@@ -180,6 +180,12 @@ int main(int argc, char **argv)
180180
diff_score_opt = diff_scoreopt_parse(arg);
181181
continue;
182182
}
183+
if (!strncmp(arg, "-C", 2)) {
184+
generate_patch = 1;
185+
detect_rename = 2;
186+
diff_score_opt = diff_scoreopt_parse(arg);
187+
continue;
188+
}
183189
if (!strcmp(arg, "-z")) {
184190
line_termination = '\0';
185191
continue;

diff-files.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "diff.h"
88

99
static const char *diff_files_usage =
10-
"git-diff-files [-p] [-q] [-r] [-z] [-M] [-R] [paths...]";
10+
"git-diff-files [-p] [-q] [-r] [-z] [-M] [-C] [-R] [paths...]";
1111

1212
static int generate_patch = 0;
1313
static int line_termination = '\n';
@@ -71,6 +71,11 @@ int main(int argc, char **argv)
7171
diff_score_opt = diff_scoreopt_parse(argv[1]);
7272
detect_rename = generate_patch = 1;
7373
}
74+
else if (!strncmp(argv[1], "-C", 2)) {
75+
diff_score_opt = diff_scoreopt_parse(argv[1]);
76+
detect_rename = 2;
77+
generate_patch = 1;
78+
}
7479
else
7580
usage(diff_files_usage);
7681
argv++; argc--;

diff-helper.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
static int detect_rename = 0;
1010
static int diff_score_opt = 0;
11+
static int generate_patch = 1;
1112

1213
static int parse_oneside_change(const char *cp, int *mode,
1314
unsigned char *sha1, char *path)
@@ -20,7 +21,8 @@ static int parse_oneside_change(const char *cp, int *mode,
2021
cp++;
2122
}
2223
*mode = m;
23-
if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6))
24+
if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6) &&
25+
strncmp(cp, "\ttree\t", 6) && strncmp(cp, " tree ", 6))
2426
return -1;
2527
cp += 6;
2628
if (get_sha1_hex(cp, sha1))
@@ -44,11 +46,13 @@ static int parse_diff_raw_output(const char *buf)
4446
diff_unmerge(cp + 1);
4547
break;
4648
case '+':
47-
parse_oneside_change(cp, &new_mode, new_sha1, path);
49+
if (parse_oneside_change(cp, &new_mode, new_sha1, path))
50+
return -1;
4851
diff_addremove('+', new_mode, new_sha1, path, NULL);
4952
break;
5053
case '-':
51-
parse_oneside_change(cp, &old_mode, old_sha1, path);
54+
if (parse_oneside_change(cp, &old_mode, old_sha1, path))
55+
return -1;
5256
diff_addremove('-', old_mode, old_sha1, path, NULL);
5357
break;
5458
case '*':
@@ -64,7 +68,8 @@ static int parse_diff_raw_output(const char *buf)
6468
new_mode = (new_mode << 3) | (ch - '0');
6569
cp++;
6670
}
67-
if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6))
71+
if (strncmp(cp, "\tblob\t", 6) && strncmp(cp, " blob ", 6) &&
72+
strncmp(cp, "\ttree\t", 6) && strncmp(cp, " tree ", 6))
6873
return -1;
6974
cp += 6;
7075
if (get_sha1_hex(cp, old_sha1))
@@ -88,7 +93,7 @@ static int parse_diff_raw_output(const char *buf)
8893
}
8994

9095
static const char *diff_helper_usage =
91-
"git-diff-helper [-z] [-R] [-M] paths...";
96+
"git-diff-helper [-z] [-R] [-M] [-C] paths...";
9297

9398
int main(int ac, const char **av) {
9499
struct strbuf sb;
@@ -102,17 +107,25 @@ int main(int ac, const char **av) {
102107
reverse = 1;
103108
else if (av[1][1] == 'z')
104109
line_termination = 0;
110+
else if (av[1][1] == 'p') /* hidden from the help */
111+
generate_patch = 0;
105112
else if (av[1][1] == 'M') {
106113
detect_rename = 1;
107114
diff_score_opt = diff_scoreopt_parse(av[1]);
108115
}
116+
else if (av[1][1] == 'C') {
117+
detect_rename = 2;
118+
diff_score_opt = diff_scoreopt_parse(av[1]);
119+
}
109120
else
110121
usage(diff_helper_usage);
111122
ac--; av++;
112123
}
113124
/* the remaining parameters are paths patterns */
114125

115-
diff_setup(detect_rename, diff_score_opt, reverse, -1, av+1, ac-1);
126+
diff_setup(detect_rename, diff_score_opt, reverse,
127+
(generate_patch ? -1 : line_termination),
128+
av+1, ac-1);
116129

117130
while (1) {
118131
int status;

diff-tree.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ static int diff_tree_stdin(char *line)
430430
}
431431

432432
static char *diff_tree_usage =
433-
"git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-R] [-m] [-s] [-v] <tree-ish> <tree-ish>";
433+
"git-diff-tree [-p] [-r] [-z] [--stdin] [-M] [-C] [-R] [-m] [-s] [-v] <tree-ish> <tree-ish>";
434434

435435
int main(int argc, char **argv)
436436
{
@@ -478,6 +478,12 @@ int main(int argc, char **argv)
478478
diff_score_opt = diff_scoreopt_parse(arg);
479479
continue;
480480
}
481+
if (!strncmp(arg, "-C", 2)) {
482+
detect_rename = 2;
483+
recursive = generate_patch = 1;
484+
diff_score_opt = diff_scoreopt_parse(arg);
485+
continue;
486+
}
481487
if (!strcmp(arg, "-z")) {
482488
line_termination = '\0';
483489
continue;

0 commit comments

Comments
 (0)