| 1 | #!/bin/sh |
| 2 | |
| 3 | test_description='git apply --3way' |
| 4 | |
| 5 | GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main |
| 6 | export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | |
| 10 | print_sanitized_conflicted_diff () { |
| 11 | git diff HEAD >diff.raw && |
| 12 | sed -e ' |
| 13 | /^index /d |
| 14 | s/^\(+[<>|][<>|][<>|][<>|]*\) .*/\1/ |
| 15 | ' diff.raw |
| 16 | } |
| 17 | |
| 18 | test_expect_success setup ' |
| 19 | test_tick && |
| 20 | test_write_lines 1 2 3 4 5 6 7 >one && |
| 21 | cat one >two && |
| 22 | git add one two && |
| 23 | git commit -m initial && |
| 24 | |
| 25 | git branch side && |
| 26 | |
| 27 | test_tick && |
| 28 | test_write_lines 1 two 3 4 5 six 7 >one && |
| 29 | test_write_lines 1 two 3 4 5 6 7 >two && |
| 30 | git commit -a -m main && |
| 31 | |
| 32 | git checkout side && |
| 33 | test_write_lines 1 2 3 4 five 6 7 >one && |
| 34 | test_write_lines 1 2 3 4 five 6 7 >two && |
| 35 | git commit -a -m side && |
| 36 | |
| 37 | git checkout main |
| 38 | ' |
| 39 | |
| 40 | test_expect_success 'apply without --3way' ' |
| 41 | git diff side^ side >P.diff && |
| 42 | |
| 43 | # should fail to apply |
| 44 | git reset --hard && |
| 45 | git checkout main^0 && |
| 46 | test_must_fail git apply --index P.diff && |
| 47 | # should leave things intact |
| 48 | git diff-files --exit-code && |
| 49 | git diff-index --exit-code --cached HEAD |
| 50 | ' |
| 51 | |
| 52 | test_apply_with_3way () { |
| 53 | # Merging side should be similar to applying this patch |
| 54 | git diff ...side >P.diff && |
| 55 | |
| 56 | # The corresponding conflicted merge |
| 57 | git reset --hard && |
| 58 | git checkout main^0 && |
| 59 | test_must_fail git merge --no-commit side && |
| 60 | git ls-files -s >expect.ls && |
| 61 | print_sanitized_conflicted_diff >expect.diff && |
| 62 | |
| 63 | # should fail to apply |
| 64 | git reset --hard && |
| 65 | git checkout main^0 && |
| 66 | test_must_fail git apply --index --3way P.diff && |
| 67 | git ls-files -s >actual.ls && |
| 68 | print_sanitized_conflicted_diff >actual.diff && |
| 69 | |
| 70 | # The result should resemble the corresponding merge |
| 71 | test_cmp expect.ls actual.ls && |
| 72 | test_cmp expect.diff actual.diff |
| 73 | } |
| 74 | |
| 75 | test_expect_success 'apply with --3way' ' |
| 76 | test_apply_with_3way |
| 77 | ' |
| 78 | |
| 79 | test_expect_success 'apply with --3way with merge.conflictStyle = diff3' ' |
| 80 | test_config merge.conflictStyle diff3 && |
| 81 | test_apply_with_3way |
| 82 | ' |
| 83 | |
| 84 | test_apply_with_3way_favoritism () { |
| 85 | apply_arg=$1 |
| 86 | merge_arg=$2 |
| 87 | |
| 88 | # Merging side should be similar to applying this patch |
| 89 | git diff ...side >P.diff && |
| 90 | |
| 91 | # The corresponding conflicted merge |
| 92 | git reset --hard && |
| 93 | git checkout main^0 && |
| 94 | git merge --no-commit $merge_arg side && |
| 95 | git ls-files -s >expect.ls && |
| 96 | print_sanitized_conflicted_diff >expect.diff && |
| 97 | |
| 98 | # should apply successfully |
| 99 | git reset --hard && |
| 100 | git checkout main^0 && |
| 101 | git apply --index --3way $apply_arg P.diff && |
| 102 | git ls-files -s >actual.ls && |
| 103 | print_sanitized_conflicted_diff >actual.diff && |
| 104 | |
| 105 | # The result should resemble the corresponding merge |
| 106 | test_cmp expect.ls actual.ls && |
| 107 | test_cmp expect.diff actual.diff |
| 108 | } |
| 109 | |
| 110 | test_expect_success 'apply with --3way --ours' ' |
| 111 | test_apply_with_3way_favoritism --ours -Xours |
| 112 | ' |
| 113 | |
| 114 | test_expect_success 'apply with --3way --theirs' ' |
| 115 | test_apply_with_3way_favoritism --theirs -Xtheirs |
| 116 | ' |
| 117 | |
| 118 | test_expect_success 'apply with --3way --union' ' |
| 119 | echo "* merge=union" >.gitattributes && |
| 120 | test_apply_with_3way_favoritism --union && |
| 121 | rm .gitattributes |
| 122 | ' |
| 123 | |
| 124 | test_expect_success 'apply with --3way with rerere enabled' ' |
| 125 | test_config rerere.enabled true && |
| 126 | |
| 127 | # Merging side should be similar to applying this patch |
| 128 | git diff ...side >P.diff && |
| 129 | |
| 130 | # The corresponding conflicted merge |
| 131 | git reset --hard && |
| 132 | git checkout main^0 && |
| 133 | test_must_fail git merge --no-commit side && |
| 134 | |
| 135 | # Manually resolve and record the resolution |
| 136 | test_write_lines 1 two 3 4 five six 7 >one && |
| 137 | git rerere && |
| 138 | cat one >expect && |
| 139 | |
| 140 | # should fail to apply |
| 141 | git reset --hard && |
| 142 | git checkout main^0 && |
| 143 | test_must_fail git apply --index --3way P.diff && |
| 144 | |
| 145 | # but rerere should have replayed the recorded resolution |
| 146 | test_cmp expect one |
| 147 | ' |
| 148 | |
| 149 | test_expect_success 'apply -3 with add/add conflict setup' ' |
| 150 | git reset --hard && |
| 151 | |
| 152 | git checkout -b adder && |
| 153 | test_write_lines 1 2 3 4 5 6 7 >three && |
| 154 | test_write_lines 1 2 3 4 5 6 7 >four && |
| 155 | git add three four && |
| 156 | git commit -m "add three and four" && |
| 157 | |
| 158 | git checkout -b another adder^ && |
| 159 | test_write_lines 1 2 3 4 5 6 7 >three && |
| 160 | test_write_lines 1 2 3 four 5 6 7 >four && |
| 161 | git add three four && |
| 162 | git commit -m "add three and four" && |
| 163 | |
| 164 | # Merging another should be similar to applying this patch |
| 165 | git diff adder...another >P.diff && |
| 166 | |
| 167 | git checkout adder^0 && |
| 168 | test_must_fail git merge --no-commit another && |
| 169 | git ls-files -s >expect.ls && |
| 170 | print_sanitized_conflicted_diff >expect.diff |
| 171 | ' |
| 172 | |
| 173 | test_expect_success 'apply -3 with add/add conflict' ' |
| 174 | # should fail to apply ... |
| 175 | git reset --hard && |
| 176 | git checkout adder^0 && |
| 177 | test_must_fail git apply --index --3way P.diff && |
| 178 | # ... and leave conflicts in the index and in the working tree |
| 179 | git ls-files -s >actual.ls && |
| 180 | print_sanitized_conflicted_diff >actual.diff && |
| 181 | |
| 182 | # The result should resemble the corresponding merge |
| 183 | test_cmp expect.ls actual.ls && |
| 184 | test_cmp expect.diff actual.diff |
| 185 | ' |
| 186 | |
| 187 | test_expect_success 'apply -3 with add/add conflict (dirty working tree)' ' |
| 188 | # should fail to apply ... |
| 189 | git reset --hard && |
| 190 | git checkout adder^0 && |
| 191 | echo >>four && |
| 192 | cat four >four.save && |
| 193 | cat three >three.save && |
| 194 | git ls-files -s >expect.ls && |
| 195 | test_must_fail git apply --index --3way P.diff && |
| 196 | # ... and should not touch anything |
| 197 | git ls-files -s >actual.ls && |
| 198 | test_cmp expect.ls actual.ls && |
| 199 | test_cmp four.save four && |
| 200 | test_cmp three.save three |
| 201 | ' |
| 202 | |
| 203 | test_expect_success 'apply -3 with ambiguous repeating file' ' |
| 204 | git reset --hard && |
| 205 | test_write_lines 1 2 1 2 1 2 1 2 1 2 1 >one_two_repeat && |
| 206 | git add one_two_repeat && |
| 207 | git commit -m "init one" && |
| 208 | test_write_lines 1 2 1 2 1 2 1 2 one 2 1 >one_two_repeat && |
| 209 | git commit -a -m "change one" && |
| 210 | |
| 211 | git diff HEAD~ >Repeat.diff && |
| 212 | git reset --hard HEAD~ && |
| 213 | |
| 214 | test_write_lines 1 2 1 2 1 2 one 2 1 2 one >one_two_repeat && |
| 215 | git commit -a -m "change surrounding one" && |
| 216 | |
| 217 | git apply --index --3way Repeat.diff && |
| 218 | test_write_lines 1 2 1 2 1 2 one 2 one 2 one >expect && |
| 219 | |
| 220 | test_cmp expect one_two_repeat |
| 221 | ' |
| 222 | |
| 223 | test_expect_success 'apply with --3way --cached clean apply' ' |
| 224 | # Merging side should be similar to applying this patch |
| 225 | git diff ...side >P.diff && |
| 226 | |
| 227 | # The corresponding cleanly applied merge |
| 228 | git reset --hard && |
| 229 | git checkout main~ && |
| 230 | git merge --no-commit side && |
| 231 | git ls-files -s >expect.ls && |
| 232 | |
| 233 | # should succeed |
| 234 | git reset --hard && |
| 235 | git checkout main~ && |
| 236 | git apply --cached --3way P.diff && |
| 237 | git ls-files -s >actual.ls && |
| 238 | print_sanitized_conflicted_diff >actual.diff && |
| 239 | |
| 240 | # The cache should resemble the corresponding merge |
| 241 | # (both files at stage #0) |
| 242 | test_cmp expect.ls actual.ls && |
| 243 | # However the working directory should not change |
| 244 | >expect.diff && |
| 245 | test_cmp expect.diff actual.diff |
| 246 | ' |
| 247 | |
| 248 | test_expect_success 'apply with --3way --cached and conflicts' ' |
| 249 | # Merging side should be similar to applying this patch |
| 250 | git diff ...side >P.diff && |
| 251 | |
| 252 | # The corresponding conflicted merge |
| 253 | git reset --hard && |
| 254 | git checkout main^0 && |
| 255 | test_must_fail git merge --no-commit side && |
| 256 | git ls-files -s >expect.ls && |
| 257 | |
| 258 | # should fail to apply |
| 259 | git reset --hard && |
| 260 | git checkout main^0 && |
| 261 | test_must_fail git apply --cached --3way P.diff && |
| 262 | git ls-files -s >actual.ls && |
| 263 | print_sanitized_conflicted_diff >actual.diff && |
| 264 | |
| 265 | # The cache should resemble the corresponding merge |
| 266 | # (one file at stage #0, one file at stages #1 #2 #3) |
| 267 | test_cmp expect.ls actual.ls && |
| 268 | # However the working directory should not change |
| 269 | >expect.diff && |
| 270 | test_cmp expect.diff actual.diff |
| 271 | ' |
| 272 | |
| 273 | test_expect_success 'apply binary file patch' ' |
| 274 | git reset --hard main && |
| 275 | cp "$TEST_DIRECTORY/test-binary-1.png" bin.png && |
| 276 | git add bin.png && |
| 277 | git commit -m "add binary file" && |
| 278 | |
| 279 | cp "$TEST_DIRECTORY/test-binary-2.png" bin.png && |
| 280 | |
| 281 | git diff --binary >bin.diff && |
| 282 | git reset --hard && |
| 283 | |
| 284 | # Apply must succeed. |
| 285 | git apply bin.diff |
| 286 | ' |
| 287 | |
| 288 | test_expect_success 'apply binary file patch with 3way' ' |
| 289 | git reset --hard main && |
| 290 | cp "$TEST_DIRECTORY/test-binary-1.png" bin.png && |
| 291 | git add bin.png && |
| 292 | git commit -m "add binary file" && |
| 293 | |
| 294 | cp "$TEST_DIRECTORY/test-binary-2.png" bin.png && |
| 295 | |
| 296 | git diff --binary >bin.diff && |
| 297 | git reset --hard && |
| 298 | |
| 299 | # Apply must succeed. |
| 300 | git apply --3way --index bin.diff |
| 301 | ' |
| 302 | |
| 303 | test_expect_success 'apply full-index patch with 3way' ' |
| 304 | git reset --hard main && |
| 305 | cp "$TEST_DIRECTORY/test-binary-1.png" bin.png && |
| 306 | git add bin.png && |
| 307 | git commit -m "add binary file" && |
| 308 | |
| 309 | cp "$TEST_DIRECTORY/test-binary-2.png" bin.png && |
| 310 | |
| 311 | git diff --full-index >bin.diff && |
| 312 | git reset --hard && |
| 313 | |
| 314 | # Apply must succeed. |
| 315 | git apply --3way --index bin.diff |
| 316 | ' |
| 317 | |
| 318 | test_expect_success 'apply delete then new patch with 3way' ' |
| 319 | git reset --hard main && |
| 320 | test_write_lines 2 > delnew && |
| 321 | git add delnew && |
| 322 | git diff --cached >> new.patch && |
| 323 | git reset --hard && |
| 324 | test_write_lines 1 > delnew && |
| 325 | git add delnew && |
| 326 | git commit -m "delnew" && |
| 327 | rm delnew && |
| 328 | git diff >> delete-then-new.patch && |
| 329 | cat new.patch >> delete-then-new.patch && |
| 330 | |
| 331 | git checkout -- . && |
| 332 | # Apply must succeed. |
| 333 | git apply --3way delete-then-new.patch |
| 334 | ' |
| 335 | |
| 336 | test_done |