Skip to content

Commit 60896c7

Browse files
Junio C HamanoLinus Torvalds
authored andcommitted
[PATCH] Be careful with symlinks when detecting renames and copies.
Earlier round was not treating symbolic links carefully enough, and would have produced diff output that renamed/copied then edited the contents of a symbolic link, which made no practical sense. Change it to detect only pure renames. Signed-off-by: Junio C Hamano <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent c1bb935 commit 60896c7

File tree

2 files changed

+80
-10
lines changed

2 files changed

+80
-10
lines changed

diffcore-rename.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ static void diff_rename_pool_add(struct diff_rename_pool *pool,
2020
struct diff_filespec *s)
2121
{
2222
if (S_ISDIR(s->mode))
23-
return; /* rename/copy patch for tree does not make sense. */
23+
return; /* no trees, please */
2424

2525
if (pool->alloc <= pool->nr) {
2626
pool->alloc = alloc_nr(pool->alloc);
@@ -71,6 +71,13 @@ static int estimate_similarity(struct diff_filespec *src,
7171
unsigned long delta_size, base_size;
7272
int score;
7373

74+
/* We deal only with regular files. Symlink renames are handled
75+
* only when they are exact matches --- in other words, no edits
76+
* after renaming.
77+
*/
78+
if (!S_ISREG(src->mode) || !S_ISREG(dst->mode))
79+
return 0;
80+
7481
delta_size = ((src->size < dst->size) ?
7582
(dst->size - src->size) : (src->size - dst->size));
7683
base_size = ((src->size < dst->size) ? src->size : dst->size);
@@ -268,7 +275,7 @@ void diffcore_rename(int detect_rename, int minimum_score)
268275
struct diff_filepair *p = q->queue[i];
269276
if (!DIFF_FILE_VALID(p->one))
270277
if (!DIFF_FILE_VALID(p->two))
271-
continue; /* ignore nonsense */
278+
continue; /* unmerged */
272279
else
273280
diff_rename_pool_add(&created, p->two);
274281
else if (!DIFF_FILE_VALID(p->two))
@@ -360,12 +367,9 @@ void diffcore_rename(int detect_rename, int minimum_score)
360367
for (i = 0; i < q->nr; i++) {
361368
struct diff_filepair *dp, *p = q->queue[i];
362369
if (!DIFF_FILE_VALID(p->one)) {
363-
if (DIFF_FILE_VALID(p->two)) {
364-
/* creation */
365-
dp = diff_queue(&outq, p->one, p->two);
366-
dp->xfrm_work = 4;
367-
}
368-
/* otherwise it is a nonsense; just ignore it */
370+
/* creation or unmerged entries */
371+
dp = diff_queue(&outq, p->one, p->two);
372+
dp->xfrm_work = 4;
369373
}
370374
else if (!DIFF_FILE_VALID(p->two)) {
371375
/* deletion */
@@ -394,7 +398,7 @@ void diffcore_rename(int detect_rename, int minimum_score)
394398
for (i = 0; i < outq.nr; i++) {
395399
struct diff_filepair *p = outq.queue[i];
396400
if (!DIFF_FILE_VALID(p->one)) {
397-
/* created */
401+
/* created or unmerged */
398402
if (p->two->xfrm_flags & RENAME_DST_MATCHED)
399403
; /* rename/copy created it already */
400404
else
@@ -443,7 +447,7 @@ void diffcore_rename(int detect_rename, int minimum_score)
443447
else
444448
/* otherwise it is a modified (or stayed) entry */
445449
diff_queue(q, p->one, p->two);
446-
free(p);
450+
diff_free_filepair(p);
447451
}
448452

449453
free(outq.queue);

t/t4004-diff-rename-symlink.sh

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/bin/sh
2+
#
3+
# Copyright (c) 2005 Junio C Hamano
4+
#
5+
6+
test_description='More rename detection tests.
7+
8+
The rename detection logic should be able to detect pure rename or
9+
copy of symbolic links, but should not produce rename/copy followed
10+
by an edit for them.
11+
'
12+
. ./test-lib.sh
13+
14+
test_expect_success \
15+
'prepare reference tree' \
16+
'echo xyzzy | tr -d '\\\\'012 >yomin &&
17+
ln -s xyzzy frotz &&
18+
git-update-cache --add frotz yomin &&
19+
tree=$(git-write-tree) &&
20+
echo $tree'
21+
22+
test_expect_success \
23+
'prepare work tree' \
24+
'mv frotz rezrov &&
25+
rm -f yomin &&
26+
ln -s xyzzy nitfol &&
27+
ln -s xzzzy bozbar &&
28+
git-update-cache --add --remove frotz rezrov nitfol bozbar yomin'
29+
30+
# tree has frotz pointing at xyzzy, and yomin that contains xyzzy to
31+
# confuse things. work tree has rezrov (xyzzy) nitfol (xyzzy) and
32+
# bozbar (xzzzy).
33+
# rezrov and nitfol are rename/copy of frotz and bozbar should be
34+
# a new creation.
35+
36+
GIT_DIFF_OPTS=--unified=0 git-diff-cache -M -p $tree >current
37+
cat >expected <<\EOF
38+
diff --git a/frotz b/nitfol
39+
similarity index 100%
40+
copy from frotz
41+
copy to nitfol
42+
diff --git a/frotz b/rezrov
43+
similarity index 100%
44+
rename old frotz
45+
rename new rezrov
46+
diff --git a/yomin b/yomin
47+
deleted file mode 100644
48+
--- a/yomin
49+
+++ /dev/null
50+
@@ -1 +0,0 @@
51+
-xyzzy
52+
\ No newline at end of file
53+
diff --git a/bozbar b/bozbar
54+
new file mode 120000
55+
--- /dev/null
56+
+++ b/bozbar
57+
@@ -0,0 +1 @@
58+
+xzzzy
59+
\ No newline at end of file
60+
EOF
61+
62+
test_expect_success \
63+
'validate diff output' \
64+
'diff -u current expected'
65+
66+
test_done

0 commit comments

Comments
 (0)