diff options
author | Junio C Hamano <gitster@pobox.com> | 2007-11-30 22:22:38 -0800 |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2007-12-02 02:24:46 -0800 |
commit | b45563a229f5150271837cf487a91ddd8224fbd3 (patch) | |
tree | a0b363c225777490a4c22adaf280ea7ef69f7772 | |
parent | 1c46ab1fada6eb449336a624995293cdd74f2b08 (diff) | |
download | git-b45563a229f5150271837cf487a91ddd8224fbd3.tar.gz |
rename: Break filepairs with different types.
When we consider if a path has been totally rewritten, we did not
touch changes from symlinks to files or vice versa. But a change
that modifies even the type of a blob surely should count as a
complete rewrite.
While we are at it, modernise diffcore-break to be aware of gitlinks (we
do not want to touch them).
Signed-off-by: Junio C Hamano <gitster@pobox.com>
-rw-r--r-- | cache.h | 7 | ||||
-rw-r--r-- | diffcore-break.c | 12 | ||||
-rwxr-xr-x | t/t4008-diff-break-rewrite.sh | 6 | ||||
-rwxr-xr-x | t/t4023-diff-rename-typechange.sh | 86 | ||||
-rw-r--r-- | tree-walk.h | 7 |
5 files changed, 104 insertions, 14 deletions
@@ -192,6 +192,13 @@ enum object_type { OBJ_MAX, }; +static inline enum object_type object_type(unsigned int mode) +{ + return S_ISDIR(mode) ? OBJ_TREE : + S_ISGITLINK(mode) ? OBJ_COMMIT : + OBJ_BLOB; +} + #define GIT_DIR_ENVIRONMENT "GIT_DIR" #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE" #define DEFAULT_GIT_DIR_ENVIRONMENT ".git" diff --git a/diffcore-break.c b/diffcore-break.c index c71a22621a..31cdcfe8bc 100644 --- a/diffcore-break.c +++ b/diffcore-break.c @@ -52,8 +52,10 @@ static int should_break(struct diff_filespec *src, * is the default. */ - if (!S_ISREG(src->mode) || !S_ISREG(dst->mode)) - return 0; /* leave symlink rename alone */ + if (S_ISREG(src->mode) != S_ISREG(dst->mode)) { + *merge_score_p = (int)MAX_SCORE; + return 1; /* even their types are different */ + } if (src->sha1_valid && dst->sha1_valid && !hashcmp(src->sha1, dst->sha1)) @@ -168,11 +170,13 @@ void diffcore_break(int break_score) struct diff_filepair *p = q->queue[i]; int score; - /* We deal only with in-place edit of non directory. + /* + * We deal only with in-place edit of blobs. * We do not break anything else. */ if (DIFF_FILE_VALID(p->one) && DIFF_FILE_VALID(p->two) && - !S_ISDIR(p->one->mode) && !S_ISDIR(p->two->mode) && + object_type(p->one->mode) == OBJ_BLOB && + object_type(p->two->mode) == OBJ_BLOB && !strcmp(p->one->path, p->two->path)) { if (should_break(p->one, p->two, break_score, &score)) { diff --git a/t/t4008-diff-break-rewrite.sh b/t/t4008-diff-break-rewrite.sh index 1287d2ad17..26c2e4aa65 100755 --- a/t/t4008-diff-break-rewrite.sh +++ b/t/t4008-diff-break-rewrite.sh @@ -122,11 +122,11 @@ test_expect_success \ 'run diff with -B -M' \ 'git diff-index -B -M "$tree" >current' -# This should not mistake file0 as the copy source of new file1 -# due to type differences. +# file0 changed from regular to symlink. file1 is very close to the preimage of file0. +# because we break file0, file1 can become a rename of it. cat >expected <<\EOF :100644 120000 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 67be421f88824578857624f7b3dc75e99a8a1481 T file0 -:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 M100 file1 +:100644 100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 f5deac7be59e7eeab8657fd9ae706fd6a57daed2 R file0 file1 EOF test_expect_success \ diff --git a/t/t4023-diff-rename-typechange.sh b/t/t4023-diff-rename-typechange.sh new file mode 100755 index 0000000000..255604effd --- /dev/null +++ b/t/t4023-diff-rename-typechange.sh @@ -0,0 +1,86 @@ +#!/bin/sh + +test_description='typechange rename detection' + +. ./test-lib.sh + +test_expect_success setup ' + + rm -f foo bar && + cat ../../COPYING >foo && + ln -s linklink bar && + git add foo bar && + git commit -a -m Initial && + git tag one && + + rm -f foo bar && + cat ../../COPYING >bar && + ln -s linklink foo && + git add foo bar && + git commit -a -m Second && + git tag two && + + rm -f foo bar && + cat ../../COPYING >foo && + git add foo && + git commit -a -m Third && + git tag three && + + mv foo bar && + ln -s linklink foo && + git add foo bar && + git commit -a -m Fourth && + git tag four && + + # This is purely for sanity check + + rm -f foo bar && + cat ../../COPYING >foo && + cat ../../Makefile >bar && + git add foo bar && + git commit -a -m Fifth && + git tag five && + + rm -f foo bar && + cat ../../Makefile >foo && + cat ../../COPYING >bar && + git add foo bar && + git commit -a -m Sixth && + git tag six + +' + +test_expect_success 'cross renames to be detected for regular files' ' + + git diff-tree five six -r --name-status -B -M | sort >actual && + { + echo "R100 foo bar" + echo "R100 bar foo" + } | sort >expect && + diff -u expect actual + +' + +test_expect_success 'cross renames to be detected for typechange' ' + + git diff-tree one two -r --name-status -B -M | sort >actual && + { + echo "R100 foo bar" + echo "R100 bar foo" + } | sort >expect && + diff -u expect actual + +' + +test_expect_success 'moves and renames' ' + + git diff-tree three four -r --name-status -B -M | sort >actual && + { + echo "R100 foo bar" + echo "T100 foo" + } | sort >expect && + diff -u expect actual + +' + +test_done diff --git a/tree-walk.h b/tree-walk.h index 903a7b0f48..db0fbdc701 100644 --- a/tree-walk.h +++ b/tree-walk.h @@ -7,13 +7,6 @@ struct name_entry { unsigned int mode; }; -static inline enum object_type object_type(unsigned int mode) -{ - return S_ISDIR(mode) ? OBJ_TREE : - S_ISGITLINK(mode) ? OBJ_COMMIT : - OBJ_BLOB; -} - struct tree_desc { const void *buffer; struct name_entry entry; |