[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 <junkio@cox.net>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Junio C Hamano 2005-05-22 21:24:49 -07:00 коммит произвёл Linus Torvalds
Родитель c1bb935020
Коммит 60896c7bfe
2 изменённых файлов: 80 добавлений и 10 удалений

Просмотреть файл

@ -20,7 +20,7 @@ static void diff_rename_pool_add(struct diff_rename_pool *pool,
struct diff_filespec *s) struct diff_filespec *s)
{ {
if (S_ISDIR(s->mode)) if (S_ISDIR(s->mode))
return; /* rename/copy patch for tree does not make sense. */ return; /* no trees, please */
if (pool->alloc <= pool->nr) { if (pool->alloc <= pool->nr) {
pool->alloc = alloc_nr(pool->alloc); pool->alloc = alloc_nr(pool->alloc);
@ -71,6 +71,13 @@ static int estimate_similarity(struct diff_filespec *src,
unsigned long delta_size, base_size; unsigned long delta_size, base_size;
int score; int score;
/* We deal only with regular files. Symlink renames are handled
* only when they are exact matches --- in other words, no edits
* after renaming.
*/
if (!S_ISREG(src->mode) || !S_ISREG(dst->mode))
return 0;
delta_size = ((src->size < dst->size) ? delta_size = ((src->size < dst->size) ?
(dst->size - src->size) : (src->size - dst->size)); (dst->size - src->size) : (src->size - dst->size));
base_size = ((src->size < dst->size) ? src->size : dst->size); base_size = ((src->size < dst->size) ? src->size : dst->size);
@ -268,7 +275,7 @@ void diffcore_rename(int detect_rename, int minimum_score)
struct diff_filepair *p = q->queue[i]; struct diff_filepair *p = q->queue[i];
if (!DIFF_FILE_VALID(p->one)) if (!DIFF_FILE_VALID(p->one))
if (!DIFF_FILE_VALID(p->two)) if (!DIFF_FILE_VALID(p->two))
continue; /* ignore nonsense */ continue; /* unmerged */
else else
diff_rename_pool_add(&created, p->two); diff_rename_pool_add(&created, p->two);
else if (!DIFF_FILE_VALID(p->two)) else if (!DIFF_FILE_VALID(p->two))
@ -360,12 +367,9 @@ void diffcore_rename(int detect_rename, int minimum_score)
for (i = 0; i < q->nr; i++) { for (i = 0; i < q->nr; i++) {
struct diff_filepair *dp, *p = q->queue[i]; struct diff_filepair *dp, *p = q->queue[i];
if (!DIFF_FILE_VALID(p->one)) { if (!DIFF_FILE_VALID(p->one)) {
if (DIFF_FILE_VALID(p->two)) { /* creation or unmerged entries */
/* creation */ dp = diff_queue(&outq, p->one, p->two);
dp = diff_queue(&outq, p->one, p->two); dp->xfrm_work = 4;
dp->xfrm_work = 4;
}
/* otherwise it is a nonsense; just ignore it */
} }
else if (!DIFF_FILE_VALID(p->two)) { else if (!DIFF_FILE_VALID(p->two)) {
/* deletion */ /* deletion */
@ -394,7 +398,7 @@ void diffcore_rename(int detect_rename, int minimum_score)
for (i = 0; i < outq.nr; i++) { for (i = 0; i < outq.nr; i++) {
struct diff_filepair *p = outq.queue[i]; struct diff_filepair *p = outq.queue[i];
if (!DIFF_FILE_VALID(p->one)) { if (!DIFF_FILE_VALID(p->one)) {
/* created */ /* created or unmerged */
if (p->two->xfrm_flags & RENAME_DST_MATCHED) if (p->two->xfrm_flags & RENAME_DST_MATCHED)
; /* rename/copy created it already */ ; /* rename/copy created it already */
else else
@ -443,7 +447,7 @@ void diffcore_rename(int detect_rename, int minimum_score)
else else
/* otherwise it is a modified (or stayed) entry */ /* otherwise it is a modified (or stayed) entry */
diff_queue(q, p->one, p->two); diff_queue(q, p->one, p->two);
free(p); diff_free_filepair(p);
} }
free(outq.queue); free(outq.queue);

Просмотреть файл

@ -0,0 +1,66 @@
#!/bin/sh
#
# Copyright (c) 2005 Junio C Hamano
#
test_description='More rename detection tests.
The rename detection logic should be able to detect pure rename or
copy of symbolic links, but should not produce rename/copy followed
by an edit for them.
'
. ./test-lib.sh
test_expect_success \
'prepare reference tree' \
'echo xyzzy | tr -d '\\\\'012 >yomin &&
ln -s xyzzy frotz &&
git-update-cache --add frotz yomin &&
tree=$(git-write-tree) &&
echo $tree'
test_expect_success \
'prepare work tree' \
'mv frotz rezrov &&
rm -f yomin &&
ln -s xyzzy nitfol &&
ln -s xzzzy bozbar &&
git-update-cache --add --remove frotz rezrov nitfol bozbar yomin'
# tree has frotz pointing at xyzzy, and yomin that contains xyzzy to
# confuse things. work tree has rezrov (xyzzy) nitfol (xyzzy) and
# bozbar (xzzzy).
# rezrov and nitfol are rename/copy of frotz and bozbar should be
# a new creation.
GIT_DIFF_OPTS=--unified=0 git-diff-cache -M -p $tree >current
cat >expected <<\EOF
diff --git a/frotz b/nitfol
similarity index 100%
copy from frotz
copy to nitfol
diff --git a/frotz b/rezrov
similarity index 100%
rename old frotz
rename new rezrov
diff --git a/yomin b/yomin
deleted file mode 100644
--- a/yomin
+++ /dev/null
@@ -1 +0,0 @@
-xyzzy
\ No newline at end of file
diff --git a/bozbar b/bozbar
new file mode 120000
--- /dev/null
+++ b/bozbar
@@ -0,0 +1 @@
+xzzzy
\ No newline at end of file
EOF
test_expect_success \
'validate diff output' \
'diff -u current expected'
test_done