| 1 | #!/bin/sh |
| 2 | # |
| 3 | # Copyright (c) 2005 Junio C Hamano |
| 4 | # |
| 5 | |
| 6 | test_description='Test rename detection in diff engine.' |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | . "$TEST_DIRECTORY"/lib-diff.sh |
| 10 | |
| 11 | test_expect_success 'setup' ' |
| 12 | cat >path0 <<-\EOF && |
| 13 | Line 1 |
| 14 | Line 2 |
| 15 | Line 3 |
| 16 | Line 4 |
| 17 | Line 5 |
| 18 | Line 6 |
| 19 | Line 7 |
| 20 | Line 8 |
| 21 | Line 9 |
| 22 | Line 10 |
| 23 | line 11 |
| 24 | Line 12 |
| 25 | Line 13 |
| 26 | Line 14 |
| 27 | Line 15 |
| 28 | EOF |
| 29 | cat >expected <<-\EOF && |
| 30 | diff --git a/path0 b/path1 |
| 31 | rename from path0 |
| 32 | rename to path1 |
| 33 | --- a/path0 |
| 34 | +++ b/path1 |
| 35 | @@ -8,7 +8,7 @@ Line 7 |
| 36 | Line 8 |
| 37 | Line 9 |
| 38 | Line 10 |
| 39 | -line 11 |
| 40 | +Line 11 |
| 41 | Line 12 |
| 42 | Line 13 |
| 43 | Line 14 |
| 44 | EOF |
| 45 | cat >no-rename <<-\EOF |
| 46 | diff --git a/path0 b/path0 |
| 47 | deleted file mode 100644 |
| 48 | index fdbec44..0000000 |
| 49 | --- a/path0 |
| 50 | +++ /dev/null |
| 51 | @@ -1,15 +0,0 @@ |
| 52 | -Line 1 |
| 53 | -Line 2 |
| 54 | -Line 3 |
| 55 | -Line 4 |
| 56 | -Line 5 |
| 57 | -Line 6 |
| 58 | -Line 7 |
| 59 | -Line 8 |
| 60 | -Line 9 |
| 61 | -Line 10 |
| 62 | -line 11 |
| 63 | -Line 12 |
| 64 | -Line 13 |
| 65 | -Line 14 |
| 66 | -Line 15 |
| 67 | diff --git a/path1 b/path1 |
| 68 | new file mode 100644 |
| 69 | index 0000000..752c50e |
| 70 | --- /dev/null |
| 71 | +++ b/path1 |
| 72 | @@ -0,0 +1,15 @@ |
| 73 | +Line 1 |
| 74 | +Line 2 |
| 75 | +Line 3 |
| 76 | +Line 4 |
| 77 | +Line 5 |
| 78 | +Line 6 |
| 79 | +Line 7 |
| 80 | +Line 8 |
| 81 | +Line 9 |
| 82 | +Line 10 |
| 83 | +Line 11 |
| 84 | +Line 12 |
| 85 | +Line 13 |
| 86 | +Line 14 |
| 87 | +Line 15 |
| 88 | EOF |
| 89 | ' |
| 90 | |
| 91 | test_expect_success \ |
| 92 | 'update-index --add a file.' \ |
| 93 | 'git update-index --add path0' |
| 94 | |
| 95 | test_expect_success \ |
| 96 | 'write that tree.' \ |
| 97 | 'tree=$(git write-tree) && echo $tree' |
| 98 | |
| 99 | sed -e 's/line/Line/' <path0 >path1 |
| 100 | rm -f path0 |
| 101 | test_expect_success \ |
| 102 | 'renamed and edited the file.' \ |
| 103 | 'git update-index --add --remove path0 path1' |
| 104 | |
| 105 | test_expect_success \ |
| 106 | 'git diff-index -p -M after rename and editing.' \ |
| 107 | 'git diff-index -p -M $tree >current' |
| 108 | |
| 109 | |
| 110 | test_expect_success \ |
| 111 | 'validate the output.' \ |
| 112 | 'compare_diff_patch current expected' |
| 113 | |
| 114 | test_expect_success 'test diff.renames=true' ' |
| 115 | git -c diff.renames=true diff --cached $tree >current && |
| 116 | compare_diff_patch current expected |
| 117 | ' |
| 118 | |
| 119 | test_expect_success 'test diff.renames=false' ' |
| 120 | git -c diff.renames=false diff --cached $tree >current && |
| 121 | compare_diff_patch current no-rename |
| 122 | ' |
| 123 | |
| 124 | test_expect_success 'test diff.renames unset' ' |
| 125 | git diff --cached $tree >current && |
| 126 | compare_diff_patch current expected |
| 127 | ' |
| 128 | |
| 129 | test_expect_success 'favour same basenames over different ones' ' |
| 130 | cp path1 another-path && |
| 131 | git add another-path && |
| 132 | git commit -m 1 && |
| 133 | git rm path1 && |
| 134 | mkdir subdir && |
| 135 | git mv another-path subdir/path1 && |
| 136 | git status >out && |
| 137 | test_grep "renamed: .*path1 -> subdir/path1" out |
| 138 | ' |
| 139 | |
| 140 | test_expect_success 'test diff.renames=true for git status' ' |
| 141 | git -c diff.renames=true status >out && |
| 142 | test_grep "renamed: .*path1 -> subdir/path1" out |
| 143 | ' |
| 144 | |
| 145 | test_expect_success 'test diff.renames=false for git status' ' |
| 146 | git -c diff.renames=false status >out && |
| 147 | test_grep ! "renamed: .*path1 -> subdir/path1" out && |
| 148 | test_grep "new file: .*subdir/path1" out && |
| 149 | test_grep "deleted: .*[^/]path1" out |
| 150 | ' |
| 151 | |
| 152 | test_expect_success 'favour same basenames even with minor differences' ' |
| 153 | git show HEAD:path1 | sed "s/15/16/" > subdir/path1 && |
| 154 | git status >out && |
| 155 | test_grep "renamed: .*path1 -> subdir/path1" out |
| 156 | ' |
| 157 | |
| 158 | test_expect_success 'two files with same basename and same content' ' |
| 159 | git reset --hard && |
| 160 | mkdir -p dir/A dir/B && |
| 161 | cp path1 dir/A/file && |
| 162 | cp path1 dir/B/file && |
| 163 | git add dir && |
| 164 | git commit -m 2 && |
| 165 | git mv dir other-dir && |
| 166 | git status >out && |
| 167 | test_grep "renamed: .*dir/A/file -> other-dir/A/file" out |
| 168 | ' |
| 169 | |
| 170 | test_expect_success 'setup for many rename source candidates' ' |
| 171 | git reset --hard && |
| 172 | for i in 0 1 2 3 4 5 6 7 8 9; |
| 173 | do |
| 174 | for j in 0 1 2 3 4 5 6 7 8 9; |
| 175 | do |
| 176 | echo "$i$j" >"path$i$j" || return 1 |
| 177 | done |
| 178 | done && |
| 179 | git add "path??" && |
| 180 | test_tick && |
| 181 | git commit -m "hundred" && |
| 182 | (cat path1 && echo new) >new-path && |
| 183 | echo old >>path1 && |
| 184 | git add new-path path1 && |
| 185 | git diff -l 4 -C -C --cached --name-status >actual 2>actual.err && |
| 186 | sed -e "s/^\([CM]\)[0-9]* /\1 /" actual >actual.munged && |
| 187 | cat >expect <<-EOF && |
| 188 | C path1 new-path |
| 189 | M path1 |
| 190 | EOF |
| 191 | test_cmp expect actual.munged && |
| 192 | grep warning actual.err |
| 193 | ' |
| 194 | |
| 195 | test_expect_success 'rename pretty print with nothing in common' ' |
| 196 | mkdir -p a/b/ && |
| 197 | : >a/b/c && |
| 198 | git add a/b/c && |
| 199 | git commit -m "create a/b/c" && |
| 200 | mkdir -p c/b/ && |
| 201 | git mv a/b/c c/b/a && |
| 202 | git commit -m "a/b/c -> c/b/a" && |
| 203 | git diff -M --summary HEAD^ HEAD >output && |
| 204 | test_grep " a/b/c => c/b/a " output && |
| 205 | git diff -M --stat HEAD^ HEAD >output && |
| 206 | test_grep " a/b/c => c/b/a " output |
| 207 | ' |
| 208 | |
| 209 | test_expect_success 'rename pretty print with common prefix' ' |
| 210 | mkdir -p c/d && |
| 211 | git mv c/b/a c/d/e && |
| 212 | git commit -m "c/b/a -> c/d/e" && |
| 213 | git diff -M --summary HEAD^ HEAD >output && |
| 214 | test_grep " c/{b/a => d/e} " output && |
| 215 | git diff -M --stat HEAD^ HEAD >output && |
| 216 | test_grep " c/{b/a => d/e} " output |
| 217 | ' |
| 218 | |
| 219 | test_expect_success 'rename pretty print with common suffix' ' |
| 220 | mkdir d && |
| 221 | git mv c/d/e d/e && |
| 222 | git commit -m "c/d/e -> d/e" && |
| 223 | git diff -M --summary HEAD^ HEAD >output && |
| 224 | test_grep " {c/d => d}/e " output && |
| 225 | git diff -M --stat HEAD^ HEAD >output && |
| 226 | test_grep " {c/d => d}/e " output |
| 227 | ' |
| 228 | |
| 229 | test_expect_success 'rename pretty print with common prefix and suffix' ' |
| 230 | mkdir d/f && |
| 231 | git mv d/e d/f/e && |
| 232 | git commit -m "d/e -> d/f/e" && |
| 233 | git diff -M --summary HEAD^ HEAD >output && |
| 234 | test_grep " d/{ => f}/e " output && |
| 235 | git diff -M --stat HEAD^ HEAD >output && |
| 236 | test_grep " d/{ => f}/e " output |
| 237 | ' |
| 238 | |
| 239 | test_expect_success 'rename pretty print common prefix and suffix overlap' ' |
| 240 | mkdir d/f/f && |
| 241 | git mv d/f/e d/f/f/e && |
| 242 | git commit -m "d/f/e d/f/f/e" && |
| 243 | git diff -M --summary HEAD^ HEAD >output && |
| 244 | test_grep " d/f/{ => f}/e " output && |
| 245 | git diff -M --stat HEAD^ HEAD >output && |
| 246 | test_grep " d/f/{ => f}/e " output |
| 247 | ' |
| 248 | |
| 249 | test_expect_success 'diff-tree -l0 defaults to a big rename limit, not zero' ' |
| 250 | test_write_lines line1 line2 line3 >myfile && |
| 251 | git add myfile && |
| 252 | git commit -m x && |
| 253 | |
| 254 | test_write_lines line1 line2 line4 >myotherfile && |
| 255 | git rm myfile && |
| 256 | git add myotherfile && |
| 257 | git commit -m x && |
| 258 | |
| 259 | git diff-tree -M -l0 HEAD HEAD^ >actual && |
| 260 | # Verify that a rename from myotherfile to myfile was detected |
| 261 | grep "myotherfile.*myfile" actual |
| 262 | ' |
| 263 | |
| 264 | test_expect_success 'basename similarity vs best similarity' ' |
| 265 | mkdir subdir && |
| 266 | test_write_lines line1 line2 line3 line4 line5 \ |
| 267 | line6 line7 line8 line9 line10 >subdir/file.txt && |
| 268 | git add subdir/file.txt && |
| 269 | git commit -m "base txt" && |
| 270 | |
| 271 | git rm subdir/file.txt && |
| 272 | test_write_lines line1 line2 line3 line4 line5 \ |
| 273 | line6 line7 line8 >file.txt && |
| 274 | test_write_lines line1 line2 line3 line4 line5 \ |
| 275 | line6 line7 line8 line9 >file.md && |
| 276 | git add file.txt file.md && |
| 277 | git commit -a -m "rename" && |
| 278 | git diff-tree -r -M --name-status HEAD^ HEAD >actual && |
| 279 | # subdir/file.txt is 88% similar to file.md, 78% similar to file.txt, |
| 280 | # but since same basenames are checked first... |
| 281 | cat >expected <<-\EOF && |
| 282 | A file.md |
| 283 | R078 subdir/file.txt file.txt |
| 284 | EOF |
| 285 | test_cmp expected actual |
| 286 | ' |
| 287 | |
| 288 | test_expect_success 'last line matters too' ' |
| 289 | { |
| 290 | test_write_lines a 0 1 2 3 4 5 6 7 8 9 && |
| 291 | printf "git ignores final up to 63 characters if not newline terminated" |
| 292 | } >no-final-lf && |
| 293 | git add no-final-lf && |
| 294 | git commit -m "original version of file with no final newline" && |
| 295 | |
| 296 | # Change ONLY the first character of the whole file |
| 297 | { |
| 298 | test_write_lines b 0 1 2 3 4 5 6 7 8 9 && |
| 299 | printf "git ignores final up to 63 characters if not newline terminated" |
| 300 | } >no-final-lf && |
| 301 | git add no-final-lf && |
| 302 | git mv no-final-lf still-absent-final-lf && |
| 303 | git commit -a -m "rename no-final-lf -> still-absent-final-lf" && |
| 304 | git diff-tree -r -M --name-status HEAD^ HEAD >actual && |
| 305 | sed -e "s/^R[0-9]* /R /" actual >actual.munged && |
| 306 | cat >expected <<-\EOF && |
| 307 | R no-final-lf still-absent-final-lf |
| 308 | EOF |
| 309 | test_cmp expected actual.munged |
| 310 | ' |
| 311 | |
| 312 | test_done |