| 1 | #!/bin/sh |
| 2 | # |
| 3 | # Copyright (c) 2010 Will Palmer |
| 4 | # |
| 5 | |
| 6 | test_description='git merge-tree' |
| 7 | |
| 8 | . ./test-lib.sh |
| 9 | |
| 10 | test_expect_success setup ' |
| 11 | test_commit "initial" "initial-file" "initial" |
| 12 | ' |
| 13 | |
| 14 | test_expect_success 'file add A, !B' ' |
| 15 | git reset --hard initial && |
| 16 | test_commit "add-a-not-b" "ONE" "AAA" && |
| 17 | git merge-tree initial initial add-a-not-b >actual && |
| 18 | cat >expected <<EXPECTED && |
| 19 | added in remote |
| 20 | their 100644 $(git rev-parse HEAD:ONE) ONE |
| 21 | @@ -0,0 +1 @@ |
| 22 | +AAA |
| 23 | EXPECTED |
| 24 | |
| 25 | test_cmp expected actual |
| 26 | ' |
| 27 | |
| 28 | test_expect_success 'file add !A, B' ' |
| 29 | git reset --hard initial && |
| 30 | test_commit "add-not-a-b" "ONE" "AAA" && |
| 31 | git merge-tree initial add-not-a-b initial >actual && |
| 32 | test_must_be_empty actual |
| 33 | ' |
| 34 | |
| 35 | test_expect_success 'file add A, B (same)' ' |
| 36 | git reset --hard initial && |
| 37 | test_commit "add-a-b-same-A" "ONE" "AAA" && |
| 38 | git reset --hard initial && |
| 39 | test_commit "add-a-b-same-B" "ONE" "AAA" && |
| 40 | git merge-tree initial add-a-b-same-A add-a-b-same-B >actual && |
| 41 | test_must_be_empty actual |
| 42 | ' |
| 43 | |
| 44 | test_expect_success 'file add A, B (different)' ' |
| 45 | git reset --hard initial && |
| 46 | test_commit "add-a-b-diff-A" "ONE" "AAA" && |
| 47 | git reset --hard initial && |
| 48 | test_commit "add-a-b-diff-B" "ONE" "BBB" && |
| 49 | git merge-tree initial add-a-b-diff-A add-a-b-diff-B >actual && |
| 50 | cat >expected <<EXPECTED && |
| 51 | added in both |
| 52 | our 100644 $(git rev-parse add-a-b-diff-A:ONE) ONE |
| 53 | their 100644 $(git rev-parse add-a-b-diff-B:ONE) ONE |
| 54 | @@ -1 +1,5 @@ |
| 55 | +<<<<<<< .our |
| 56 | AAA |
| 57 | +======= |
| 58 | +BBB |
| 59 | +>>>>>>> .their |
| 60 | EXPECTED |
| 61 | |
| 62 | test_cmp expected actual |
| 63 | ' |
| 64 | |
| 65 | test_expect_success 'file change A, !B' ' |
| 66 | git reset --hard initial && |
| 67 | test_commit "change-a-not-b" "initial-file" "BBB" && |
| 68 | git merge-tree initial change-a-not-b initial >actual && |
| 69 | test_must_be_empty actual |
| 70 | ' |
| 71 | |
| 72 | test_expect_success 'file change !A, B' ' |
| 73 | git reset --hard initial && |
| 74 | test_commit "change-not-a-b" "initial-file" "BBB" && |
| 75 | git merge-tree initial initial change-not-a-b >actual && |
| 76 | cat >expected <<EXPECTED && |
| 77 | merged |
| 78 | result 100644 $(git rev-parse change-a-not-b:initial-file) initial-file |
| 79 | our 100644 $(git rev-parse initial:initial-file ) initial-file |
| 80 | @@ -1 +1 @@ |
| 81 | -initial |
| 82 | +BBB |
| 83 | EXPECTED |
| 84 | |
| 85 | test_cmp expected actual |
| 86 | ' |
| 87 | |
| 88 | test_expect_success '3-way merge with --attr-source' ' |
| 89 | test_when_finished rm -rf 3-way && |
| 90 | git init 3-way && |
| 91 | ( |
| 92 | cd 3-way && |
| 93 | test_commit initial file1 foo && |
| 94 | base=$(git rev-parse HEAD) && |
| 95 | git checkout -b brancha && |
| 96 | echo bar >>file1 && |
| 97 | git commit -am "adding bar" && |
| 98 | source=$(git rev-parse HEAD) && |
| 99 | git checkout @{-1} && |
| 100 | git checkout -b branchb && |
| 101 | echo baz >>file1 && |
| 102 | git commit -am "adding baz" && |
| 103 | merge=$(git rev-parse HEAD) && |
| 104 | git checkout -b gitattributes && |
| 105 | test_commit "gitattributes" .gitattributes "file1 merge=union" && |
| 106 | git checkout @{-1} && |
| 107 | tree=$(git --attr-source=gitattributes merge-tree --write-tree \ |
| 108 | --merge-base "$base" --end-of-options "$source" "$merge") && |
| 109 | test_write_lines foo bar baz >expect && |
| 110 | git cat-file -p "$tree:file1" >actual && |
| 111 | test_cmp expect actual |
| 112 | ) |
| 113 | ' |
| 114 | |
| 115 | test_expect_success 'file change A, B (same)' ' |
| 116 | git reset --hard initial && |
| 117 | test_commit "change-a-b-same-A" "initial-file" "AAA" && |
| 118 | git reset --hard initial && |
| 119 | test_commit "change-a-b-same-B" "initial-file" "AAA" && |
| 120 | git merge-tree initial change-a-b-same-A change-a-b-same-B >actual && |
| 121 | test_must_be_empty actual |
| 122 | ' |
| 123 | |
| 124 | test_expect_success 'file change A, B (different)' ' |
| 125 | git reset --hard initial && |
| 126 | test_commit "change-a-b-diff-A" "initial-file" "AAA" && |
| 127 | git reset --hard initial && |
| 128 | test_commit "change-a-b-diff-B" "initial-file" "BBB" && |
| 129 | git merge-tree initial change-a-b-diff-A change-a-b-diff-B >actual && |
| 130 | cat >expected <<EXPECTED && |
| 131 | changed in both |
| 132 | base 100644 $(git rev-parse initial:initial-file ) initial-file |
| 133 | our 100644 $(git rev-parse change-a-b-diff-A:initial-file) initial-file |
| 134 | their 100644 $(git rev-parse change-a-b-diff-B:initial-file) initial-file |
| 135 | @@ -1 +1,5 @@ |
| 136 | +<<<<<<< .our |
| 137 | AAA |
| 138 | +======= |
| 139 | +BBB |
| 140 | +>>>>>>> .their |
| 141 | EXPECTED |
| 142 | |
| 143 | test_cmp expected actual |
| 144 | ' |
| 145 | |
| 146 | test_expect_success 'file change A, B (mixed)' ' |
| 147 | git reset --hard initial && |
| 148 | test_commit "change-a-b-mix-base" "ONE" " |
| 149 | AAA |
| 150 | AAA |
| 151 | AAA |
| 152 | AAA |
| 153 | AAA |
| 154 | AAA |
| 155 | AAA |
| 156 | AAA |
| 157 | AAA |
| 158 | AAA |
| 159 | AAA |
| 160 | AAA |
| 161 | AAA |
| 162 | AAA |
| 163 | AAA" && |
| 164 | test_commit "change-a-b-mix-A" "ONE" \ |
| 165 | "$(sed -e "1{s/AAA/BBB/;}" -e "10{s/AAA/BBB/;}" <ONE)" && |
| 166 | git reset --hard change-a-b-mix-base && |
| 167 | test_commit "change-a-b-mix-B" "ONE" \ |
| 168 | "$(sed -e "1{s/AAA/BBB/;}" -e "10{s/AAA/CCC/;}" <ONE)" && |
| 169 | git merge-tree change-a-b-mix-base change-a-b-mix-A change-a-b-mix-B \ |
| 170 | >actual && |
| 171 | |
| 172 | cat >expected <<EXPECTED && |
| 173 | changed in both |
| 174 | base 100644 $(git rev-parse change-a-b-mix-base:ONE) ONE |
| 175 | our 100644 $(git rev-parse change-a-b-mix-A:ONE ) ONE |
| 176 | their 100644 $(git rev-parse change-a-b-mix-B:ONE ) ONE |
| 177 | @@ -7,7 +7,11 @@ |
| 178 | AAA |
| 179 | AAA |
| 180 | AAA |
| 181 | +<<<<<<< .our |
| 182 | BBB |
| 183 | +======= |
| 184 | +CCC |
| 185 | +>>>>>>> .their |
| 186 | AAA |
| 187 | AAA |
| 188 | AAA |
| 189 | EXPECTED |
| 190 | |
| 191 | test_cmp expected actual |
| 192 | ' |
| 193 | |
| 194 | test_expect_success 'file remove A, !B' ' |
| 195 | git reset --hard initial && |
| 196 | test_commit "rm-a-not-b-base" "ONE" "AAA" && |
| 197 | git rm ONE && |
| 198 | git commit -m "rm-a-not-b" && |
| 199 | git tag "rm-a-not-b" && |
| 200 | git merge-tree rm-a-not-b-base rm-a-not-b rm-a-not-b-base >actual && |
| 201 | test_must_be_empty actual |
| 202 | ' |
| 203 | |
| 204 | test_expect_success 'file remove !A, B' ' |
| 205 | git reset --hard initial && |
| 206 | test_commit "rm-not-a-b-base" "ONE" "AAA" && |
| 207 | git rm ONE && |
| 208 | git commit -m "rm-not-a-b" && |
| 209 | git tag "rm-not-a-b" && |
| 210 | git merge-tree rm-a-not-b-base rm-a-not-b-base rm-a-not-b >actual && |
| 211 | cat >expected <<EXPECTED && |
| 212 | removed in remote |
| 213 | base 100644 $(git rev-parse rm-a-not-b-base:ONE) ONE |
| 214 | our 100644 $(git rev-parse rm-a-not-b-base:ONE) ONE |
| 215 | @@ -1 +0,0 @@ |
| 216 | -AAA |
| 217 | EXPECTED |
| 218 | |
| 219 | test_cmp expected actual |
| 220 | ' |
| 221 | |
| 222 | test_expect_success 'file remove A, B (same)' ' |
| 223 | git reset --hard initial && |
| 224 | test_commit "rm-a-b-base" "ONE" "AAA" && |
| 225 | git rm ONE && |
| 226 | git commit -m "rm-a-b" && |
| 227 | git tag "rm-a-b" && |
| 228 | git merge-tree rm-a-b-base rm-a-b rm-a-b >actual && |
| 229 | test_must_be_empty actual |
| 230 | ' |
| 231 | |
| 232 | test_expect_success 'file change A, remove B' ' |
| 233 | git reset --hard initial && |
| 234 | test_commit "change-a-rm-b-base" "ONE" "AAA" && |
| 235 | test_commit "change-a-rm-b-A" "ONE" "BBB" && |
| 236 | git reset --hard change-a-rm-b-base && |
| 237 | git rm ONE && |
| 238 | git commit -m "change-a-rm-b-B" && |
| 239 | git tag "change-a-rm-b-B" && |
| 240 | git merge-tree change-a-rm-b-base change-a-rm-b-A change-a-rm-b-B \ |
| 241 | >actual && |
| 242 | cat >expected <<EXPECTED && |
| 243 | removed in remote |
| 244 | base 100644 $(git rev-parse change-a-rm-b-base:ONE) ONE |
| 245 | our 100644 $(git rev-parse change-a-rm-b-A:ONE ) ONE |
| 246 | @@ -1 +0,0 @@ |
| 247 | -BBB |
| 248 | EXPECTED |
| 249 | |
| 250 | test_cmp expected actual |
| 251 | ' |
| 252 | |
| 253 | test_expect_success 'file remove A, change B' ' |
| 254 | git reset --hard initial && |
| 255 | test_commit "rm-a-change-b-base" "ONE" "AAA" && |
| 256 | |
| 257 | git rm ONE && |
| 258 | git commit -m "rm-a-change-b-A" && |
| 259 | git tag "rm-a-change-b-A" && |
| 260 | git reset --hard rm-a-change-b-base && |
| 261 | test_commit "rm-a-change-b-B" "ONE" "BBB" && |
| 262 | git merge-tree rm-a-change-b-base rm-a-change-b-A rm-a-change-b-B \ |
| 263 | >actual && |
| 264 | cat >expected <<EXPECTED && |
| 265 | removed in local |
| 266 | base 100644 $(git rev-parse rm-a-change-b-base:ONE) ONE |
| 267 | their 100644 $(git rev-parse rm-a-change-b-B:ONE ) ONE |
| 268 | EXPECTED |
| 269 | test_cmp expected actual |
| 270 | ' |
| 271 | |
| 272 | test_expect_success 'tree add A, B (same)' ' |
| 273 | git reset --hard initial && |
| 274 | mkdir sub && |
| 275 | test_commit "add sub/file" "sub/file" "file" add-tree-A && |
| 276 | git merge-tree initial add-tree-A add-tree-A >actual && |
| 277 | test_must_be_empty actual |
| 278 | ' |
| 279 | |
| 280 | test_expect_success 'tree add A, B (different)' ' |
| 281 | git reset --hard initial && |
| 282 | mkdir sub && |
| 283 | test_commit "add sub/file" "sub/file" "AAA" add-tree-a-b-A && |
| 284 | git reset --hard initial && |
| 285 | mkdir sub && |
| 286 | test_commit "add sub/file" "sub/file" "BBB" add-tree-a-b-B && |
| 287 | git merge-tree initial add-tree-a-b-A add-tree-a-b-B >actual && |
| 288 | cat >expect <<-EOF && |
| 289 | added in both |
| 290 | our 100644 $(git rev-parse add-tree-a-b-A:sub/file) sub/file |
| 291 | their 100644 $(git rev-parse add-tree-a-b-B:sub/file) sub/file |
| 292 | @@ -1 +1,5 @@ |
| 293 | +<<<<<<< .our |
| 294 | AAA |
| 295 | +======= |
| 296 | +BBB |
| 297 | +>>>>>>> .their |
| 298 | EOF |
| 299 | test_cmp expect actual |
| 300 | ' |
| 301 | |
| 302 | test_expect_success 'tree unchanged A, removed B' ' |
| 303 | git reset --hard initial && |
| 304 | mkdir sub && |
| 305 | test_commit "add sub/file" "sub/file" "AAA" tree-remove-b-initial && |
| 306 | git rm sub/file && |
| 307 | test_tick && |
| 308 | git commit -m "remove sub/file" && |
| 309 | git tag tree-remove-b-B && |
| 310 | git merge-tree tree-remove-b-initial tree-remove-b-initial tree-remove-b-B >actual && |
| 311 | cat >expect <<-EOF && |
| 312 | removed in remote |
| 313 | base 100644 $(git rev-parse tree-remove-b-initial:sub/file) sub/file |
| 314 | our 100644 $(git rev-parse tree-remove-b-initial:sub/file) sub/file |
| 315 | @@ -1 +0,0 @@ |
| 316 | -AAA |
| 317 | EOF |
| 318 | test_cmp expect actual |
| 319 | ' |
| 320 | |
| 321 | test_expect_success 'turn file to tree' ' |
| 322 | git reset --hard initial && |
| 323 | rm initial-file && |
| 324 | mkdir initial-file && |
| 325 | test_commit "turn-file-to-tree" "initial-file/ONE" "CCC" && |
| 326 | git merge-tree initial initial turn-file-to-tree >actual && |
| 327 | cat >expect <<-EOF && |
| 328 | added in remote |
| 329 | their 100644 $(git rev-parse turn-file-to-tree:initial-file/ONE) initial-file/ONE |
| 330 | @@ -0,0 +1 @@ |
| 331 | +CCC |
| 332 | removed in remote |
| 333 | base 100644 $(git rev-parse initial:initial-file) initial-file |
| 334 | our 100644 $(git rev-parse initial:initial-file) initial-file |
| 335 | @@ -1 +0,0 @@ |
| 336 | -initial |
| 337 | EOF |
| 338 | test_cmp expect actual |
| 339 | ' |
| 340 | |
| 341 | test_expect_success 'turn tree to file' ' |
| 342 | git reset --hard initial && |
| 343 | mkdir dir && |
| 344 | test_commit "add-tree" "dir/path" "AAA" && |
| 345 | test_commit "add-another-tree" "dir/another" "BBB" && |
| 346 | rm -fr dir && |
| 347 | test_commit "make-file" "dir" "CCC" && |
| 348 | git merge-tree add-tree add-another-tree make-file >actual && |
| 349 | cat >expect <<-EOF && |
| 350 | removed in remote |
| 351 | base 100644 $(git rev-parse add-tree:dir/path) dir/path |
| 352 | our 100644 $(git rev-parse add-tree:dir/path) dir/path |
| 353 | @@ -1 +0,0 @@ |
| 354 | -AAA |
| 355 | added in remote |
| 356 | their 100644 $(git rev-parse make-file:dir) dir |
| 357 | @@ -0,0 +1 @@ |
| 358 | +CCC |
| 359 | EOF |
| 360 | test_cmp expect actual |
| 361 | ' |
| 362 | |
| 363 | test_expect_success 'merge-tree respects core.useReplaceRefs=false' ' |
| 364 | test_commit merge-to && |
| 365 | test_commit valid base && |
| 366 | git reset --hard HEAD^ && |
| 367 | test_commit malicious base && |
| 368 | |
| 369 | test_when_finished "git replace -d $(git rev-parse valid^0)" && |
| 370 | git replace valid^0 malicious^0 && |
| 371 | |
| 372 | tree=$(git -c core.useReplaceRefs=true merge-tree --write-tree merge-to valid) && |
| 373 | merged=$(git cat-file -p $tree:base) && |
| 374 | test malicious = $merged && |
| 375 | |
| 376 | tree=$(git -c core.useReplaceRefs=false merge-tree --write-tree merge-to valid) && |
| 377 | merged=$(git cat-file -p $tree:base) && |
| 378 | test valid = $merged |
| 379 | ' |
| 380 | |
| 381 | test_done |