| 1 | #!/usr/bin/env bash
|
| 2 | set -eu -o pipefail
|
| 3 |
|
| 4 | function tick () {
|
| 5 | if test -z "${tick+set}"
|
| 6 | then
|
| 7 | tick=1112911993
|
| 8 | else
|
| 9 | tick=$(($tick + 60))
|
| 10 | fi
|
| 11 | GIT_COMMITTER_DATE="$tick -0700"
|
| 12 | GIT_AUTHOR_DATE="$tick -0700"
|
| 13 | export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
|
| 14 | }
|
| 15 |
|
| 16 | # Translate a historical SHA-1 object id (as hard-coded in the `git update-index
|
| 17 | # --index-info` blocks below) to the equivalent id under the repository's
|
| 18 | # current hash algorithm, so these baselines work under both SHA-1 and SHA-256.
|
| 19 | function oid () {
|
| 20 | case "${GIT_DEFAULT_HASH:-sha1}" in
|
| 21 | sha1)
|
| 22 | printf '%s' "$1"
|
| 23 | return
|
| 24 | ;;
|
| 25 | sha256)
|
| 26 | ;;
|
| 27 | *)
|
| 28 | echo "oid(): unsupported object hash '${GIT_DEFAULT_HASH}', expected 'sha1' or 'sha256'" >&2
|
| 29 | return 1
|
| 30 | ;;
|
| 31 | esac
|
| 32 | case "$1" in
|
| 33 | 092bfb9bdf74dd8cfd22e812151281ee9aa6f01a) echo d246bf89e9d0f356301a75184ab79e68cfcb0aac1a7acbf3d4de81400b5ee231 ;;
|
| 34 | 09c277aa66897c58157f57a374eacc63a407dcab) echo cf8aedf347c947abf6c6e2c4ecaa2e086ea61ce81f52491c453b81c6455f305e ;;
|
| 35 | 0a6a0ba83635bc00e7c79a4b5b6e50381385c1af) echo be45c0023fb9c5e05387235ef07be7e7e2034838216cd24cca06840cc01bc771 ;;
|
| 36 | 0cde534c2fca6c92c07b3e7a696665e844b9b933) echo cc0d90a1291b62ffbf9288fad4e290e3a85160cef42c708be3b8a90ac13d501b ;;
|
| 37 | 19102815663d23f8b75a47e7a01965dcdc96468c) echo a65ca4376b51e98097fec3a009b7e5adce3255aecaa1a6da7b1cdc92b90e025e ;;
|
| 38 | 1a2664a9924754c698e323f756f9f87f3f2fb337) echo cff0bb6fba5633bd804f0a15fed6329ede0a9dfc4a7f53e31581f3d1a2005e0f ;;
|
| 39 | 257cc5642cb1a054f08cc83f2d943e56fd3ebe99) echo 47d6aca82756ff2e61e53520bfdf1faa6c86d933be4854eb34840c57d12e0c85 ;;
|
| 40 | 4178ea6795c4c3e07b4e17e6a04aa49584b07ecd) echo 60becdf11d1fcac5bdafbebf1f3e5c7dec1463f8381bcc8bfb533262ec3b1fa8 ;;
|
| 41 | 44065282f89b9bd6439ed2e4674721383fd987eb) echo 6632209c4f376d0d893dcb49cd85f0abf9fb1bb0f79c2c6c998adef4d95cac95 ;;
|
| 42 | 45b983be36b73c0788dc9cbcb76cbb80fc7bb057) echo 96c18f0297e38d01f4b2dacddea4259aea6b2961eb0822bd2c0c3f6029030045 ;;
|
| 43 | 4b5599c7c2ed4390417d9699bec86144a386873d) echo 54b65f98d2bdee38cacc335639121482f497d71b6c9874002b637173f2cc212b ;;
|
| 44 | 542802a799ded74fa01c47ba2f8925e284a369e2) echo 863a67a88f3ae07c9c4784fbed16d4f8eabea50aa40923804f7435c45c4bcb1e ;;
|
| 45 | 5716ca5987cbf97d6bb54920bea6adde242d87e6) echo a52e146ac2ab2d0efbb768ab8ebd1e98a6055764c81fe424fbae4522f5b4cb92 ;;
|
| 46 | 61780798228d17af2d34fce4cfbdf35556832472) echo 9b69d308c97f2c5933fdd0e8ce04acce91c09cb969e36a1f86756fc5a5d3323a ;;
|
| 47 | 64012489f118cb4011c8902b4a635f70dcb0c0ca) echo 24bba3b983b179b8ceb5b7af0995c745dbe07f36b75e593b28e000c7d26aa1e5 ;;
|
| 48 | 65bc6a1e238f4bf05b28fd05240636e2cfb657e0) echo 315347e306b9d8222324e6f48a1f585074712267eae89d34ef607663046cb3e3 ;;
|
| 49 | 78981922613b2afb6025042ff6bd878ac1994e85) echo f8625e43f9e04f24291f77cdbe4c71b3c2a3b0003f60419b3ed06a058d766c8b ;;
|
| 50 | 8a1218a1024a212bb3db30becd860315f9f3ac52) echo 6841122c240e69074e82e38506c1fcf806c3ee2469673392a9ed7650d7a6d51d ;;
|
| 51 | 9dc97bdc2426e68423360e3e5299280b2cf6b8ff) echo 7108d070fd9fde47d46504102c6935d9251cce816fdbdcc6c1d56710f11790d1 ;;
|
| 52 | a4ae6e4709228b5da6001cb9d1cfa7736851e2a6) echo c3ae6188533b9bea9ad1049892c6b5488fffe5cfc518b30ba21b64a124bc7afe ;;
|
| 53 | b414108e81e5091fe0974a1858b4d0d22b107f70) echo f5f52958fe19d6073227d52208826e0d189bfdb9d0c428984244075155e57c71 ;;
|
| 54 | d0549c3d3c96a464289f3b820b7d96aedc58924b) echo 7960eaf2c5f3ac192aa208323a78bf4b0f2fb21d79813af79a78674698689442 ;;
|
| 55 | d5f7fc3f74f7dec08280f370a975b112e8f60818) echo ffc23e0956239fed93c95c4cf3d3152a887825f756309251d71bb16f261afabd ;;
|
| 56 | df967b96a579e45a18b8251732d16804b2e56a55) echo abed979e3cd3667c5a295c2641f8319f950860c65cc168eebd1571c51bb4f6fc ;;
|
| 57 | e29fa63dae4ccf0788897a7025da868083178fdf) echo 577603f537e595c5324b5987646cb9073d159a4f0c9e73f820d2ee83c8926acf ;;
|
| 58 | e33f5e94470d3b5fa0220ff6a9cabb78a3f72fa3) echo 72a7259eef0664ef8dae2039c11c61ec4dd039f94eee87a21c6ee1c637b7cca0 ;;
|
| 59 | e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) echo 473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 ;;
|
| 60 | ea28dcd7f627a2a7bbd09daa679c452180617c9f) echo efd6b0b052df02752b7f371021660541dcb8f2b0665c19b672b031af7c086588 ;;
|
| 61 | f286e5cdd97ac6895438ea4548638bb98ac9bd6b) echo 33ba40b57f32a1383518de4f91d9eaf8bf5eb55e318f47215af5c367f9778b9b ;;
|
| 62 | f2ad6c76f0115a6ba5b00456a849810e7ec0af20) echo 2abe107e3b1b618efafa0df5e5f1118e5bf86694eb8c185741e67795ae314aa4 ;;
|
| 63 | f801a62deed900f8a80ff35e3339474ad6352a93) echo 970d16592cccbb8ce3846be7a74ecb94bc3bf8d01bec1eeb15a57380aae5d5a3 ;;
|
| 64 | f89a08d1e226b9a319210641b63b07dcf0bd705f) echo 43d8308eb726995b8b6a3f826252dd21dc35d01386931b8eea4125723e36cc83 ;;
|
| 65 | fa49b077972391ad58037050f2a75f74e3671e92) echo 6d5fd291bb0f67444e99ab492f1bf1fcdf5dca09dab24cf331e05111b4cfc1a3 ;;
|
| 66 | # gitlinks: submodule 'sub' commits (sub-root, sub-a, sub-b), deterministic from the fixed tick dates
|
| 67 | e835c0c403c8e494c0ca98f3d25d0b8464c18d38) echo ed2d65b7fe3c3f869a21cfec7f54867db6c8eb2cc9b0bf671522d87599704d70 ;;
|
| 68 | 64466ebdff775ad618d9cc993cf52840e0af528c) echo df5d889015388598b724a741b53437e4dee9d67a5dbe0fa9f361fedd4c9ac6e8 ;;
|
| 69 | ea6eb701e03c2497915c25a851f3da8f8e362ca0) echo c79d38d6c8161bf2aec16032f82127c7ac237eeab69e1490422c93b5c314ce9c ;;
|
| 70 | *) echo "oid(): no SHA-256 mapping for '$1'" >&2; return 1 ;;
|
| 71 | esac
|
| 72 | }
|
| 73 |
|
| 74 | function write_lines () {
|
| 75 | printf "%s\n" "$@"
|
| 76 | }
|
| 77 |
|
| 78 | function seq () {
|
| 79 | case $# in
|
| 80 | 1) set 1 "$@" ;;
|
| 81 | 2) ;;
|
| 82 | *) { echo "need 1 or 2 parameters: <end> or <start> <end>" 1>&2 && exit 2; } ;;
|
| 83 | esac
|
| 84 | local seq_counter=$1
|
| 85 | while test "$seq_counter" -le "$2"
|
| 86 | do
|
| 87 | echo "$seq_counter"
|
| 88 | seq_counter=$(( seq_counter + 1 ))
|
| 89 | done
|
| 90 | }
|
| 91 |
|
| 92 | function make_conflict_index() {
|
| 93 | local identifier=${1:?The first argument is the name of the parent directory along with the output name}
|
| 94 | cp .git/index .git/"${identifier}".index
|
| 95 | }
|
| 96 |
|
| 97 | function make_resolve_tree() {
|
| 98 | local resolve=${1:?Their 'ancestor' or 'ours'}
|
| 99 | local our_side=${2:-}
|
| 100 | local their_side=${3:-}
|
| 101 |
|
| 102 | local filename="resolve-${our_side}-${their_side}-with-${resolve}"
|
| 103 | git write-tree > ".git/${filename}.tree"
|
| 104 | }
|
| 105 |
|
| 106 | function baseline () (
|
| 107 | local dir=${1:?the directory to enter}
|
| 108 | local output_name=${2:?the basename of the output of the merge}
|
| 109 | local our_committish=${3:?our side from which a commit can be derived}
|
| 110 | local their_committish=${4:?Their side from which a commit can be derived}
|
| 111 | local opt_deviation_message=${5:-}
|
| 112 | local one_side=${6:-}
|
| 113 |
|
| 114 | cd "$dir"
|
| 115 | local our_commit_id
|
| 116 | local their_commit_id
|
| 117 |
|
| 118 | local conflict_style="merge"
|
| 119 | if [[ "$output_name" == *-merge ]]; then
|
| 120 | conflict_style="merge"
|
| 121 | elif [[ "$output_name" == *-diff3 ]]; then
|
| 122 | conflict_style="diff3"
|
| 123 | fi
|
| 124 |
|
| 125 | our_commit_id="$(git rev-parse "$our_committish")"
|
| 126 | their_commit_id="$(git rev-parse "$their_committish")"
|
| 127 | local maybe_expected_tree="$(git rev-parse expected^{tree})"
|
| 128 | local maybe_expected_reversed_tree="$(git rev-parse expected-reversed^{tree})"
|
| 129 | if [ "$maybe_expected_reversed_tree" == "expected-reversed^{tree}" ]; then
|
| 130 | maybe_expected_reversed_tree="$(git rev-parse expected^{tree} || :)"
|
| 131 | fi
|
| 132 | if [ -z "$opt_deviation_message" ]; then
|
| 133 | maybe_expected_tree="expected^{tree}"
|
| 134 | maybe_expected_reversed_tree="expected^{tree}"
|
| 135 | fi
|
| 136 |
|
| 137 | local merge_info="${output_name}.merge-info"
|
| 138 | git -c merge.conflictStyle=$conflict_style merge-tree -z --write-tree --allow-unrelated-histories "$our_committish" "$their_committish" > "$merge_info" || :
|
| 139 | echo "$dir" "$conflict_style" "$our_commit_id" "$our_committish" "$their_commit_id" "$their_committish" "$merge_info" "$maybe_expected_tree" "$opt_deviation_message" >> ../baseline.cases
|
| 140 |
|
| 141 | if [[ "$one_side" != "no-reverse" ]]; then
|
| 142 | local merge_info="${output_name}-reversed.merge-info"
|
| 143 | git -c merge.conflictStyle=$conflict_style merge-tree -z --write-tree --allow-unrelated-histories "$their_committish" "$our_committish" > "$merge_info" || :
|
| 144 | echo "$dir" "$conflict_style" "$their_commit_id" "$their_committish" "$our_commit_id" "$our_committish" "$merge_info" "$maybe_expected_reversed_tree" "$opt_deviation_message" >> ../baseline.cases
|
| 145 | fi
|
| 146 | )
|
| 147 |
|
| 148 |
|
| 149 | git init non-tree-to-tree
|
| 150 | (cd non-tree-to-tree
|
| 151 | write_lines original 1 2 3 4 5 >a
|
| 152 | git add a && git commit -m "init"
|
| 153 |
|
| 154 | git branch A
|
| 155 | git branch B
|
| 156 |
|
| 157 | git checkout A
|
| 158 | write_lines 1 2 3 4 5 6 >a
|
| 159 | git commit -am "'A' changes 'a'"
|
| 160 |
|
| 161 | git checkout B
|
| 162 | rm a
|
| 163 | mkdir -p a/sub
|
| 164 | touch a/sub/b a/sub/c a/d a/e
|
| 165 | git add a && git commit -m "mv 'a' to 'a/sub/b', populate 'a/' with empty files"
|
| 166 | )
|
| 167 |
|
| 168 | git init deleted-file-added-dir
|
| 169 | (cd deleted-file-added-dir
|
| 170 | echo original >to-be-deleted
|
| 171 | git add to-be-deleted && git commit -m "init"
|
| 172 |
|
| 173 | git branch A
|
| 174 | git branch B
|
| 175 |
|
| 176 | git checkout A
|
| 177 | git rm to-be-deleted
|
| 178 | git commit -m "delete file"
|
| 179 |
|
| 180 | git checkout B
|
| 181 | git rm to-be-deleted
|
| 182 | mkdir to-be-deleted
|
| 183 | touch to-be-deleted/a
|
| 184 | git add to-be-deleted/a && git commit -m "replace file with directory"
|
| 185 | )
|
| 186 |
|
| 187 | git init deleted-file-added-gitlink-directory
|
| 188 | (cd deleted-file-added-gitlink-directory
|
| 189 | write_lines original >a
|
| 190 | git add a
|
| 191 | git commit -m "file base"
|
| 192 | base=$(git rev-parse HEAD)
|
| 193 |
|
| 194 | git branch A
|
| 195 | git branch B
|
| 196 |
|
| 197 | # Both sides delete `a`; B additionally replaces it with a directory containing
|
| 198 | # a gitlink. The shared deletion and descendant addition are compatible even
|
| 199 | # though the gitlink takes a different structural merge path than a blob.
|
| 200 | git checkout A
|
| 201 | git rm a
|
| 202 | git commit -m "delete a"
|
| 203 |
|
| 204 | git checkout B
|
| 205 | git rm a
|
| 206 | git update-index --add --cacheinfo 160000,$base,a/a
|
| 207 | git commit -m "replace a with a gitlink directory"
|
| 208 | )
|
| 209 |
|
| 210 | git init tree-to-non-tree
|
| 211 | (cd tree-to-non-tree
|
| 212 | mkdir -p a/sub
|
| 213 | write_lines original 1 2 3 4 5 >a/sub/b
|
| 214 | touch a/sub/c a/d a/e
|
| 215 | git add a && git commit -m "init"
|
| 216 |
|
| 217 | git branch A
|
| 218 | git branch B
|
| 219 |
|
| 220 | git checkout A
|
| 221 | write_lines 1 2 3 4 5 6 >a/sub/b
|
| 222 | git commit -am "'A' changes 'a/sub/b'"
|
| 223 |
|
| 224 | git checkout B
|
| 225 | rm -Rf a
|
| 226 | echo "new file" > a
|
| 227 | git add a && git commit -m "rm -Rf a/ && add non-empty 'a'"
|
| 228 | )
|
| 229 |
|
| 230 | git init non-tree-to-tree-with-rename
|
| 231 | (cd non-tree-to-tree-with-rename
|
| 232 | write_lines original 1 2 3 4 5 >a
|
| 233 | git add a && git commit -m "init"
|
| 234 |
|
| 235 | git branch A
|
| 236 | git branch B
|
| 237 |
|
| 238 | git checkout A
|
| 239 | write_lines 1 2 3 4 5 6 >a
|
| 240 | git commit -am "'A' changes 'a'"
|
| 241 |
|
| 242 | git checkout B
|
| 243 | mv a tmp
|
| 244 | mkdir -p a/sub
|
| 245 | mv tmp a/sub/b
|
| 246 | touch a/sub/c a/d a/e
|
| 247 | git add a && git commit -m "mv 'a' to 'a/sub/b', populate 'a/' with empty files"
|
| 248 | )
|
| 249 |
|
| 250 | git init tree-to-non-tree-with-rename
|
| 251 | (cd tree-to-non-tree-with-rename
|
| 252 | mkdir -p a/sub
|
| 253 | write_lines original 1 2 3 4 5 >a/sub/b
|
| 254 | touch a/sub/c a/d a/e
|
| 255 | git add a && git commit -m "init"
|
| 256 |
|
| 257 | git branch A
|
| 258 | git branch B
|
| 259 |
|
| 260 | git checkout A
|
| 261 | write_lines 1 2 3 4 5 6 >a/sub/b
|
| 262 | git commit -am "'A' changes 'a/sub/b'"
|
| 263 |
|
| 264 | git checkout B
|
| 265 | rm -Rf a
|
| 266 | touch a
|
| 267 | git add a && git commit -m "rm -Rf a/ && add empty 'a' (which is like a rename from an empty deleted file)"
|
| 268 | # And because it's so thrown off, it gets a completely different result if reversed.
|
| 269 | git branch expected-reversed
|
| 270 |
|
| 271 | rm .git/index
|
| 272 | git update-index --index-info <<EOF
|
| 273 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/b
|
| 274 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a/sub/b
|
| 275 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a~B
|
| 276 | EOF
|
| 277 | make_conflict_index tree-to-non-tree-with-rename-A-B
|
| 278 |
|
| 279 | rm .git/index
|
| 280 | git update-index --index-info <<EOF
|
| 281 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/b
|
| 282 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a/sub/b
|
| 283 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a~B
|
| 284 | EOF
|
| 285 | make_conflict_index tree-to-non-tree-with-rename-A-B-reversed
|
| 286 | )
|
| 287 |
|
| 288 | git init simple
|
| 289 | (cd simple
|
| 290 | rm -Rf .git/hooks
|
| 291 | write_lines 1 2 3 4 5 >numbers
|
| 292 | echo hello >greeting
|
| 293 | echo foo >whatever
|
| 294 | git add numbers greeting whatever
|
| 295 | tick
|
| 296 | git commit -m initial
|
| 297 |
|
| 298 | git branch side1
|
| 299 | git branch side2
|
| 300 | git branch side3
|
| 301 | git branch side4
|
| 302 |
|
| 303 | git checkout side1
|
| 304 | write_lines 1 2 3 4 5 6 >numbers
|
| 305 | echo hi >greeting
|
| 306 | echo bar >whatever
|
| 307 | git add numbers greeting whatever
|
| 308 | tick
|
| 309 | git commit -m modify-stuff
|
| 310 |
|
| 311 | git checkout side2
|
| 312 | write_lines 0 1 2 3 4 5 >numbers
|
| 313 | echo yo >greeting
|
| 314 | git rm whatever
|
| 315 | mkdir whatever
|
| 316 | >whatever/empty
|
| 317 | git add numbers greeting whatever/empty
|
| 318 | tick
|
| 319 | git commit -m other-modifications
|
| 320 |
|
| 321 | git checkout side3
|
| 322 | git mv numbers sequence
|
| 323 | tick
|
| 324 | git commit -m rename-numbers
|
| 325 |
|
| 326 | git checkout side4
|
| 327 | write_lines 0 1 2 3 4 5 >numbers
|
| 328 | echo yo >greeting
|
| 329 | git add numbers greeting
|
| 330 | tick
|
| 331 | git commit -m other-content-modifications
|
| 332 |
|
| 333 | git switch --orphan unrelated
|
| 334 | >something-else
|
| 335 | git add something-else
|
| 336 | tick
|
| 337 | git commit -m first-commit
|
| 338 |
|
| 339 | git checkout -b tweak1 side1
|
| 340 | write_lines zero 1 2 3 4 5 6 >numbers
|
| 341 | git add numbers
|
| 342 | git mv numbers "Αυτά μου φαίνονται κινέζικα"
|
| 343 | git commit -m "Renamed numbers"
|
| 344 | )
|
| 345 |
|
| 346 | git init rename-delete
|
| 347 | (cd rename-delete
|
| 348 | write_lines 1 2 3 4 5 >foo
|
| 349 | mkdir olddir
|
| 350 | for i in a b c; do echo $i >olddir/$i; done
|
| 351 | git add foo olddir
|
| 352 | git commit -m "original"
|
| 353 |
|
| 354 | git branch A
|
| 355 | git branch B
|
| 356 |
|
| 357 | git checkout A
|
| 358 | write_lines 1 2 3 4 5 6 >foo
|
| 359 | git add foo
|
| 360 | git mv olddir newdir
|
| 361 | git commit -m "Modify foo, rename olddir to newdir"
|
| 362 |
|
| 363 | git checkout B
|
| 364 | write_lines 1 2 3 4 5 six >foo
|
| 365 | git add foo
|
| 366 | git mv foo olddir/bar
|
| 367 | git commit -m "Modify foo & rename foo -> olddir/bar"
|
| 368 | )
|
| 369 |
|
| 370 | git init rename-change-matrix
|
| 371 | (cd rename-change-matrix
|
| 372 | # Each top-level directory is one independent rename interaction:
|
| 373 | #
|
| 374 | # * modify-source:
|
| 375 | # A renames `file` to `renamed`; B modifies `file`.
|
| 376 | # The modification follows the rename and the result is clean at `renamed`.
|
| 377 | # * delete-source:
|
| 378 | # A renames `file` to `renamed`; B deletes `file`.
|
| 379 | # This is a rename/delete conflict, with A's renamed file retained.
|
| 380 | # * add-destination:
|
| 381 | # A renames `file` to `target`; B adds an unrelated `target`.
|
| 382 | # Both additions occupy the rename destination, producing an add/add conflict.
|
| 383 | # * modify-destination:
|
| 384 | # A replaces the existing `target` by renaming `source` onto it; B modifies the old `target`.
|
| 385 | # The merge remains tied to the destination path: the base is the old `target`, A replaces all
|
| 386 | # of it with `source`, and B appends to the old `target`. Those edits conflict, preserving the
|
| 387 | # complete A and B versions inside conflict markers.
|
| 388 | # * delete-destination:
|
| 389 | # A replaces the existing `target` by renaming `source` onto it; B deletes the old `target`.
|
| 390 | # The deletion conflicts with A's replacement, which remains at `target`.
|
| 391 | # * different-renames:
|
| 392 | # A and B both modify `file`, then rename it to different destinations.
|
| 393 | # Both destinations contain the one merged result, with a content conflict for the two appends.
|
| 394 | # Its configured marker size is 10; the rename/rename conflict adds one, yielding 11.
|
| 395 | # * directory-old:
|
| 396 | # A renames the directory; B adds a child below its old name.
|
| 397 | # The child follows the directory rename and the result is clean below `directory-renamed`.
|
| 398 | #
|
| 399 | # Distinct repeated words keep rename similarity pairing local to each case.
|
| 400 | mkdir -p modify-source delete-source add-destination modify-destination delete-destination \
|
| 401 | different-renames directory-old
|
| 402 | write_lines alpha alpha alpha alpha alpha >modify-source/file
|
| 403 | write_lines bravo bravo bravo bravo bravo >delete-source/file
|
| 404 | write_lines charlie charlie charlie charlie charlie >add-destination/file
|
| 405 | write_lines delta-source delta-source delta-source delta-source delta-source >modify-destination/source
|
| 406 | write_lines delta-target delta-target delta-target delta-target delta-target >modify-destination/target
|
| 407 | write_lines echo-source echo-source echo-source echo-source echo-source >delete-destination/source
|
| 408 | write_lines echo-target echo-target echo-target echo-target echo-target >delete-destination/target
|
| 409 | write_lines golf golf golf golf golf >different-renames/file
|
| 410 | write_lines juliet juliet juliet juliet juliet >directory-old/file
|
| 411 | echo 'different-renames/* conflict-marker-size=10' >.gitattributes
|
| 412 | git add . && git commit -m "base"
|
| 413 |
|
| 414 | git branch A
|
| 415 | git branch B
|
| 416 |
|
| 417 | git checkout A
|
| 418 | git mv modify-source/file modify-source/renamed
|
| 419 | git mv delete-source/file delete-source/renamed
|
| 420 | git mv add-destination/file add-destination/target
|
| 421 | git rm modify-destination/target
|
| 422 | git mv modify-destination/source modify-destination/target
|
| 423 | git rm delete-destination/target
|
| 424 | git mv delete-destination/source delete-destination/target
|
| 425 | echo changed-by-A >>different-renames/file
|
| 426 | git mv different-renames/file different-renames/ours
|
| 427 | git mv directory-old directory-renamed
|
| 428 | git commit -am "rename one side of each matrix entry"
|
| 429 |
|
| 430 | git checkout B
|
| 431 | echo changed-by-B >>modify-source/file
|
| 432 | git rm delete-source/file
|
| 433 | echo added-by-B >add-destination/target
|
| 434 | echo changed-by-B >>modify-destination/target
|
| 435 | git rm delete-destination/target
|
| 436 | echo changed-by-B >>different-renames/file
|
| 437 | git mv different-renames/file different-renames/theirs
|
| 438 | echo added-by-B >directory-old/added
|
| 439 | git add . && git commit -m "apply the other change in each matrix entry"
|
| 440 |
|
| 441 | )
|
| 442 |
|
| 443 | git init same-rename-with-content
|
| 444 | (cd same-rename-with-content
|
| 445 | # Both sides modify the same source and rename it to the same destination.
|
| 446 | # The two appends conflict, but the rename itself agrees. The result should therefore be
|
| 447 | # exactly one content merge at `target`, never a second merge of an already-merged blob.
|
| 448 | write_lines foxtrot foxtrot foxtrot foxtrot foxtrot >file
|
| 449 | git add file && git commit -m "base"
|
| 450 |
|
| 451 | git branch A
|
| 452 | git branch B
|
| 453 |
|
| 454 | git checkout A
|
| 455 | echo changed-by-A >>file
|
| 456 | git mv file target
|
| 457 | git commit -am "A renames and changes file"
|
| 458 |
|
| 459 | git checkout B
|
| 460 | echo changed-by-B >>file
|
| 461 | git mv file target
|
| 462 | git commit -am "B renames and changes file"
|
| 463 |
|
| 464 | # Both sides agree on the rename, so this is an ordinary content conflict using the
|
| 465 | # configured marker size. These branches provide the merged blob for gix's index shape.
|
| 466 | git checkout -b expected main
|
| 467 | git rm file
|
| 468 | write_lines \
|
| 469 | foxtrot foxtrot foxtrot foxtrot foxtrot \
|
| 470 | '<<<<<<< A' \
|
| 471 | changed-by-A \
|
| 472 | ======= \
|
| 473 | changed-by-B \
|
| 474 | '>>>>>>> B' >target
|
| 475 | git add target && git commit -m "single content merge at shared rename destination"
|
| 476 |
|
| 477 | git checkout -b expected-reversed main
|
| 478 | git rm file
|
| 479 | write_lines \
|
| 480 | foxtrot foxtrot foxtrot foxtrot foxtrot \
|
| 481 | '<<<<<<< B' \
|
| 482 | changed-by-B \
|
| 483 | ======= \
|
| 484 | changed-by-A \
|
| 485 | '>>>>>>> A' >target
|
| 486 | git add target && git commit -m "single reversed content merge at shared rename destination"
|
| 487 | )
|
| 488 |
|
| 489 | git init same-rename-and-file-to-directory
|
| 490 | (cd same-rename-and-file-to-directory
|
| 491 | # Both sides perform the same compound operation:
|
| 492 | #
|
| 493 | # * rename `source` to `moved`;
|
| 494 | # * replace the old `source` path with a directory;
|
| 495 | # * add different content at `source/child`.
|
| 496 | #
|
| 497 | # The identical rewrite must be applied only once. Applying it again after merging the
|
| 498 | # children would recursively remove `source` and silently discard both payloads.
|
| 499 | write_lines source source source source source >source
|
| 500 | git add source && git commit -m "base"
|
| 501 |
|
| 502 | git branch A
|
| 503 | git branch B
|
| 504 |
|
| 505 | git checkout A
|
| 506 | git mv source moved
|
| 507 | mkdir source
|
| 508 | echo changed-by-A >source/child
|
| 509 | git add . && git commit -m "A renames source and adds a child at its old path"
|
| 510 |
|
| 511 | git checkout B
|
| 512 | git mv source moved
|
| 513 | mkdir source
|
| 514 | echo changed-by-B >source/child
|
| 515 | git add . && git commit -m "B renames source and adds a child at its old path"
|
| 516 | )
|
| 517 |
|
| 518 | git init renames-to-same-destination
|
| 519 | (cd renames-to-same-destination
|
| 520 | # The sides rename different source files onto the same destination:
|
| 521 | #
|
| 522 | # * A: `one` -> `target`
|
| 523 | # * B: `two` -> `target`
|
| 524 | #
|
| 525 | # Neither rename should silently win. A normal merge removes both sources and records the
|
| 526 | # two destination contents as an add/add conflict. Forced ancestor resolution keeps `one`
|
| 527 | # and `two`; forced ours applies only the rename belonging to the selected first side.
|
| 528 | write_lines one one one one one >one
|
| 529 | write_lines two two two two two >two
|
| 530 | git add . && git commit -m "base"
|
| 531 |
|
| 532 | git branch A
|
| 533 | git branch B
|
| 534 |
|
| 535 | git checkout A
|
| 536 | git mv one target
|
| 537 | git commit -m "rename one to target"
|
| 538 |
|
| 539 | git checkout B
|
| 540 | git mv two target
|
| 541 | git commit -m "rename two to target"
|
| 542 | )
|
| 543 |
|
| 544 | git init identical-renames-to-same-destination
|
| 545 | (cd identical-renames-to-same-destination
|
| 546 | write_lines same >one
|
| 547 | cp one two
|
| 548 | git add .
|
| 549 | git commit -m "two identical files"
|
| 550 |
|
| 551 | git branch A
|
| 552 | git branch B
|
| 553 |
|
| 554 | # Both sides rename a different source to `target`, but the entries have the
|
| 555 | # same mode and object ID. There is nothing to content-merge and the two
|
| 556 | # operations collapse cleanly to the shared destination in either direction.
|
| 557 | git checkout A
|
| 558 | git mv one target
|
| 559 | git commit -m "rename one to target"
|
| 560 |
|
| 561 | git checkout B
|
| 562 | git mv two target
|
| 563 | git commit -m "rename two to target"
|
| 564 | )
|
| 565 |
|
| 566 | git init identical-renames-to-same-destination-with-mode-change
|
| 567 | (cd identical-renames-to-same-destination-with-mode-change
|
| 568 | write_lines same >one
|
| 569 | cp one two
|
| 570 | git add .
|
| 571 | git commit -m "two identical files"
|
| 572 |
|
| 573 | git branch A
|
| 574 | git branch B
|
| 575 |
|
| 576 | # The destinations have the same blob ID but differ in executable mode.
|
| 577 | # Content merging must see those original modes even though the final mode
|
| 578 | # has already been selected.
|
| 579 | git checkout A
|
| 580 | git mv one target
|
| 581 | chmod +x target
|
| 582 | # For this to work on windows, we need explicit executable bit handling.
|
| 583 | git update-index --chmod=+x target
|
| 584 | git commit -m "rename one to executable target"
|
| 585 |
|
| 586 | git checkout B
|
| 587 | git mv two target
|
| 588 | git commit -m "rename two to target"
|
| 589 |
|
| 590 | # gix treats the identical content as clean and carries the executable mode
|
| 591 | # selected from A to the shared destination in both merge directions.
|
| 592 | git checkout -b expected A
|
| 593 | git rm two
|
| 594 | git commit -m "expected gix merge"
|
| 595 | )
|
| 596 |
|
| 597 | git init deleted-file-added-dir-with-rename
|
| 598 | (cd deleted-file-added-dir-with-rename
|
| 599 | # Regression for a deletion that is processed but not applied:
|
| 600 | #
|
| 601 | # * A deletes the file `x`.
|
| 602 | # * B renames that file to `renamed`, then creates the directory entry `x/a`.
|
| 603 | #
|
| 604 | # With ancestor conflict resolution, A's deletion must not count as applied merely because
|
| 605 | # the rename/delete conflict was handled. The ancestor file `x` remains, so `x/a` cannot
|
| 606 | # turn it into a directory.
|
| 607 | echo base >x
|
| 608 | git add x
|
| 609 | git commit -m "add x"
|
| 610 |
|
| 611 | git branch A
|
| 612 | git branch B
|
| 613 |
|
| 614 | git checkout A
|
| 615 | git rm x
|
| 616 | git commit -m "delete x"
|
| 617 |
|
| 618 | git checkout B
|
| 619 | git mv x renamed
|
| 620 | mkdir x
|
| 621 | echo added >x/a
|
| 622 | git add x/a
|
| 623 | git commit -m "rename x and add x/a"
|
| 624 | )
|
| 625 |
|
| 626 | git init deleted-file-replaced-by-renamed-dir
|
| 627 | (cd deleted-file-replaced-by-renamed-dir
|
| 628 | # Regression for a file that one side replaces with a directory filled only by renames:
|
| 629 | #
|
| 630 | # * A deletes the file `a/b` and moves `d/g` and `d/h` into the new directory `a/b/`.
|
| 631 | # * B only edits the unrelated file `u`.
|
| 632 | #
|
| 633 | # Rename tracking reports A's renames before the unpaired deletion of `a/b`, so the deletion
|
| 634 | # reaches the tree editor after `a/b/` exists and must not remove that directory.
|
| 635 | mkdir a d
|
| 636 | echo original >a/b
|
| 637 | seq 1 10 >d/g
|
| 638 | seq 11 20 >d/h
|
| 639 | seq 21 30 >u
|
| 640 | git add . && git commit -m "init"
|
| 641 |
|
| 642 | git branch A
|
| 643 | git branch B
|
| 644 |
|
| 645 | git checkout A
|
| 646 | git rm a/b
|
| 647 | mkdir -p a/b
|
| 648 | git mv d/g a/b/g
|
| 649 | git mv d/h a/b/h
|
| 650 | git commit -m "replace the file a/b with the moved directory d"
|
| 651 |
|
| 652 | git checkout B
|
| 653 | seq 21 31 >u
|
| 654 | git commit -am "edit unrelated file"
|
| 655 | )
|
| 656 |
|
| 657 | git init renamed-file-replaced-by-renamed-dir
|
| 658 | (cd renamed-file-replaced-by-renamed-dir
|
| 659 | # Like `deleted-file-replaced-by-renamed-dir`, but A moves the file `a/b` to `c` instead of
|
| 660 | # deleting it, and B edits `a/b`. B's edit follows the rename to `c`, and removing the rename
|
| 661 | # source `a/b` must not remove the directory `a/b/` that A's other rename created.
|
| 662 | mkdir a d
|
| 663 | seq 1 10 >a/b
|
| 664 | seq 11 20 >d/g
|
| 665 | git add . && git commit -m "init"
|
| 666 |
|
| 667 | git branch A
|
| 668 | git branch B
|
| 669 |
|
| 670 | git checkout A
|
| 671 | git mv a/b c
|
| 672 | mkdir -p a/b
|
| 673 | git mv d/g a/b/g
|
| 674 | git commit -m "move the file a/b away and d/g into a/b/"
|
| 675 |
|
| 676 | git checkout B
|
| 677 | seq 1 11 >a/b
|
| 678 | git commit -am "edit a/b"
|
| 679 | )
|
| 680 |
|
| 681 | git init rename-add
|
| 682 | (cd rename-add
|
| 683 | write_lines original 1 2 3 4 5 >foo
|
| 684 | git add foo
|
| 685 | git commit -m "original"
|
| 686 |
|
| 687 | git branch A
|
| 688 | git branch B
|
| 689 |
|
| 690 | git checkout A
|
| 691 | write_lines 1 2 3 4 5 >foo
|
| 692 | echo "different file" >bar
|
| 693 | git add foo bar
|
| 694 | git commit -m "Modify foo, add bar"
|
| 695 |
|
| 696 | git checkout B
|
| 697 | write_lines original 1 2 3 4 5 6 >foo
|
| 698 | git add foo
|
| 699 | git mv foo bar
|
| 700 | git commit -m "rename foo to bar"
|
| 701 | )
|
| 702 |
|
| 703 | git init rename-add-exe-bit-conflict
|
| 704 | (cd rename-add-exe-bit-conflict
|
| 705 | touch a b
|
| 706 | chmod +x a
|
| 707 | git add --chmod=+x a
|
| 708 | git add b
|
| 709 | git commit -m "original"
|
| 710 |
|
| 711 | git branch A
|
| 712 | git branch B
|
| 713 |
|
| 714 | git checkout A
|
| 715 | chmod -x a
|
| 716 | git update-index --chmod=-x a
|
| 717 | git commit -m "-x a"
|
| 718 |
|
| 719 | git checkout B
|
| 720 | git mv --force b a
|
| 721 | chmod +x a
|
| 722 | git update-index --chmod=+x a
|
| 723 | git commit -m "mv b a; chmod +x a"
|
| 724 | )
|
| 725 |
|
| 726 | git init rename-add-symlink
|
| 727 | (cd rename-add-symlink
|
| 728 | write_lines original 1 2 3 4 5 >foo
|
| 729 | git add foo
|
| 730 | git commit -m "original"
|
| 731 |
|
| 732 | git branch A
|
| 733 | git branch B
|
| 734 |
|
| 735 | git checkout A
|
| 736 | write_lines 1 2 3 4 5 >foo
|
| 737 | ln -s foo bar
|
| 738 | git add foo bar
|
| 739 | git commit -m "Modify foo, add symlink bar"
|
| 740 |
|
| 741 | git checkout B
|
| 742 | write_lines original 1 2 3 4 5 6 >foo
|
| 743 | git add foo
|
| 744 | git mv foo bar
|
| 745 | git commit -m "rename foo to bar"
|
| 746 | )
|
| 747 |
|
| 748 | git init rename-add-same-symlink
|
| 749 | (cd rename-add-same-symlink
|
| 750 | touch target
|
| 751 | ln -s target link
|
| 752 | git add .
|
| 753 | git commit -m "original"
|
| 754 |
|
| 755 | git branch A
|
| 756 | git branch B
|
| 757 |
|
| 758 | git checkout A
|
| 759 | git mv link link-new
|
| 760 | git commit -m "rename link to link-new"
|
| 761 |
|
| 762 | git checkout B
|
| 763 | ln -s target link-new
|
| 764 | git add link-new
|
| 765 | git commit -m "create link-new"
|
| 766 | )
|
| 767 |
|
| 768 | git init rename-rename-plus-content
|
| 769 | (cd rename-rename-plus-content
|
| 770 | write_lines 1 2 3 4 5 >foo
|
| 771 | git add foo
|
| 772 | git commit -m "original"
|
| 773 |
|
| 774 | git branch A
|
| 775 | git branch B
|
| 776 |
|
| 777 | git checkout A
|
| 778 | write_lines 1 2 3 4 5 six >foo
|
| 779 | git add foo
|
| 780 | git mv foo bar
|
| 781 | git commit -m "Modify foo + rename to bar"
|
| 782 |
|
| 783 | git checkout B
|
| 784 | write_lines 1 2 3 4 5 6 >foo
|
| 785 | git add foo
|
| 786 | git mv foo baz
|
| 787 | git commit -m "Modify foo + rename to baz"
|
| 788 | )
|
| 789 |
|
| 790 | git init rename-add-delete
|
| 791 | (
|
| 792 | cd rename-add-delete
|
| 793 | echo "original file" >foo
|
| 794 | git add foo
|
| 795 | git commit -m "original"
|
| 796 |
|
| 797 | git branch A
|
| 798 | git branch B
|
| 799 |
|
| 800 | git checkout A
|
| 801 | git rm foo
|
| 802 | echo "different file" >bar
|
| 803 | git add bar
|
| 804 | git commit -m "Remove foo, add bar"
|
| 805 |
|
| 806 | git checkout B
|
| 807 | git mv foo bar
|
| 808 | git commit -m "rename foo to bar"
|
| 809 | )
|
| 810 |
|
| 811 | git init rename-rename-delete-delete
|
| 812 | (
|
| 813 | cd rename-rename-delete-delete
|
| 814 | echo foo >foo
|
| 815 | echo bar >bar
|
| 816 | git add foo bar
|
| 817 | git commit -m O
|
| 818 |
|
| 819 | git branch A
|
| 820 | git branch B
|
| 821 |
|
| 822 | git checkout A
|
| 823 | git mv foo baz
|
| 824 | git rm bar
|
| 825 | git commit -m "Rename foo, remove bar"
|
| 826 |
|
| 827 | git checkout B
|
| 828 | git mv bar baz
|
| 829 | git rm foo
|
| 830 | git commit -m "Rename bar, remove foo"
|
| 831 | )
|
| 832 |
|
| 833 | git init super-1
|
| 834 | (cd super-1
|
| 835 | seq 11 19 >one
|
| 836 | seq 31 39 >three
|
| 837 | seq 51 59 >five
|
| 838 | git add .
|
| 839 | tick
|
| 840 | git commit -m "O"
|
| 841 |
|
| 842 | git branch A
|
| 843 | git branch B
|
| 844 |
|
| 845 | git checkout A
|
| 846 | seq 10 19 >one
|
| 847 | echo 40 >>three
|
| 848 | git add one three
|
| 849 | git mv one two
|
| 850 | git mv three four
|
| 851 | git mv five six
|
| 852 | tick
|
| 853 | git commit -m "A"
|
| 854 |
|
| 855 | git checkout B
|
| 856 | echo 20 >>one
|
| 857 | echo forty >>three
|
| 858 | echo 60 >>five
|
| 859 | git add one three five
|
| 860 | git mv one six
|
| 861 | git mv three two
|
| 862 | git mv five four
|
| 863 | tick
|
| 864 | git commit -m "B"
|
| 865 | )
|
| 866 |
|
| 867 | git init super-2
|
| 868 | (cd super-2
|
| 869 | write_lines 1 2 3 4 5 >foo
|
| 870 | mkdir olddir
|
| 871 | for i in a b c; do echo $i >olddir/$i || exit 1; done
|
| 872 | git add foo olddir
|
| 873 | git commit -m "original"
|
| 874 |
|
| 875 | git branch A
|
| 876 | git branch B
|
| 877 |
|
| 878 | git checkout A
|
| 879 | git rm foo
|
| 880 | git mv olddir newdir
|
| 881 | mkdir newdir/bar
|
| 882 | >newdir/bar/file
|
| 883 | git add newdir/bar/file
|
| 884 | git commit -m "rm foo, olddir/ -> newdir/, + newdir/bar/file"
|
| 885 |
|
| 886 | git checkout B
|
| 887 | write_lines 1 2 3 4 5 6 >foo
|
| 888 | git add foo
|
| 889 | git mv foo olddir/bar
|
| 890 | git commit -m "Modify foo & rename foo -> olddir/bar"
|
| 891 |
|
| 892 | rm .git/index
|
| 893 | git update-index --index-info <<EOF
|
| 894 | 100644 $(oid 78981922613b2afb6025042ff6bd878ac1994e85) 0 newdir/a
|
| 895 | 100644 $(oid 61780798228d17af2d34fce4cfbdf35556832472) 0 newdir/b
|
| 896 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 newdir/bar/file
|
| 897 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 newdir/bar~B
|
| 898 | 100644 $(oid f2ad6c76f0115a6ba5b00456a849810e7ec0af20) 0 newdir/c
|
| 899 | EOF
|
| 900 | # Git also has
|
| 901 | # 100644 b414108e81e5091fe0974a1858b4d0d22b107f70 1 newdir/bar~B
|
| 902 | # which then looks like "deleted by us: newdir/bar-B`
|
| 903 | # Our index here doesn't manage to track the base across so many renames, but it ends up looking like
|
| 904 | # `added by them: newdir/bar~B` which to my mind is more helpful, in a situation where the index simply
|
| 905 | # cannot properly show what happened.
|
| 906 | make_conflict_index super-2-A-B
|
| 907 | make_conflict_index super-2-A-B-diff3
|
| 908 |
|
| 909 | rm .git/index
|
| 910 | git update-index --index-info <<EOF
|
| 911 | 100644 $(oid 78981922613b2afb6025042ff6bd878ac1994e85) 0 newdir/a
|
| 912 | 100644 $(oid 61780798228d17af2d34fce4cfbdf35556832472) 0 newdir/b
|
| 913 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 newdir/bar/file
|
| 914 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 newdir/bar~B
|
| 915 | 100644 $(oid f2ad6c76f0115a6ba5b00456a849810e7ec0af20) 0 newdir/c
|
| 916 | EOF
|
| 917 | make_conflict_index super-2-A-B-reversed
|
| 918 | make_conflict_index super-2-A-B-diff3-reversed
|
| 919 | )
|
| 920 |
|
| 921 | git init rename-within-rename
|
| 922 | (cd rename-within-rename
|
| 923 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 924 | mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f
|
| 925 | touch a/w a/sub/z
|
| 926 | git add . && git commit -m "original"
|
| 927 |
|
| 928 | git branch A
|
| 929 | git branch B
|
| 930 | git branch expected
|
| 931 |
|
| 932 | git checkout A
|
| 933 | write_lines 1 2 3 4 5 >a/x.f
|
| 934 | write_lines 1 2 3 4 5 >a/sub/y.f
|
| 935 | git mv a a-renamed
|
| 936 | git commit -am "changed all content, renamed a -> a-renamed"
|
| 937 |
|
| 938 | git checkout B
|
| 939 | write_lines original 1 2 3 4 5 6 >a/x.f
|
| 940 | write_lines original 1 2 3 4 5 6 >a/sub/y.f
|
| 941 | git mv a/sub a/sub-renamed
|
| 942 | git commit -am "changed all content, renamed a/sub -> a/sub-renamed"
|
| 943 |
|
| 944 | git checkout expected
|
| 945 | write_lines 1 2 3 4 5 6 >a/x.f
|
| 946 | write_lines 1 2 3 4 5 6 >a/sub/y.f
|
| 947 | cp -Rv a/sub a/sub-renamed
|
| 948 | git add .
|
| 949 | git mv a a-renamed
|
| 950 | git commit -am "we also have duplication just like Git, but we are consistent independently of the side, hence the expectation"
|
| 951 |
|
| 952 | # We have duplication just like Git, but our index is definitely more complex. This one seems more plausible.
|
| 953 | # The problem is that renames can't be indicated correctly in the index.
|
| 954 | rm .git/index
|
| 955 | git update-index --index-info <<EOF
|
| 956 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a-renamed/sub/y.f
|
| 957 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a-renamed/sub/z
|
| 958 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/sub-renamed/y.f
|
| 959 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/sub-renamed/z
|
| 960 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/w
|
| 961 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/x.f
|
| 962 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a/sub-renamed/y.f
|
| 963 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a/sub-renamed/z
|
| 964 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 965 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/sub/z
|
| 966 | EOF
|
| 967 | make_conflict_index rename-within-rename-A-B-deviates
|
| 968 | rm .git/index
|
| 969 | git update-index --index-info <<EOF
|
| 970 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a-renamed/sub/y.f
|
| 971 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a-renamed/sub/z
|
| 972 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/sub-renamed/y.f
|
| 973 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/sub-renamed/z
|
| 974 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/w
|
| 975 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/x.f
|
| 976 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a/sub-renamed/y.f
|
| 977 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a/sub-renamed/z
|
| 978 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 979 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/sub/z
|
| 980 | EOF
|
| 981 | make_conflict_index rename-within-rename-A-B-deviates-reversed
|
| 982 | )
|
| 983 |
|
| 984 | git init rename-within-rename-2
|
| 985 | (cd rename-within-rename-2
|
| 986 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 987 | mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f
|
| 988 | touch a/w a/sub/z
|
| 989 | git add . && git commit -m "original"
|
| 990 |
|
| 991 | git branch A
|
| 992 | git branch B
|
| 993 | git branch expected
|
| 994 |
|
| 995 | git checkout A
|
| 996 | write_lines 1 2 3 4 5 >a/x.f
|
| 997 | write_lines 1 2 3 4 5 >a/sub/y.f
|
| 998 | git mv a/sub a/sub-renamed
|
| 999 | git mv a a-renamed
|
| 1000 | git commit -am "changed all content, renamed a -> a-renamed, a/sub -> a/sub-renamed"
|
| 1001 |
|
| 1002 | git checkout B
|
| 1003 | write_lines original 1 2 3 4 5 6 >a/x.f
|
| 1004 | write_lines original 1 2 3 4 5 6 >a/sub/y.f
|
| 1005 | git mv a/sub a/sub-renamed
|
| 1006 | git commit -am "changed all content, renamed a/sub -> a/sub-renamed"
|
| 1007 |
|
| 1008 | git checkout expected
|
| 1009 | write_lines 1 2 3 4 5 6 >a/x.f
|
| 1010 | write_lines 1 2 3 4 5 6 >a/sub/y.f
|
| 1011 | git mv a/sub a/sub-renamed
|
| 1012 | git mv a a-renamed
|
| 1013 | git commit -am "tracked both renames, applied all modifications by merge"
|
| 1014 | # Both merge directions yield this tree, so `expected` serves the reversed case as well.
|
| 1015 |
|
| 1016 |
|
| 1017 | # Both directions produce the same cleanly merged state, and the index is the same as well.
|
| 1018 | rm .git/index
|
| 1019 | git update-index --index-info <<EOF
|
| 1020 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/sub-renamed/y.f
|
| 1021 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/sub-renamed/z
|
| 1022 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/w
|
| 1023 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/x.f
|
| 1024 | EOF
|
| 1025 | make_conflict_index rename-within-rename-2-A-B-deviates
|
| 1026 | make_conflict_index rename-within-rename-2-A-B-deviates-reversed
|
| 1027 | )
|
| 1028 |
|
| 1029 | git init conflicting-rename
|
| 1030 | (cd conflicting-rename
|
| 1031 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1032 | mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f
|
| 1033 | touch a/w a/sub/z
|
| 1034 | git add . && git commit -m "original"
|
| 1035 |
|
| 1036 | git branch A
|
| 1037 | git branch B
|
| 1038 |
|
| 1039 | git checkout A
|
| 1040 | write_lines 1 2 3 4 5 >a/x.f
|
| 1041 | write_lines 1 2 3 4 5 >a/sub/y.f
|
| 1042 | git mv a a-renamed
|
| 1043 | git commit -am "changed all content, renamed a -> a-renamed"
|
| 1044 |
|
| 1045 | git checkout B
|
| 1046 | write_lines original 1 2 3 4 5 6 >a/x.f
|
| 1047 | write_lines original 1 2 3 4 5 6 >a/sub/y.f
|
| 1048 | git mv a a-different
|
| 1049 | git commit -am "changed all content, renamed a -> a-different"
|
| 1050 |
|
| 1051 | # Git only sees the files with content changes as conflicting, and somehow misses to add the
|
| 1052 | # bases of the files without content changes. After all, these also have been renamed into
|
| 1053 | # different places which must be a conflict just as much.
|
| 1054 | rm .git/index
|
| 1055 | git update-index --index-info <<EOF
|
| 1056 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a-different/sub/y.f
|
| 1057 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a-different/sub/z
|
| 1058 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a-different/w
|
| 1059 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a-different/x.f
|
| 1060 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a-renamed/sub/y.f
|
| 1061 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a-renamed/sub/z
|
| 1062 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a-renamed/w
|
| 1063 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a-renamed/x.f
|
| 1064 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 1065 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/x.f
|
| 1066 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/sub/z
|
| 1067 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/w
|
| 1068 | EOF
|
| 1069 | make_conflict_index conflicting-rename-A-B
|
| 1070 |
|
| 1071 | rm .git/index
|
| 1072 | git update-index --index-info <<EOF
|
| 1073 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a-different/sub/y.f
|
| 1074 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a-different/sub/z
|
| 1075 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a-different/w
|
| 1076 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a-different/x.f
|
| 1077 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a-renamed/sub/y.f
|
| 1078 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a-renamed/sub/z
|
| 1079 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a-renamed/w
|
| 1080 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a-renamed/x.f
|
| 1081 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 1082 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/x.f
|
| 1083 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/sub/z
|
| 1084 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/w
|
| 1085 | EOF
|
| 1086 | make_conflict_index conflicting-rename-A-B-reversed
|
| 1087 | )
|
| 1088 |
|
| 1089 | git init conflicting-rename-2
|
| 1090 | (cd conflicting-rename-2
|
| 1091 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1092 | mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f
|
| 1093 | touch a/w a/sub/z
|
| 1094 | git add . && git commit -m "original"
|
| 1095 |
|
| 1096 | git branch A
|
| 1097 | git branch B
|
| 1098 |
|
| 1099 | git checkout A
|
| 1100 | write_lines 1 2 3 4 5 >a/x.f
|
| 1101 | write_lines 1 2 3 4 5 >a/sub/y.f
|
| 1102 | git mv a/sub a/sub-renamed
|
| 1103 | git commit -am "changed all content, renamed a/sub -> a/sub-renamed"
|
| 1104 |
|
| 1105 | git checkout B
|
| 1106 | write_lines original 1 2 3 4 5 6 >a/x.f
|
| 1107 | write_lines original 1 2 3 4 5 6 >a/sub/y.f
|
| 1108 | git mv a/sub a/sub-different
|
| 1109 | git commit -am "changed all content, renamed a/sub -> a/sub-different"
|
| 1110 |
|
| 1111 | # Here it's the same as above, i.e. Git doesn't list files as conflicting if
|
| 1112 | # they didn't change, even though they have a conflicting rename.
|
| 1113 | rm .git/index
|
| 1114 | git update-index --index-info <<EOF
|
| 1115 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a/sub-different/y.f
|
| 1116 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a/sub-different/z
|
| 1117 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a/sub-renamed/y.f
|
| 1118 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a/sub-renamed/z
|
| 1119 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 1120 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/sub/z
|
| 1121 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a/w
|
| 1122 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a/x.f
|
| 1123 | EOF
|
| 1124 | make_conflict_index conflicting-rename-2-A-B
|
| 1125 |
|
| 1126 | rm .git/index
|
| 1127 | git update-index --index-info <<EOF
|
| 1128 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a/sub-different/y.f
|
| 1129 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a/sub-different/z
|
| 1130 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a/sub-renamed/y.f
|
| 1131 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a/sub-renamed/z
|
| 1132 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 1133 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 1 a/sub/z
|
| 1134 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a/w
|
| 1135 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a/x.f
|
| 1136 | EOF
|
| 1137 | make_conflict_index conflicting-rename-2-A-B-reversed
|
| 1138 | )
|
| 1139 |
|
| 1140 | git init conflicting-rename-complex
|
| 1141 | (cd conflicting-rename-complex
|
| 1142 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1143 | mkdir a/sub && write_lines original 1 2 3 4 5 >a/sub/y.f
|
| 1144 | touch a/w a/sub/z
|
| 1145 | git add . && git commit -m "original"
|
| 1146 |
|
| 1147 | git branch A
|
| 1148 | git branch B
|
| 1149 | git branch expected
|
| 1150 |
|
| 1151 | git checkout A
|
| 1152 | write_lines 1 2 3 4 5 >a/x.f
|
| 1153 | write_lines 1 2 3 4 5 >a/sub/y.f
|
| 1154 | git mv a a-renamed
|
| 1155 | git commit -am "changed all content, renamed a -> a-renamed"
|
| 1156 |
|
| 1157 | git checkout B
|
| 1158 | write_lines original 1 2 3 4 5 6 >a/sub/y.f
|
| 1159 | git mv a/sub tmp
|
| 1160 | git rm -r a
|
| 1161 | git mv tmp a
|
| 1162 | git commit -am "change something in subdirectory, then overwrite directory with subdirectory"
|
| 1163 |
|
| 1164 | git checkout expected
|
| 1165 | rm .git/index
|
| 1166 | rm -Rf ./a
|
| 1167 | mkdir -p a-renamed/sub
|
| 1168 | write_lines 1 2 3 4 5 6 >a-renamed/sub/y.f
|
| 1169 | write_lines 1 2 3 4 5 >a-renamed/x.f
|
| 1170 | write_lines 1 2 3 4 5 6 >a-renamed/y.f
|
| 1171 | touch a-renamed/z a-renamed/w a-renamed/sub/z
|
| 1172 | git add .
|
| 1173 | git commit -m "Close to what Git has, but different due to rename tracking. Contents follow their true renames thanks to filename-aware matching, while Git also keeps rename/rename destinations that we compose."
|
| 1174 |
|
| 1175 |
|
| 1176 | # Since the whole state is very different, the expected index is as well, but at least it should make sense for what it is.
|
| 1177 | # Files pair up by matching filename like in Git, so `y.f` and `z` follow their true renames,
|
| 1178 | # while `a/x.f` and `a/w` which `B` deleted conflict with `A`'s directory rename and keep our side.
|
| 1179 | rm .git/index
|
| 1180 | git update-index --index-info <<EOF
|
| 1181 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a-renamed/sub/y.f
|
| 1182 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a-renamed/sub/z
|
| 1183 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/y.f
|
| 1184 | 100644 $(oid 8a1218a1024a212bb3db30becd860315f9f3ac52) 2 a-renamed/x.f
|
| 1185 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 2 a-renamed/w
|
| 1186 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/z
|
| 1187 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 1188 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a/y.f
|
| 1189 | EOF
|
| 1190 | make_conflict_index conflicting-rename-complex-A-B
|
| 1191 |
|
| 1192 | rm .git/index
|
| 1193 | git update-index --index-info <<EOF
|
| 1194 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 3 a-renamed/sub/y.f
|
| 1195 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a-renamed/sub/z
|
| 1196 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/y.f
|
| 1197 | 100644 $(oid 8a1218a1024a212bb3db30becd860315f9f3ac52) 3 a-renamed/x.f
|
| 1198 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 3 a-renamed/w
|
| 1199 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/z
|
| 1200 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 1 a/sub/y.f
|
| 1201 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 2 a/y.f
|
| 1202 | EOF
|
| 1203 | make_conflict_index conflicting-rename-complex-A-B-reversed
|
| 1204 | )
|
| 1205 |
|
| 1206 | git init same-rename-different-mode
|
| 1207 | (cd same-rename-different-mode
|
| 1208 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1209 | touch a/w
|
| 1210 | git add . && git commit -m "original"
|
| 1211 |
|
| 1212 | git branch A
|
| 1213 | git branch B
|
| 1214 | git branch expected
|
| 1215 |
|
| 1216 | git checkout A
|
| 1217 | write_lines 1 2 3 4 5 >a/x.f
|
| 1218 | chmod +x a/x.f a/w
|
| 1219 | git update-index --chmod=+x a/x.f a/w
|
| 1220 | git mv a a-renamed
|
| 1221 | git commit -am "changed a/xf, add +x everywhere, renamed a -> a-renamed"
|
| 1222 |
|
| 1223 | git checkout B
|
| 1224 | write_lines original 1 2 3 4 5 6 >a/x.f
|
| 1225 | git mv a a-renamed
|
| 1226 | git commit -am "changed all content, renamed a -> a-renamed"
|
| 1227 |
|
| 1228 | git checkout expected
|
| 1229 | chmod +x a/x.f a/w
|
| 1230 | git update-index --chmod=+x a/x.f a/w
|
| 1231 | write_lines 1 2 3 4 5 6 >a/x.f
|
| 1232 | git mv a a-renamed
|
| 1233 | git commit -am "Git, when branches are reversed, doesn't keep the +x flag on a/w so we specify our own expectation"
|
| 1234 | # Git sets +x and adds it as conflict, even though the merge is perfect, i.e. one side adds +x on top, perfectly additive.
|
| 1235 | make_conflict_index same-rename-different-mode-A-B
|
| 1236 | make_conflict_index same-rename-different-mode-A-B-reversed
|
| 1237 | )
|
| 1238 |
|
| 1239 | git init remove-executable-mode
|
| 1240 | (cd remove-executable-mode
|
| 1241 | touch w
|
| 1242 | chmod +x w
|
| 1243 | git add --chmod=+x w
|
| 1244 | git add . && git commit -m "original"
|
| 1245 |
|
| 1246 | git branch A
|
| 1247 | git branch B
|
| 1248 |
|
| 1249 | git checkout A
|
| 1250 | chmod -x w
|
| 1251 | git update-index --chmod=-x w
|
| 1252 | git commit -am "remove executable bit from w"
|
| 1253 |
|
| 1254 | git checkout B
|
| 1255 | write_lines 1 2 3 4 5 >w
|
| 1256 | git commit -am "unrelated change to w"
|
| 1257 | )
|
| 1258 |
|
| 1259 | git init renamed-symlink-with-conflict
|
| 1260 | (cd renamed-symlink-with-conflict
|
| 1261 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1262 | ln -s a/x.f link
|
| 1263 | git add . && git commit -m "original"
|
| 1264 |
|
| 1265 | git branch A
|
| 1266 | git branch B
|
| 1267 |
|
| 1268 | git checkout A
|
| 1269 | write_lines 1 2 3 4 5 >a/x.f
|
| 1270 | git mv link link-renamed
|
| 1271 | git commit -am "changed a/x.f, renamed link -> link-renamed"
|
| 1272 |
|
| 1273 | git checkout B
|
| 1274 | write_lines original 1 2 3 4 5 6 >a/x.f
|
| 1275 | git mv link link-different
|
| 1276 | git commit -am "change content, renamed link -> link-different"
|
| 1277 | )
|
| 1278 |
|
| 1279 | git init added-file-changed-content-and-mode
|
| 1280 | (cd added-file-changed-content-and-mode
|
| 1281 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1282 | git add . && git commit -m "original"
|
| 1283 |
|
| 1284 | git branch A
|
| 1285 | git branch B
|
| 1286 | git branch expected
|
| 1287 |
|
| 1288 | git checkout A
|
| 1289 | write_lines 1 2 3 4 5 >new
|
| 1290 | git add .
|
| 1291 | git commit -m "add 'new' with content A"
|
| 1292 |
|
| 1293 | git checkout B
|
| 1294 | write_lines original 1 2 3 4 5 6 >new
|
| 1295 | chmod +x new
|
| 1296 | git add --chmod=+x new
|
| 1297 | git commit -m "add new with content B and +x"
|
| 1298 |
|
| 1299 | git checkout expected
|
| 1300 | echo -n $'<<<<<<< A\n1\n2\n3\n4\n5\n=======\noriginal\n1\n2\n3\n4\n5\n6\n>>>>>>> B\n' >new
|
| 1301 | chmod +x new
|
| 1302 | git add --chmod=+x new
|
| 1303 | git commit -m "Git has a better merge here, but that's due to better hunk handling/hunk splitting. We, however, consistently use +x"
|
| 1304 | )
|
| 1305 |
|
| 1306 | git init type-change-and-renamed
|
| 1307 | (cd type-change-and-renamed
|
| 1308 | mkdir a && >a/x.f
|
| 1309 | ln -s a/x.f link
|
| 1310 | git add . && git commit -m "original"
|
| 1311 |
|
| 1312 | git branch A
|
| 1313 | git branch B
|
| 1314 |
|
| 1315 | git checkout A
|
| 1316 | rm link && echo not-link > link
|
| 1317 | git commit -am "link type-changed, file changed"
|
| 1318 |
|
| 1319 | git checkout B
|
| 1320 | git mv link link-renamed
|
| 1321 | git commit -am "just renamed the link"
|
| 1322 | )
|
| 1323 |
|
| 1324 | git init change-and-delete
|
| 1325 | (cd change-and-delete
|
| 1326 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1327 | ln -s a/x.f link
|
| 1328 | git add . && git commit -m "original"
|
| 1329 |
|
| 1330 | git branch A
|
| 1331 | git branch B
|
| 1332 |
|
| 1333 | git checkout A
|
| 1334 | write_lines 1 2 3 4 5 6 >a/x.f
|
| 1335 | rm link && echo not-link > link
|
| 1336 | git commit -am "link type-changed, file changed"
|
| 1337 |
|
| 1338 | git checkout B
|
| 1339 | git rm link a/x.f
|
| 1340 | git commit -am "delete everything"
|
| 1341 | )
|
| 1342 |
|
| 1343 | git init submodule-both-modify
|
| 1344 | (cd submodule-both-modify
|
| 1345 | mkdir sub
|
| 1346 | (cd sub
|
| 1347 | git init
|
| 1348 | echo original > file
|
| 1349 | git add file
|
| 1350 | tick
|
| 1351 | git commit -m sub-root
|
| 1352 | )
|
| 1353 | git add sub
|
| 1354 | tick
|
| 1355 | git commit -m root
|
| 1356 |
|
| 1357 | git branch expected
|
| 1358 |
|
| 1359 | git checkout -b A main
|
| 1360 | (cd sub
|
| 1361 | echo A > file
|
| 1362 | git add file
|
| 1363 | tick
|
| 1364 | git commit -m sub-a
|
| 1365 | )
|
| 1366 | git add sub
|
| 1367 | tick
|
| 1368 | git commit -m a
|
| 1369 | git branch -f expected
|
| 1370 |
|
| 1371 | git checkout -b B main
|
| 1372 | (cd sub
|
| 1373 | echo B > file
|
| 1374 | git add file
|
| 1375 | tick
|
| 1376 | git commit -m sub-b
|
| 1377 | )
|
| 1378 | git add sub
|
| 1379 | tick
|
| 1380 | git commit -m b
|
| 1381 | git branch expected-reversed
|
| 1382 |
|
| 1383 | # The tree merger retains Git's conflict stages and provisional ours entry without inspecting submodule history.
|
| 1384 | rm .git/index
|
| 1385 | git update-index --index-info <<EOF
|
| 1386 | 160000 $(oid e835c0c403c8e494c0ca98f3d25d0b8464c18d38) 1 sub
|
| 1387 | 160000 $(oid 64466ebdff775ad618d9cc993cf52840e0af528c) 2 sub
|
| 1388 | 160000 $(oid ea6eb701e03c2497915c25a851f3da8f8e362ca0) 3 sub
|
| 1389 | EOF
|
| 1390 | make_conflict_index submodule-both-modify-A-B
|
| 1391 |
|
| 1392 | rm .git/index
|
| 1393 | git update-index --index-info <<EOF
|
| 1394 | 160000 $(oid e835c0c403c8e494c0ca98f3d25d0b8464c18d38) 1 sub
|
| 1395 | 160000 $(oid ea6eb701e03c2497915c25a851f3da8f8e362ca0) 2 sub
|
| 1396 | 160000 $(oid 64466ebdff775ad618d9cc993cf52840e0af528c) 3 sub
|
| 1397 | EOF
|
| 1398 | make_conflict_index submodule-both-modify-A-B-reversed
|
| 1399 | )
|
| 1400 |
|
| 1401 | git init gitlink-replaced-by-files
|
| 1402 | (cd gitlink-replaced-by-files
|
| 1403 | git commit --allow-empty -m "seed commit"
|
| 1404 | seed=$(git rev-parse HEAD)
|
| 1405 | git update-index --add --cacheinfo 160000,$seed,item
|
| 1406 | git commit -m "gitlink base"
|
| 1407 |
|
| 1408 | git branch A
|
| 1409 | git branch B
|
| 1410 |
|
| 1411 | # Both sides replace the gitlink with regular files. Their contents must be
|
| 1412 | # merged as an add/add pair with an empty blob ancestor; the commit named by
|
| 1413 | # the base entry is not a valid blob-merge resource.
|
| 1414 | git checkout A
|
| 1415 | git rm item
|
| 1416 | write_lines changed-by-A >item
|
| 1417 | git add item
|
| 1418 | git commit -m "replace gitlink with A's file"
|
| 1419 |
|
| 1420 | git checkout B
|
| 1421 | git rm item
|
| 1422 | write_lines changed-by-B >item
|
| 1423 | git add item
|
| 1424 | git commit -m "replace gitlink with B's file"
|
| 1425 | )
|
| 1426 |
|
| 1427 | git init both-modify-union-attr
|
| 1428 | (cd both-modify-union-attr
|
| 1429 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1430 | echo "a/* merge=union" >.gitattributes
|
| 1431 | git add . && git commit -m "original"
|
| 1432 |
|
| 1433 | git branch A
|
| 1434 | git branch B
|
| 1435 |
|
| 1436 | git checkout A
|
| 1437 | write_lines A 1 2 3 4 5 6 >a/x.f
|
| 1438 | git commit -am "change file"
|
| 1439 |
|
| 1440 | git checkout B
|
| 1441 | write_lines B 1 2 3 4 5 7 >a/x.f
|
| 1442 | git commit -am "change file differently"
|
| 1443 | )
|
| 1444 |
|
| 1445 | git init both-modify-binary
|
| 1446 | (cd both-modify-binary
|
| 1447 | mkdir a && printf '\x00 binary' >a/x.f
|
| 1448 | git add . && git commit -m "original"
|
| 1449 |
|
| 1450 | git branch A
|
| 1451 | git branch B
|
| 1452 |
|
| 1453 | git checkout A
|
| 1454 | printf '\x00 A' >a/x.f
|
| 1455 | git commit -am "change binary file"
|
| 1456 |
|
| 1457 | git checkout B
|
| 1458 | printf '\x00 B' >a/x.f
|
| 1459 | git commit -am "change binary file differently"
|
| 1460 | )
|
| 1461 |
|
| 1462 | git init both-modify-file-with-binary-attr
|
| 1463 | (cd both-modify-file-with-binary-attr
|
| 1464 | mkdir a && echo 'not binary' >a/x.f
|
| 1465 | git add . && git commit -m "original"
|
| 1466 |
|
| 1467 | git branch A
|
| 1468 | git branch B
|
| 1469 |
|
| 1470 | git checkout A
|
| 1471 | echo 'A binary' >a/x.f
|
| 1472 | git commit -am "change pseudo-binary file"
|
| 1473 |
|
| 1474 | git checkout B
|
| 1475 | echo 'B binary' >a/x.f
|
| 1476 | git commit -am "change pseudo-binary file differently"
|
| 1477 | )
|
| 1478 |
|
| 1479 | git init big-file-merge
|
| 1480 | (cd big-file-merge
|
| 1481 | git config --local core.bigFileThreshold 100
|
| 1482 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1483 | git add . && git commit -m "original"
|
| 1484 |
|
| 1485 | git branch A
|
| 1486 | git branch B
|
| 1487 |
|
| 1488 | git checkout A
|
| 1489 | seq 37 >a/x.f
|
| 1490 | git commit -am "turn normal file into big one (102 bytes)"
|
| 1491 | git branch expected
|
| 1492 |
|
| 1493 | git checkout B
|
| 1494 | write_lines 1 2 3 4 5 6 >a/x.f
|
| 1495 | git commit -am "a normal but conflicting file change"
|
| 1496 | )
|
| 1497 |
|
| 1498 | git init no-merge-base
|
| 1499 | (cd no-merge-base
|
| 1500 | git checkout -b A
|
| 1501 | echo "A" >content && git add . && git commit -m "content A"
|
| 1502 |
|
| 1503 | git checkout --orphan B
|
| 1504 | echo "B" >content && git add . && git commit -m "content B"
|
| 1505 |
|
| 1506 | git checkout -b expectation
|
| 1507 | )
|
| 1508 |
|
| 1509 | git init multiple-merge-bases
|
| 1510 | (cd multiple-merge-bases
|
| 1511 | write_lines 1 2 3 4 5 >content
|
| 1512 | git add . && git commit -m "initial"
|
| 1513 |
|
| 1514 | git branch A
|
| 1515 | git branch B
|
| 1516 |
|
| 1517 | git checkout A
|
| 1518 | write_lines 0 1 2 3 4 5 >content
|
| 1519 | git commit -am "change in A" && git tag A1
|
| 1520 |
|
| 1521 | git checkout B
|
| 1522 | write_lines 1 2 3 4 5 6 >content
|
| 1523 | git commit -am "change in B" && git tag B1
|
| 1524 |
|
| 1525 | git checkout A
|
| 1526 | git merge B1
|
| 1527 |
|
| 1528 | git checkout B
|
| 1529 | git merge A1
|
| 1530 |
|
| 1531 | git checkout A
|
| 1532 | write_lines 0 1 2 3 4 5 A >content
|
| 1533 | git commit -am "conflicting in A"
|
| 1534 |
|
| 1535 | git checkout B
|
| 1536 | git rm content
|
| 1537 | write_lines 0 2 3 4 5 six >renamed
|
| 1538 | git commit -m "rename in B"
|
| 1539 | )
|
| 1540 |
|
| 1541 | git init multiple-merge-bases-with-renamed-dir
|
| 1542 | (cd multiple-merge-bases-with-renamed-dir
|
| 1543 | # `deleted-file-replaced-by-renamed-dir` with two merge bases: building the virtual merge base
|
| 1544 | # replays that shape, and only if it keeps `a/b/` do A's and B's edits inside it merge cleanly.
|
| 1545 | mkdir a d
|
| 1546 | echo original >a/b
|
| 1547 | seq 1 10 >d/g
|
| 1548 | seq 11 20 >d/h
|
| 1549 | seq 21 30 >u
|
| 1550 | git add . && git commit -m "initial"
|
| 1551 |
|
| 1552 | git branch A
|
| 1553 | git branch B
|
| 1554 |
|
| 1555 | git checkout A
|
| 1556 | git rm a/b
|
| 1557 | mkdir -p a/b
|
| 1558 | git mv d/g a/b/g
|
| 1559 | git mv d/h a/b/h
|
| 1560 | git commit -m "replace the file a/b with the moved directory d" && git tag A1
|
| 1561 |
|
| 1562 | git checkout B
|
| 1563 | seq 21 31 >u
|
| 1564 | git commit -am "edit unrelated file" && git tag B1
|
| 1565 |
|
| 1566 | git checkout A
|
| 1567 | git merge B1
|
| 1568 |
|
| 1569 | git checkout B
|
| 1570 | git merge A1
|
| 1571 |
|
| 1572 | git checkout A
|
| 1573 | seq 1 11 >a/b/g
|
| 1574 | git commit -am "edit a/b/g in A"
|
| 1575 |
|
| 1576 | git checkout B
|
| 1577 | seq 11 21 >a/b/h
|
| 1578 | git commit -am "edit a/b/h in B"
|
| 1579 | )
|
| 1580 |
|
| 1581 | git init rename-and-modification
|
| 1582 | (cd rename-and-modification
|
| 1583 | mkdir a && write_lines original 1 2 3 4 5 >a/x.f
|
| 1584 | git add . && git commit -m "original"
|
| 1585 |
|
| 1586 | git branch A
|
| 1587 | git branch B
|
| 1588 |
|
| 1589 | git checkout A
|
| 1590 | git mv a/x.f x.f
|
| 1591 | git commit -am "move a/x.f to the top-level"
|
| 1592 |
|
| 1593 | git checkout B
|
| 1594 | write_lines 1 2 3 4 5 6 >a/x.f
|
| 1595 | git commit -am "changed a/x.f"
|
| 1596 | )
|
| 1597 |
|
| 1598 | git init symlink-modification
|
| 1599 | (cd symlink-modification
|
| 1600 | touch a b o
|
| 1601 | ln -s o link
|
| 1602 | git add . && git commit -m "original"
|
| 1603 |
|
| 1604 | git branch A
|
| 1605 | git branch B
|
| 1606 |
|
| 1607 | git checkout A
|
| 1608 | rm link && ln -s a link
|
| 1609 | git commit -am "set link to point to 'a'"
|
| 1610 |
|
| 1611 | git checkout B
|
| 1612 | rm link && ln -s b link
|
| 1613 | git commit -am "set link to point to 'b'"
|
| 1614 | )
|
| 1615 |
|
| 1616 | git init symlink-addition
|
| 1617 | (cd symlink-addition
|
| 1618 | touch a b
|
| 1619 | git add . && git commit -m "original without symlink"
|
| 1620 |
|
| 1621 | git branch A
|
| 1622 | git branch B
|
| 1623 |
|
| 1624 | git checkout A
|
| 1625 | ln -s a link && git add .
|
| 1626 | git commit -m "new link to point to 'a'"
|
| 1627 |
|
| 1628 | git checkout B
|
| 1629 | ln -s b link && git add .
|
| 1630 | git commit -m "new link to point to 'b'"
|
| 1631 | )
|
| 1632 |
|
| 1633 | git init added-file-vs-added-directory
|
| 1634 | (cd added-file-vs-added-directory
|
| 1635 | git commit --allow-empty -m "empty base"
|
| 1636 |
|
| 1637 | git branch A
|
| 1638 | git branch B
|
| 1639 |
|
| 1640 | # A adds a file at `e`, while B adds a file below the directory `e`. Resolving
|
| 1641 | # this tree/non-tree pair removes B's `e/e` path-tree leaf; its now-empty `e`
|
| 1642 | # parent must not remain visible as a change during the inverse scheduling pass.
|
| 1643 | git checkout A
|
| 1644 | write_lines file >e
|
| 1645 | git add e
|
| 1646 | git commit -m "add file e"
|
| 1647 |
|
| 1648 | git checkout B
|
| 1649 | mkdir e
|
| 1650 | write_lines nested >e/e
|
| 1651 | git add e/e
|
| 1652 | git commit -m "add directory e"
|
| 1653 | )
|
| 1654 |
|
| 1655 | git init added-symlink-blocks-gitlink-directory
|
| 1656 | (cd added-symlink-blocks-gitlink-directory
|
| 1657 | git commit --allow-empty -m "empty base"
|
| 1658 | base="$(git rev-parse HEAD)"
|
| 1659 |
|
| 1660 | git branch A
|
| 1661 | git branch B
|
| 1662 |
|
| 1663 | # A adds a non-tree at `d`, while B adds a directory at the same path. The nested
|
| 1664 | # gitlink is deliberate: tree/non-tree handling must not accidentally route this
|
| 1665 | # structural conflict through the blob or submodule merge cases.
|
| 1666 | git checkout A
|
| 1667 | ln -s target d
|
| 1668 | git add d
|
| 1669 | git commit -m "add symlink d"
|
| 1670 |
|
| 1671 | git checkout B
|
| 1672 | git update-index --index-info <<EOF
|
| 1673 | 160000 commit $base d/a/d
|
| 1674 | EOF
|
| 1675 | git commit -m "add nested gitlink below d"
|
| 1676 | )
|
| 1677 |
|
| 1678 | git init gitlink-vs-renamed-symlink-directory-with-siblings
|
| 1679 | (cd gitlink-vs-renamed-symlink-directory-with-siblings
|
| 1680 | git commit --allow-empty -m "gitlink target"
|
| 1681 | root="$(git rev-parse HEAD)"
|
| 1682 | mkdir -p a/a
|
| 1683 | ln -s target a/a/a
|
| 1684 | git add a/a/a
|
| 1685 | git update-index --add --cacheinfo 160000,$root,h
|
| 1686 | git commit -m "symlink and gitlink base"
|
| 1687 |
|
| 1688 | git branch A
|
| 1689 | git branch B
|
| 1690 |
|
| 1691 | # A replaces the symlink-containing directory with a regular child and keeps
|
| 1692 | # the gitlink at `h`. B instead removes that gitlink, moves the symlink below
|
| 1693 | # a new `h` directory, and adds a sibling below it. Resolving the resulting
|
| 1694 | # type mismatch may consume the sibling's structural path before cleanup.
|
| 1695 | git checkout A
|
| 1696 | git rm a/a/a
|
| 1697 | mkdir a
|
| 1698 | write_lines changed >a/b
|
| 1699 | git add a/b
|
| 1700 | git commit -m "replace the symlink directory"
|
| 1701 |
|
| 1702 | git checkout B
|
| 1703 | git mv a/a/a moved-link
|
| 1704 | git update-index --force-remove h
|
| 1705 | mkdir -p h/b
|
| 1706 | git mv moved-link h/a
|
| 1707 | write_lines sibling >h/b/a
|
| 1708 | git add .
|
| 1709 | git commit -m "replace the gitlink with a renamed symlink and sibling"
|
| 1710 |
|
| 1711 | # gix follows the detected `a` -> `h` directory rename and relocates A's
|
| 1712 | # added `a/b` to `h/b~A`. Git leaves the addition at `a/b`; this fixture
|
| 1713 | # records the existing semantic difference while guarding the path cleanup.
|
| 1714 | git checkout -b expected B
|
| 1715 | git update-index --add --cacheinfo "100644,$(git rev-parse A:a/b),h/b~A"
|
| 1716 | git commit -m "expected gix merge"
|
| 1717 |
|
| 1718 | # FIXME: merge symmetry: only when B is ours, gix also preserves A's blocking
|
| 1719 | # gitlink at its unique path.
|
| 1720 | git checkout -b expected-reversed
|
| 1721 | git update-index --add --cacheinfo "160000,$root,h~B"
|
| 1722 | git commit -m "expected reversed gix merge"
|
| 1723 | )
|
| 1724 |
|
| 1725 | git init same-source-rewrites-after-consumed-path
|
| 1726 | (cd same-source-rewrites-after-consumed-path
|
| 1727 | mkdir -p a/a
|
| 1728 | printf payload >a/a/a
|
| 1729 | printf payload >b
|
| 1730 | git add .
|
| 1731 | git commit -m "identical files at nested and root paths"
|
| 1732 |
|
| 1733 | git branch A
|
| 1734 | git branch B
|
| 1735 |
|
| 1736 | # Every non-directory entry deliberately has the same object ID. This gives
|
| 1737 | # rewrite detection several equally valid source/destination pairings. A
|
| 1738 | # removes `a/a/a` and reuses its payload at unrelated paths.
|
| 1739 | git checkout A
|
| 1740 | git rm a/a/a
|
| 1741 | mkdir -p e/a g/e
|
| 1742 | ln -s payload e/a/g
|
| 1743 | printf payload >g/e/a
|
| 1744 | git add .
|
| 1745 | git commit -m "remove the nested source and add identical entries"
|
| 1746 |
|
| 1747 | # B retains `a/a/a`, adds an executable sibling, replaces `b` with a nested
|
| 1748 | # copy, and adds another copy. Resolving one ambiguous rewrite can consume
|
| 1749 | # the shared source before a later same-source rewrite cleans it up.
|
| 1750 | git checkout B
|
| 1751 | mkdir -p a/e h/e
|
| 1752 | printf payload >a/e/a
|
| 1753 | chmod +x a/e/a
|
| 1754 | git rm b
|
| 1755 | mkdir -p b/b
|
| 1756 | printf payload >b/b/f
|
| 1757 | printf payload >h/e/a
|
| 1758 | git add .
|
| 1759 | git update-index --chmod=+x a/e/a
|
| 1760 | git commit -m "retain and multiply the identical payload"
|
| 1761 |
|
| 1762 | # gix pairs both sides with the same ambiguous base source and carries B's
|
| 1763 | # executable mode to A's destination. Git leaves both additions in place.
|
| 1764 | git checkout -b expected B
|
| 1765 | git update-index --force-remove a/a/a
|
| 1766 | git update-index --force-remove a/e/a
|
| 1767 | git update-index --add --cacheinfo "120000,$(git rev-parse A:e/a/g),e/a/g"
|
| 1768 | git update-index --add --cacheinfo "100755,$(git rev-parse B:a/e/a),g/e/a"
|
| 1769 | git commit -m "expected gix merge"
|
| 1770 | )
|
| 1771 |
|
| 1772 | git init rename-delete-after-consumed-path
|
| 1773 | (cd rename-delete-after-consumed-path
|
| 1774 | mkdir -p a h/d f e/f
|
| 1775 | write_lines shared >a/a
|
| 1776 | chmod +x a/a
|
| 1777 | write_lines four >b
|
| 1778 | write_lines seven >e/f/a
|
| 1779 | chmod +x e/f/a
|
| 1780 | write_lines shared >f/a
|
| 1781 | write_lines shared >h/d/a
|
| 1782 | git add .
|
| 1783 | git update-index --chmod=+x a/a e/f/a
|
| 1784 | git commit -m "base with repeated rename candidates"
|
| 1785 |
|
| 1786 | git branch A
|
| 1787 | git branch B
|
| 1788 |
|
| 1789 | # A moves `h/d/a` below `a`, turns `f/a` into `f`, and replaces `e/`.
|
| 1790 | # The repeated `shared` payload deliberately gives rename detection several
|
| 1791 | # possible sources, matching the scheduling ambiguity found by the fuzzer.
|
| 1792 | git checkout A
|
| 1793 | git rm -r a e
|
| 1794 | mkdir -p a/a a/d
|
| 1795 | write_lines four >a/a/a
|
| 1796 | git mv h/d/a a/d/a
|
| 1797 | mv f/a moved
|
| 1798 | rmdir f
|
| 1799 | mv moved f
|
| 1800 | write_lines five >d
|
| 1801 | write_lines shared >e
|
| 1802 | git add -A
|
| 1803 | git commit -m "rename repeated payloads and replace directories"
|
| 1804 |
|
| 1805 | # B deletes A's rename source and replaces `b`, `e`, and `f` with opposite
|
| 1806 | # file/directory shapes. Resolving another rename/delete pair can consume the
|
| 1807 | # path node for `h/d/a` before that pending deletion follows a directory rename.
|
| 1808 | git checkout B
|
| 1809 | git rm -r a b e f h
|
| 1810 | mkdir -p b/a
|
| 1811 | write_lines shared >b/a/a
|
| 1812 | write_lines four >e
|
| 1813 | write_lines four >f
|
| 1814 | git add .
|
| 1815 | git commit -m "delete rename sources and replace directories"
|
| 1816 |
|
| 1817 | # Ambiguous identity-only rename pairing makes gix keep a smaller tree than
|
| 1818 | # Git and merge the repeated payloads at the surviving paths.
|
| 1819 | shared_four=$(
|
| 1820 | printf '%s\n' \
|
| 1821 | '<<<<<<< A' \
|
| 1822 | shared \
|
| 1823 | ======= \
|
| 1824 | four \
|
| 1825 | '>>>>>>> B' |
|
| 1826 | git hash-object -w --stdin
|
| 1827 | )
|
| 1828 | four_shared=$(
|
| 1829 | printf '%s\n' \
|
| 1830 | '<<<<<<< A' \
|
| 1831 | four \
|
| 1832 | ======= \
|
| 1833 | shared \
|
| 1834 | '>>>>>>> B' |
|
| 1835 | git hash-object -w --stdin
|
| 1836 | )
|
| 1837 | git checkout -b expected B
|
| 1838 | git read-tree --empty
|
| 1839 | git update-index --add --cacheinfo "100644,$four_shared,b/a/a"
|
| 1840 | git update-index --add --cacheinfo "100644,$(git rev-parse A:a/d/a),b/d/a"
|
| 1841 | git update-index --add --cacheinfo "100644,$(git rev-parse A:d),d"
|
| 1842 | git update-index --add --cacheinfo "100644,$shared_four,e"
|
| 1843 | git update-index --add --cacheinfo "100644,$shared_four,f"
|
| 1844 | git commit -m "expected gix merge"
|
| 1845 |
|
| 1846 | reversed_four_shared=$(
|
| 1847 | printf '%s\n' \
|
| 1848 | '<<<<<<< B' \
|
| 1849 | four \
|
| 1850 | ======= \
|
| 1851 | shared \
|
| 1852 | '>>>>>>> A' |
|
| 1853 | git hash-object -w --stdin
|
| 1854 | )
|
| 1855 | reversed_shared_four=$(
|
| 1856 | printf '%s\n' \
|
| 1857 | '<<<<<<< B' \
|
| 1858 | shared \
|
| 1859 | ======= \
|
| 1860 | four \
|
| 1861 | '>>>>>>> A' |
|
| 1862 | git hash-object -w --stdin
|
| 1863 | )
|
| 1864 | # Reversing the merge keeps the same paths and pairings, with directional
|
| 1865 | # conflict-marker labels.
|
| 1866 | git checkout -f -b expected-reversed B
|
| 1867 | git read-tree --empty
|
| 1868 | git update-index --add --cacheinfo "100644,$reversed_shared_four,b/a/a"
|
| 1869 | git update-index --add --cacheinfo "100644,$(git rev-parse A:a/d/a),b/d/a"
|
| 1870 | git update-index --add --cacheinfo "100644,$(git rev-parse A:d),d"
|
| 1871 | git update-index --add --cacheinfo "100644,$reversed_four_shared,e"
|
| 1872 | git update-index --add --cacheinfo "100644,$reversed_four_shared,f"
|
| 1873 | git commit -m "expected reversed gix merge"
|
| 1874 | )
|
| 1875 |
|
| 1876 | git init modified-file-vs-gitlink-directory
|
| 1877 | (cd modified-file-vs-gitlink-directory
|
| 1878 | ln -s target a
|
| 1879 | git add a
|
| 1880 | git commit -m "symlink base"
|
| 1881 | base="$(git rev-parse HEAD)"
|
| 1882 |
|
| 1883 | git branch A
|
| 1884 | git branch B
|
| 1885 |
|
| 1886 | # A replaces the symlink with an executable file while B replaces it with a
|
| 1887 | # directory. The nested gitlink makes its addition sort before the base-file
|
| 1888 | # deletion, exercising merge scheduling independently of diff order.
|
| 1889 | git checkout A
|
| 1890 | rm a
|
| 1891 | write_lines modified >a
|
| 1892 | chmod +x a
|
| 1893 | git add --chmod=+x a
|
| 1894 | git commit -m "replace a with an executable"
|
| 1895 |
|
| 1896 | git checkout B
|
| 1897 | git rm a
|
| 1898 | git update-index --index-info <<EOF
|
| 1899 | 160000 commit $base a/h
|
| 1900 | EOF
|
| 1901 | git commit -m "replace a with a gitlink directory"
|
| 1902 | )
|
| 1903 |
|
| 1904 | git init relocated-addition-blocked-by-rename
|
| 1905 | (cd relocated-addition-blocked-by-rename
|
| 1906 | mkdir -p c
|
| 1907 | write_lines base >c/c
|
| 1908 | git add .
|
| 1909 | git commit -m "file in c"
|
| 1910 |
|
| 1911 | git branch A
|
| 1912 | git branch B
|
| 1913 |
|
| 1914 | # A's exact file rename also implies the directory rename `c` -> `a`. B adds
|
| 1915 | # `c/a/c`, so directory-rename handling relocates it to `a/a/c`, where A's
|
| 1916 | # renamed file at `a/a` blocks the required directory.
|
| 1917 | git checkout A
|
| 1918 | mkdir -p a
|
| 1919 | git mv c/c a/a
|
| 1920 | rmdir c
|
| 1921 | git commit -m "rename c/c to a/a"
|
| 1922 |
|
| 1923 | git checkout B
|
| 1924 | mkdir -p c/a
|
| 1925 | write_lines added >c/a/c
|
| 1926 | git add .
|
| 1927 | git commit -m "add below renamed directory"
|
| 1928 | )
|
| 1929 |
|
| 1930 | git init nested-rename-blocks-relocated-addition
|
| 1931 | (cd nested-rename-blocks-relocated-addition
|
| 1932 | mkdir a
|
| 1933 | write_lines base >a/a
|
| 1934 | git add .
|
| 1935 | git commit -m "file in a"
|
| 1936 |
|
| 1937 | git branch A
|
| 1938 | git branch B
|
| 1939 |
|
| 1940 | # Both sides rename the same file. A puts it where its containing directory
|
| 1941 | # used to be, while B nests it another level below that directory.
|
| 1942 | git checkout A
|
| 1943 | git mv a/a moved
|
| 1944 | rmdir a
|
| 1945 | git mv moved a
|
| 1946 | git commit -m "move a/a to a"
|
| 1947 |
|
| 1948 | git checkout B
|
| 1949 | git mv a/a moved
|
| 1950 | mkdir -p a/a
|
| 1951 | git mv moved a/a/a
|
| 1952 | git commit -m "move a/a to a/a/a"
|
| 1953 | )
|
| 1954 |
|
| 1955 | git init directory-rename-vs-directory-to-file
|
| 1956 | (cd directory-rename-vs-directory-to-file
|
| 1957 | mkdir a
|
| 1958 | write_lines same >a/a
|
| 1959 | git add .
|
| 1960 | git commit -m "file in a"
|
| 1961 |
|
| 1962 | git branch A
|
| 1963 | git branch B
|
| 1964 |
|
| 1965 | # A renames the containing directory. B moves its only file to the directory's
|
| 1966 | # former path, replacing the directory with that file. This is a different-renames
|
| 1967 | # conflict whose tree/non-tree handling must update the rename side's path tree.
|
| 1968 | git checkout A
|
| 1969 | git mv a e
|
| 1970 | git commit -m "rename a to e"
|
| 1971 |
|
| 1972 | git checkout B
|
| 1973 | git mv a/a moved
|
| 1974 | rmdir a
|
| 1975 | git mv moved a
|
| 1976 | git commit -m "replace a directory with its file"
|
| 1977 | )
|
| 1978 |
|
| 1979 | git init directory-rename-vs-renamed-file-replacement
|
| 1980 | (cd directory-rename-vs-renamed-file-replacement
|
| 1981 | mkdir -p h/h
|
| 1982 | write_lines nested >h/h/a
|
| 1983 | write_lines outside >a
|
| 1984 | git add .
|
| 1985 | git commit -m "directory and outside file"
|
| 1986 |
|
| 1987 | git branch A
|
| 1988 | git branch B
|
| 1989 |
|
| 1990 | # A moves the directory away. B deletes its contents and moves an unrelated
|
| 1991 | # file onto the vacated directory path. Unlike the contained-file variant
|
| 1992 | # above, the replacement rename has a distinct source, so it can meet the
|
| 1993 | # structural directory rewrite before the nested rename/delete pair does.
|
| 1994 | git checkout A
|
| 1995 | git mv h/h f
|
| 1996 | rmdir h
|
| 1997 | git commit -m "rename the directory"
|
| 1998 |
|
| 1999 | git checkout B
|
| 2000 | git rm h/h/a
|
| 2001 | mkdir -p h
|
| 2002 | git mv a h/h
|
| 2003 | git commit -m "replace the directory with a renamed file"
|
| 2004 | )
|
| 2005 |
|
| 2006 | git init unrelated-renames-overlapping-destinations
|
| 2007 | (cd unrelated-renames-overlapping-destinations
|
| 2008 | mkdir -p a/a h/b
|
| 2009 | write_lines first >a/a/a
|
| 2010 | write_lines second >h/b/a
|
| 2011 | git add .
|
| 2012 | git commit -m "two files in separate directories"
|
| 2013 |
|
| 2014 | git branch A
|
| 2015 | git branch B
|
| 2016 |
|
| 2017 | # A's directory rename places `h/b/a` below `c`. B independently renames
|
| 2018 | # `a/a/a` to the non-tree `c` and renames `h/b/a` elsewhere. The two rename
|
| 2019 | # destinations therefore overlap even though their source files are unrelated.
|
| 2020 | git checkout A
|
| 2021 | git mv h c
|
| 2022 | git commit -m "rename h to c"
|
| 2023 |
|
| 2024 | git checkout B
|
| 2025 | git mv h/b/a moved-h
|
| 2026 | git mv a/a/a moved-a
|
| 2027 | rmdir a/a
|
| 2028 | mkdir -p a
|
| 2029 | git mv moved-h a/a
|
| 2030 | git mv moved-a c
|
| 2031 | git commit -m "rename both files to crossing destinations"
|
| 2032 | )
|
| 2033 |
|
| 2034 | git init renamed-file-inside-renamed-directory
|
| 2035 | (cd renamed-file-inside-renamed-directory
|
| 2036 | mkdir -p a/a h/b
|
| 2037 | write_lines first >a/a/a
|
| 2038 | write_lines second >h/b/a
|
| 2039 | git add .
|
| 2040 | git commit -m "two files in separate directories"
|
| 2041 |
|
| 2042 | git branch A
|
| 2043 | git branch B
|
| 2044 |
|
| 2045 | # A renames `h` to `c`. B replaces the contents of `h` with a file renamed
|
| 2046 | # from elsewhere while moving the original `h/b/a` to `a/a`. Directory-rename
|
| 2047 | # handling must therefore defer and relocate a rewrite, not just an addition.
|
| 2048 | git checkout A
|
| 2049 | git mv h c
|
| 2050 | git commit -m "rename h to c"
|
| 2051 |
|
| 2052 | git checkout B
|
| 2053 | git mv h/b/a moved-h
|
| 2054 | git mv a/a/a moved-a
|
| 2055 | rmdir a/a h/b h
|
| 2056 | mkdir -p a h
|
| 2057 | git mv moved-h a/a
|
| 2058 | git mv moved-a h/h
|
| 2059 | git commit -m "replace a renamed directory with an outside file"
|
| 2060 | )
|
| 2061 |
|
| 2062 | git init unrelated-renames-to-same-path-with-type-mismatch
|
| 2063 | (cd unrelated-renames-to-same-path-with-type-mismatch
|
| 2064 | write_lines payload >file-source
|
| 2065 | ln -s payload link-source
|
| 2066 | git add .
|
| 2067 | git commit -m "regular file and symlink"
|
| 2068 |
|
| 2069 | git branch A
|
| 2070 | git branch B
|
| 2071 |
|
| 2072 | # Both sides rename a different base entry to `target`. A's entry is a
|
| 2073 | # symlink while B's is a regular file, so their destination cannot be
|
| 2074 | # content-merged. Git keeps the symlink at `target` and relocates the regular
|
| 2075 | # file to the side-qualified `target~B`, independently of merge direction.
|
| 2076 | git checkout A
|
| 2077 | git mv link-source target
|
| 2078 | git commit -m "rename the symlink to target"
|
| 2079 |
|
| 2080 | git checkout B
|
| 2081 | git mv file-source target
|
| 2082 | git commit -m "rename the regular file to target"
|
| 2083 | )
|
| 2084 |
|
| 2085 | git init renamed-file-vs-file-to-directory-with-siblings
|
| 2086 | (cd renamed-file-vs-file-to-directory-with-siblings
|
| 2087 | write_lines base >a
|
| 2088 | git add a
|
| 2089 | git commit -m "base file"
|
| 2090 |
|
| 2091 | git branch A
|
| 2092 | git branch B
|
| 2093 |
|
| 2094 | # A renames the base file away while B replaces its old path with a directory
|
| 2095 | # containing two children. Both children encounter the same rename/delete
|
| 2096 | # conflict; handling the first must not make the second try to remove an
|
| 2097 | # already-pruned rename-destination node.
|
| 2098 | git checkout A
|
| 2099 | git mv a h
|
| 2100 | git commit -m "rename the file"
|
| 2101 |
|
| 2102 | git checkout B
|
| 2103 | git rm a
|
| 2104 | mkdir a
|
| 2105 | write_lines first >a/a
|
| 2106 | write_lines second >a/c
|
| 2107 | git add .
|
| 2108 | git commit -m "replace the file with two children"
|
| 2109 | )
|
| 2110 |
|
| 2111 | git init identical-additions-with-different-relations
|
| 2112 | (cd identical-additions-with-different-relations
|
| 2113 | # A's earlier directory deletion shifts the relation ID assigned to the shared
|
| 2114 | # addition. The relation is diff-local, so both additions still have one effect.
|
| 2115 | mkdir -p a-shift
|
| 2116 | echo shift >a-shift/file
|
| 2117 | git add . && git commit -m "base"
|
| 2118 |
|
| 2119 | git branch A
|
| 2120 | git branch B
|
| 2121 |
|
| 2122 | git checkout A
|
| 2123 | git rm -r a-shift
|
| 2124 | mkdir -p b-target
|
| 2125 | echo shared-addition >b-target/file
|
| 2126 | git add . && git commit -m "delete a directory and add the shared tree"
|
| 2127 |
|
| 2128 | git checkout B
|
| 2129 | mkdir -p b-target
|
| 2130 | echo shared-addition >b-target/file
|
| 2131 | git add . && git commit -m "add the shared tree"
|
| 2132 | )
|
| 2133 |
|
| 2134 | git init identical-deletions-with-different-relations
|
| 2135 | (cd identical-deletions-with-different-relations
|
| 2136 | # A deletes an earlier directory as well, so the shared deletion receives a
|
| 2137 | # different relation ID on each side despite removing the same tree.
|
| 2138 | mkdir -p a-shift b-target
|
| 2139 | echo shift >a-shift/file
|
| 2140 | echo shared-deletion >b-target/file
|
| 2141 | git add . && git commit -m "base"
|
| 2142 |
|
| 2143 | git branch A
|
| 2144 | git branch B
|
| 2145 |
|
| 2146 | git checkout A
|
| 2147 | git rm -r a-shift b-target
|
| 2148 | git commit -m "delete the earlier and shared trees"
|
| 2149 |
|
| 2150 | git checkout B
|
| 2151 | git rm -r b-target
|
| 2152 | git commit -m "delete the shared tree"
|
| 2153 | )
|
| 2154 |
|
| 2155 | git init identical-rewrites-with-different-relations
|
| 2156 | (cd identical-rewrites-with-different-relations
|
| 2157 | # Moving the same file into a new directory gives each rewrite a destination
|
| 2158 | # relation. A's earlier deletion shifts that ID without changing the rename.
|
| 2159 | mkdir -p a-shift
|
| 2160 | echo shift >a-shift/file
|
| 2161 | echo shared-rewrite >b-source
|
| 2162 | git add . && git commit -m "base"
|
| 2163 |
|
| 2164 | git branch A
|
| 2165 | git branch B
|
| 2166 |
|
| 2167 | git checkout A
|
| 2168 | git rm -r a-shift
|
| 2169 | mkdir c-target
|
| 2170 | git mv b-source c-target/file
|
| 2171 | mkdir b-source
|
| 2172 | echo from-A >b-source/A-only
|
| 2173 | git add . && git commit -m "delete an earlier tree and rename the shared file"
|
| 2174 |
|
| 2175 | git checkout B
|
| 2176 | mkdir c-target
|
| 2177 | git mv b-source c-target/file
|
| 2178 | mkdir b-source
|
| 2179 | echo from-B >b-source/B-only
|
| 2180 | git add . && git commit -m "rename the shared file"
|
| 2181 | )
|
| 2182 |
|
| 2183 | git init type-change-to-symlink
|
| 2184 | (cd type-change-to-symlink
|
| 2185 | touch a b link
|
| 2186 | git add . && git commit -m "original without symlink"
|
| 2187 |
|
| 2188 | git branch A
|
| 2189 | git branch B
|
| 2190 |
|
| 2191 | git checkout A
|
| 2192 | git rm link
|
| 2193 | ln -s a link && git add .
|
| 2194 | git commit -m "new link to point to 'a'"
|
| 2195 |
|
| 2196 | git checkout B
|
| 2197 | git rm link
|
| 2198 | ln -s b link && git add .
|
| 2199 | git commit -m "new link to point to 'b'"
|
| 2200 | )
|
| 2201 |
|
| 2202 |
|
| 2203 |
|
| 2204 | baseline non-tree-to-tree A-B A B
|
| 2205 | baseline deleted-file-added-dir A-B A B
|
| 2206 | baseline deleted-file-added-gitlink-directory A-B A B
|
| 2207 | baseline tree-to-non-tree A-B A B
|
| 2208 | baseline tree-to-non-tree-with-rename A-B A B
|
| 2209 | baseline non-tree-to-tree-with-rename A-B A B
|
| 2210 | baseline rename-add-same-symlink A-B A B
|
| 2211 | baseline rename-add-exe-bit-conflict A-B A B
|
| 2212 | baseline remove-executable-mode A-B A B
|
| 2213 | baseline simple side-1-3-without-conflict side1 side3
|
| 2214 | baseline simple fast-forward side1 main
|
| 2215 | baseline simple no-change main main
|
| 2216 | baseline simple side-1-3-without-conflict-diff3 side1 side3
|
| 2217 | baseline simple side-1-2-various-conflicts side1 side2
|
| 2218 | baseline simple side-1-2-various-conflicts-diff3 side1 side2
|
| 2219 | baseline simple single-content-conflict side1 side4
|
| 2220 | baseline simple single-content-conflict-diff3 side1 side4
|
| 2221 | baseline simple tweak1-side2 tweak1 side2
|
| 2222 | baseline simple tweak1-side2-diff3 tweak1 side2
|
| 2223 | baseline simple side-1-unrelated side1 unrelated
|
| 2224 | baseline simple side-1-unrelated-diff3 side1 unrelated
|
| 2225 | baseline rename-delete A-B A B
|
| 2226 | baseline rename-delete A-similar A A
|
| 2227 | baseline rename-delete B-similar B B
|
| 2228 | baseline rename-change-matrix A-B A B
|
| 2229 | baseline same-rename-with-content A-B A B
|
| 2230 | baseline same-rename-and-file-to-directory A-B A B
|
| 2231 | baseline renames-to-same-destination A-B A B
|
| 2232 | baseline identical-renames-to-same-destination A-B A B
|
| 2233 | baseline identical-renames-to-same-destination-with-mode-change A-B A B "gix resolves the identical content and mode change cleanly, while Git leaves an add/add mode conflict"
|
| 2234 | baseline deleted-file-added-dir-with-rename A-B A B
|
| 2235 | baseline deleted-file-replaced-by-renamed-dir A-B A B
|
| 2236 | baseline renamed-file-replaced-by-renamed-dir A-B A B
|
| 2237 | baseline rename-add A-B A B
|
| 2238 | baseline rename-add A-B-diff3 A B
|
| 2239 | baseline rename-add-symlink A-B A B
|
| 2240 | baseline rename-add-symlink A-B-diff3 A B
|
| 2241 | baseline rename-rename-plus-content A-B A B
|
| 2242 | baseline rename-rename-plus-content A-B-diff3 A B
|
| 2243 | baseline rename-add-delete A-B A B
|
| 2244 | baseline rename-rename-delete-delete A-B A B
|
| 2245 | baseline super-1 A-B A B
|
| 2246 | baseline super-1 A-B-diff3 A B
|
| 2247 | baseline super-2 A-B A B
|
| 2248 | baseline super-2 A-B-diff3 A B
|
| 2249 |
|
| 2250 | baseline rename-within-rename A-B-deviates A B "Git doesn't detect the rename-nesting, we do neither"
|
| 2251 | baseline rename-within-rename-2 A-B-deviates A B "Git keeps the doubly-renamed file in both rename destinations as it doesn't compose nested directory renames - we do, and merge contents cleanly in one place, in both merge directions"
|
| 2252 | baseline conflicting-rename A-B A B
|
| 2253 | baseline conflicting-rename-2 A-B A B
|
| 2254 | baseline conflicting-rename-complex A-B A B "Git has different rename tracking - overall result it's still close enough"
|
| 2255 |
|
| 2256 | baseline same-rename-different-mode A-B A B "Git works for the A/B case, but for B/A it forgets to set the executable bit"
|
| 2257 | baseline renamed-symlink-with-conflict A-B A B
|
| 2258 | baseline added-file-changed-content-and-mode A-B A B "We improve on executable bit handling, but loose on diff quality as we are definitely missing some tweaks"
|
| 2259 |
|
| 2260 | baseline type-change-and-renamed A-B A B
|
| 2261 | baseline change-and-delete A-B A B
|
| 2262 | baseline submodule-both-modify A-B A B "The tree-only merge cannot inspect submodule reachability, so it keeps ours as the provisional entry and reports SubmoduleMerge."
|
| 2263 | baseline gitlink-replaced-by-files A-B A B
|
| 2264 | baseline both-modify-union-attr A-B A B
|
| 2265 | baseline both-modify-union-attr A-B-diff3 A B
|
| 2266 | baseline both-modify-binary A-B A B
|
| 2267 | baseline both-modify-binary A-B A B
|
| 2268 | baseline both-modify-file-with-binary-attr A-B A B
|
| 2269 | baseline big-file-merge A-B A B "Git actually ignores core.bigFileThreshold during merging and tries a normal merge (or binary one) anyway. We don't ignore it and treat big files like binary files" \
|
| 2270 | no-reverse
|
| 2271 | baseline no-merge-base A-B A B
|
| 2272 | baseline no-merge-base A-B-diff3 A B
|
| 2273 |
|
| 2274 | baseline multiple-merge-bases A-B A B
|
| 2275 | baseline multiple-merge-bases A-B-diff3 A B
|
| 2276 | baseline multiple-merge-bases-with-renamed-dir A-B A B
|
| 2277 |
|
| 2278 | baseline rename-and-modification A-B A B
|
| 2279 | baseline symlink-modification A-B A B
|
| 2280 | baseline symlink-addition A-B A B
|
| 2281 | baseline added-file-vs-added-directory A-B A B
|
| 2282 | baseline added-symlink-blocks-gitlink-directory A-B A B
|
| 2283 | baseline gitlink-vs-renamed-symlink-directory-with-siblings A-B A B "gix relocates A's addition through the detected directory rename, while Git keeps it at its original path; FIXME: merge symmetry: reversing gix also preserves A's blocking gitlink"
|
| 2284 | baseline same-source-rewrites-after-consumed-path A-B A B "ambiguous identical blobs make gix pair both sides with one base source, while Git retains both additions"
|
| 2285 | baseline rename-delete-after-consumed-path A-B A B "ambiguous identical blobs make gix pair rename sources differently than Git"
|
| 2286 | baseline modified-file-vs-gitlink-directory A-B A B
|
| 2287 | baseline relocated-addition-blocked-by-rename A-B A B
|
| 2288 | baseline nested-rename-blocks-relocated-addition A-B A B
|
| 2289 | baseline directory-rename-vs-directory-to-file A-B A B
|
| 2290 | baseline directory-rename-vs-renamed-file-replacement A-B A B
|
| 2291 | baseline unrelated-renames-overlapping-destinations A-B A B
|
| 2292 | baseline renamed-file-inside-renamed-directory A-B A B
|
| 2293 | baseline unrelated-renames-to-same-path-with-type-mismatch A-B A B
|
| 2294 | baseline renamed-file-vs-file-to-directory-with-siblings A-B A B
|
| 2295 | baseline identical-additions-with-different-relations A-B A B
|
| 2296 | baseline identical-deletions-with-different-relations A-B A B
|
| 2297 | baseline identical-rewrites-with-different-relations A-B A B
|
| 2298 | baseline type-change-to-symlink A-B A B
|
| 2299 |
|
| 2300 | ##
|
| 2301 | ## Only once the tree-merges were performed can we refer to their objects
|
| 2302 | ## when making tree-conflict resolution expectations. It's important
|
| 2303 | ## to get these right.
|
| 2304 | ##
|
| 2305 | (cd added-file-vs-added-directory
|
| 2306 | # The ancestor is empty, so choosing it keeps neither addition.
|
| 2307 | git read-tree main
|
| 2308 | make_resolve_tree ancestor A B
|
| 2309 | make_resolve_tree ancestor B A
|
| 2310 |
|
| 2311 | # Choosing ours keeps precisely the side selected by the merge direction.
|
| 2312 | git read-tree A
|
| 2313 | make_resolve_tree ours A B
|
| 2314 | git read-tree B
|
| 2315 | make_resolve_tree ours B A
|
| 2316 | )
|
| 2317 |
|
| 2318 | (cd deleted-file-added-gitlink-directory
|
| 2319 | # Both operations are compatible, so forced conflict resolution changes nothing:
|
| 2320 | # the shared deletion applies and B's directory remains in both directions.
|
| 2321 | git read-tree B
|
| 2322 | make_resolve_tree ancestor A B
|
| 2323 | make_resolve_tree ancestor B A
|
| 2324 | make_resolve_tree ours A B
|
| 2325 | make_resolve_tree ours B A
|
| 2326 | )
|
| 2327 |
|
| 2328 | (cd added-symlink-blocks-gitlink-directory
|
| 2329 | # The ancestor is empty, so choosing it keeps neither addition in either direction.
|
| 2330 | git read-tree main
|
| 2331 | make_resolve_tree ancestor A B
|
| 2332 | make_resolve_tree ancestor B A
|
| 2333 |
|
| 2334 | # Choosing ours keeps precisely the side named first: either A's symlink or B's
|
| 2335 | # directory containing the nested gitlink.
|
| 2336 | git read-tree A
|
| 2337 | make_resolve_tree ours A B
|
| 2338 | git read-tree B
|
| 2339 | make_resolve_tree ours B A
|
| 2340 | )
|
| 2341 |
|
| 2342 | (cd modified-file-vs-gitlink-directory
|
| 2343 | # Ancestor resolution restores the original symlink in both directions.
|
| 2344 | git read-tree main
|
| 2345 | make_resolve_tree ancestor A B
|
| 2346 | make_resolve_tree ancestor B A
|
| 2347 |
|
| 2348 | # Choosing ours keeps precisely the selected replacement.
|
| 2349 | git read-tree A
|
| 2350 | make_resolve_tree ours A B
|
| 2351 | git read-tree B
|
| 2352 | make_resolve_tree ours B A
|
| 2353 | )
|
| 2354 |
|
| 2355 | (cd relocated-addition-blocked-by-rename
|
| 2356 | # The explicit file rename prevents the inferred directory rename from relocating
|
| 2357 | # B's addition through a non-tree. The changes are therefore compatible, and forced
|
| 2358 | # conflict resolution has nothing to discard in either direction.
|
| 2359 | IFS= read -r -d '' merged_tree_id <A-B.merge-info
|
| 2360 | git read-tree "$merged_tree_id"
|
| 2361 | make_resolve_tree ancestor A B
|
| 2362 | make_resolve_tree ours A B
|
| 2363 |
|
| 2364 | IFS= read -r -d '' merged_reversed_tree_id <A-B-reversed.merge-info
|
| 2365 | git read-tree "$merged_reversed_tree_id"
|
| 2366 | make_resolve_tree ancestor B A
|
| 2367 | make_resolve_tree ours B A
|
| 2368 | )
|
| 2369 |
|
| 2370 | (cd nested-rename-blocks-relocated-addition
|
| 2371 | # gix keeps the rename/rename stages in addition to the file/directory stages
|
| 2372 | # that Git reports. The resulting tree and retained side content are identical.
|
| 2373 | blob=$(git rev-parse main:a/a)
|
| 2374 | rm .git/index
|
| 2375 | git update-index --index-info <<EOF
|
| 2376 | 100644 blob $blob 2 a
|
| 2377 | 100644 blob $blob 1 a/a
|
| 2378 | 100644 blob $blob 3 a/a/a
|
| 2379 | 100644 blob $blob 2 a~A
|
| 2380 | EOF
|
| 2381 | make_conflict_index nested-rename-blocks-relocated-addition-A-B
|
| 2382 |
|
| 2383 | rm .git/index
|
| 2384 | git update-index --index-info <<EOF
|
| 2385 | 100644 blob $blob 3 a
|
| 2386 | 100644 blob $blob 1 a/a
|
| 2387 | 100644 blob $blob 2 a/a/a
|
| 2388 | 100644 blob $blob 3 a~A
|
| 2389 | EOF
|
| 2390 | make_conflict_index nested-rename-blocks-relocated-addition-A-B-reversed
|
| 2391 | )
|
| 2392 |
|
| 2393 | (cd directory-rename-vs-directory-to-file
|
| 2394 | # Ancestor resolution applies neither rename and restores `a/a`.
|
| 2395 | git read-tree main
|
| 2396 | make_resolve_tree ancestor A B
|
| 2397 | make_resolve_tree ancestor B A
|
| 2398 |
|
| 2399 | # Choosing ours keeps precisely the directory rename or directory-to-file
|
| 2400 | # replacement selected by the merge direction.
|
| 2401 | git read-tree A
|
| 2402 | make_resolve_tree ours A B
|
| 2403 | git read-tree B
|
| 2404 | make_resolve_tree ours B A
|
| 2405 | )
|
| 2406 |
|
| 2407 | (cd directory-rename-vs-renamed-file-replacement
|
| 2408 | # Git retains the original file as stage 1 at its rename destination. Like the
|
| 2409 | # other rename/delete cases, gix records only the side that kept the file.
|
| 2410 | IFS= read -r -d '' merged_tree_id <A-B.merge-info
|
| 2411 | rm .git/index
|
| 2412 | git read-tree "$merged_tree_id"
|
| 2413 | git update-index --force-remove f/a
|
| 2414 | git update-index --index-info <<EOF
|
| 2415 | 100644 blob $(git rev-parse A:f/a) 2 f/a
|
| 2416 | EOF
|
| 2417 | make_conflict_index directory-rename-vs-renamed-file-replacement-A-B
|
| 2418 |
|
| 2419 | rm .git/index
|
| 2420 | git read-tree "$merged_tree_id"
|
| 2421 | git update-index --force-remove f/a
|
| 2422 | git update-index --index-info <<EOF
|
| 2423 | 100644 blob $(git rev-parse A:f/a) 3 f/a
|
| 2424 | EOF
|
| 2425 | make_conflict_index directory-rename-vs-renamed-file-replacement-A-B-reversed
|
| 2426 |
|
| 2427 | # Ancestor resolution rejects both conflicting renames and restores the original
|
| 2428 | # directory and outside file.
|
| 2429 | git read-tree main
|
| 2430 | make_resolve_tree ancestor A B
|
| 2431 | make_resolve_tree ancestor B A
|
| 2432 |
|
| 2433 | # Choosing ours keeps precisely the directory rename or file replacement selected
|
| 2434 | # by the merge direction.
|
| 2435 | git read-tree A
|
| 2436 | make_resolve_tree ours A B
|
| 2437 | git read-tree B
|
| 2438 | make_resolve_tree ours B A
|
| 2439 | )
|
| 2440 |
|
| 2441 | (cd unrelated-renames-overlapping-destinations
|
| 2442 | # Ancestor rejects the conflicting rename destinations and keeps both base files.
|
| 2443 | git read-tree main
|
| 2444 | make_resolve_tree ancestor A B
|
| 2445 | make_resolve_tree ancestor B A
|
| 2446 |
|
| 2447 | # Choosing ours keeps the complete side selected by the merge direction.
|
| 2448 | git read-tree A
|
| 2449 | make_resolve_tree ours A B
|
| 2450 | git read-tree B
|
| 2451 | make_resolve_tree ours B A
|
| 2452 | )
|
| 2453 |
|
| 2454 | (cd renamed-file-inside-renamed-directory
|
| 2455 | # Git puts the relocated `c/h` into stages 1, 2, and 3 even though all three
|
| 2456 | # entries are identical. gix records the successful directory relocation as
|
| 2457 | # stage 0 and reserves conflict stages for the genuinely divergent rename.
|
| 2458 | rm .git/index
|
| 2459 | git update-index --index-info <<EOF
|
| 2460 | 100644 blob $(git rev-parse main:h/b/a) 3 a/a
|
| 2461 | 100644 blob $(git rev-parse main:h/b/a) 2 c/b/a
|
| 2462 | 100644 blob $(git rev-parse main:a/a/a) c/h
|
| 2463 | 100644 blob $(git rev-parse main:h/b/a) 1 h/b/a
|
| 2464 | EOF
|
| 2465 | make_conflict_index renamed-file-inside-renamed-directory-A-B
|
| 2466 |
|
| 2467 | rm .git/index
|
| 2468 | git update-index --index-info <<EOF
|
| 2469 | 100644 blob $(git rev-parse main:h/b/a) 2 a/a
|
| 2470 | 100644 blob $(git rev-parse main:h/b/a) 3 c/b/a
|
| 2471 | 100644 blob $(git rev-parse main:a/a/a) c/h
|
| 2472 | 100644 blob $(git rev-parse main:h/b/a) 1 h/b/a
|
| 2473 | EOF
|
| 2474 | make_conflict_index renamed-file-inside-renamed-directory-A-B-reversed
|
| 2475 |
|
| 2476 | # Ancestor rejects the divergent rename of `h/b/a`, but the separate file
|
| 2477 | # rename is cleanly relocated through A's directory rename to `c/h`.
|
| 2478 | git read-tree main
|
| 2479 | git update-index --force-remove a/a/a
|
| 2480 | git update-index --add --cacheinfo "100644,$(git rev-parse main:a/a/a),c/h"
|
| 2481 | make_resolve_tree ancestor A B
|
| 2482 | make_resolve_tree ancestor B A
|
| 2483 |
|
| 2484 | # Choosing A still retains the independently relocated file from B.
|
| 2485 | git read-tree A
|
| 2486 | git update-index --force-remove a/a/a
|
| 2487 | git update-index --add --cacheinfo "100644,$(git rev-parse main:a/a/a),c/h"
|
| 2488 | make_resolve_tree ours A B
|
| 2489 |
|
| 2490 | # Choosing B keeps B's divergent rename, while the other file still follows
|
| 2491 | # the independently resolved directory relocation.
|
| 2492 | git read-tree B
|
| 2493 | git update-index --force-remove h/h
|
| 2494 | git update-index --add --cacheinfo "100644,$(git rev-parse main:a/a/a),c/h"
|
| 2495 | make_resolve_tree ours B A
|
| 2496 | )
|
| 2497 |
|
| 2498 | (cd unrelated-renames-to-same-path-with-type-mismatch
|
| 2499 | # Ancestor resolution rejects both incompatible destination renames.
|
| 2500 | git read-tree main
|
| 2501 | make_resolve_tree ancestor A B
|
| 2502 | make_resolve_tree ancestor B A
|
| 2503 |
|
| 2504 | # Choosing ours applies only the rename from the side named first.
|
| 2505 | git read-tree A
|
| 2506 | make_resolve_tree ours A B
|
| 2507 | git read-tree B
|
| 2508 | make_resolve_tree ours B A
|
| 2509 | )
|
| 2510 |
|
| 2511 | (cd renamed-file-vs-file-to-directory-with-siblings
|
| 2512 | # Git retains the base file as stage 1 at its rename destination. As in the
|
| 2513 | # other rename/delete cases, gix records only the side that kept the file.
|
| 2514 | IFS= read -r -d '' merged_tree_id <A-B.merge-info
|
| 2515 | rm .git/index
|
| 2516 | git read-tree "$merged_tree_id"
|
| 2517 | git update-index --force-remove h
|
| 2518 | git update-index --index-info <<EOF
|
| 2519 | 100644 blob $(git rev-parse A:h) 2 h
|
| 2520 | EOF
|
| 2521 | make_conflict_index renamed-file-vs-file-to-directory-with-siblings-A-B
|
| 2522 |
|
| 2523 | rm .git/index
|
| 2524 | git read-tree "$merged_tree_id"
|
| 2525 | git update-index --force-remove h
|
| 2526 | git update-index --index-info <<EOF
|
| 2527 | 100644 blob $(git rev-parse A:h) 3 h
|
| 2528 | EOF
|
| 2529 | make_conflict_index renamed-file-vs-file-to-directory-with-siblings-A-B-reversed
|
| 2530 |
|
| 2531 | # Ancestor resolution rejects the rename and the file-to-directory
|
| 2532 | # replacement, restoring the base file.
|
| 2533 | git read-tree main
|
| 2534 | make_resolve_tree ancestor A B
|
| 2535 | make_resolve_tree ancestor B A
|
| 2536 |
|
| 2537 | # Choosing A keeps its rename while still accepting B's non-conflicting
|
| 2538 | # children at the now-vacant source path.
|
| 2539 | IFS= read -r -d '' merged_tree_id <A-B.merge-info
|
| 2540 | git read-tree "$merged_tree_id"
|
| 2541 | make_resolve_tree ours A B
|
| 2542 |
|
| 2543 | # Choosing B rejects A's rename and keeps B's replacement directory.
|
| 2544 | git read-tree B
|
| 2545 | make_resolve_tree ours B A
|
| 2546 | )
|
| 2547 |
|
| 2548 | (cd gitlink-vs-renamed-symlink-directory-with-siblings
|
| 2549 | # Git retains the renamed symlink's base stage and leaves `a/b` unconflicted.
|
| 2550 | # gix instead records only the surviving rename side and the relocated
|
| 2551 | # addition as the two sides of its file/directory conflict.
|
| 2552 | rm .git/index
|
| 2553 | git update-index --index-info <<EOF
|
| 2554 | 120000 blob $(git rev-parse B:h/a) 3 h/a
|
| 2555 | 100644 blob $(git rev-parse B:h/b/a) h/b/a
|
| 2556 | 100644 blob $(git rev-parse A:a/b) 2 h/b~A
|
| 2557 | EOF
|
| 2558 | make_conflict_index gitlink-vs-renamed-symlink-directory-with-siblings-A-B
|
| 2559 |
|
| 2560 | rm .git/index
|
| 2561 | git update-index --index-info <<EOF
|
| 2562 | 120000 blob $(git rev-parse B:h/a) 2 h/a
|
| 2563 | 100644 blob $(git rev-parse B:h/b/a) h/b/a
|
| 2564 | 100644 blob $(git rev-parse A:a/b) 3 h/b~A
|
| 2565 | 160000 commit $(git rev-parse main:h) 2 h~B
|
| 2566 | EOF
|
| 2567 | make_conflict_index gitlink-vs-renamed-symlink-directory-with-siblings-A-B-reversed
|
| 2568 |
|
| 2569 | # Ancestor keeps the renamed symlink at its base path, while the independent
|
| 2570 | # sibling below B's replacement directory remains applicable.
|
| 2571 | git read-tree main
|
| 2572 | git update-index --force-remove h
|
| 2573 | git update-index --add --cacheinfo "100644,$(git rev-parse B:h/b/a),h/b/a"
|
| 2574 | make_resolve_tree ancestor A B
|
| 2575 | git read-tree main
|
| 2576 | git update-index --force-remove h
|
| 2577 | git update-index --add --cacheinfo "100644,$(git rev-parse B:h/b/a),h/b/a"
|
| 2578 | make_resolve_tree ancestor B A
|
| 2579 |
|
| 2580 | # With A as ours, its addition follows the detected directory rename while
|
| 2581 | # the conflicting gitlink and B's sibling are rejected.
|
| 2582 | git read-tree --empty
|
| 2583 | git update-index --add --cacheinfo "100644,$(git rev-parse A:a/b),h/b"
|
| 2584 | make_resolve_tree ours A B
|
| 2585 |
|
| 2586 | # With B as ours, retain B's replacement directory.
|
| 2587 | git read-tree B
|
| 2588 | make_resolve_tree ours B A
|
| 2589 | )
|
| 2590 |
|
| 2591 | (cd rename-delete-after-consumed-path
|
| 2592 | # Git associates the repeated blobs with different rename sources. Record
|
| 2593 | # gix's structured conflicts explicitly; the worktree tree is documented by
|
| 2594 | # the `expected` branches above.
|
| 2595 | rm .git/index
|
| 2596 | git update-index --index-info <<EOF
|
| 2597 | 100755 blob $(git rev-parse main:a/a) 1 a/a
|
| 2598 | 100644 blob $(git rev-parse A:a/d/a) 2 a/d/a
|
| 2599 | 100644 blob $(git rev-parse A:a/a/a) 2 b/a/a
|
| 2600 | 100644 blob $(git rev-parse B:b/a/a) 3 b/a/a
|
| 2601 | 100644 blob $(git rev-parse A:a/d/a) b/d/a
|
| 2602 | 100644 blob $(git rev-parse A:d) d
|
| 2603 | 100644 blob $(git rev-parse A:e) 2 e
|
| 2604 | 100644 blob $(git rev-parse B:e) 3 e
|
| 2605 | 100644 blob $(git rev-parse A:f) 2 f
|
| 2606 | 100644 blob $(git rev-parse B:f) 3 f
|
| 2607 | EOF
|
| 2608 | make_conflict_index rename-delete-after-consumed-path-A-B
|
| 2609 |
|
| 2610 | rm .git/index
|
| 2611 | git update-index --index-info <<EOF
|
| 2612 | 100755 blob $(git rev-parse main:a/a) 1 a/a
|
| 2613 | 100644 blob $(git rev-parse A:a/d/a) 3 a/d/a
|
| 2614 | 100644 blob $(git rev-parse B:b/a/a) 2 b/a/a
|
| 2615 | 100644 blob $(git rev-parse A:a/a/a) 3 b/a/a
|
| 2616 | 100644 blob $(git rev-parse A:a/d/a) b/d/a
|
| 2617 | 100644 blob $(git rev-parse A:d) d
|
| 2618 | 100644 blob $(git rev-parse B:e) 2 e
|
| 2619 | 100644 blob $(git rev-parse A:e) 3 e
|
| 2620 | 100644 blob $(git rev-parse B:f) 2 f
|
| 2621 | 100644 blob $(git rev-parse A:f) 3 f
|
| 2622 | EOF
|
| 2623 | make_conflict_index rename-delete-after-consumed-path-A-B-reversed
|
| 2624 | )
|
| 2625 |
|
| 2626 | (cd simple
|
| 2627 | rm .git/index
|
| 2628 | # 'whatever' is tree-conflict, 'greeting' is content conflict with markers
|
| 2629 | git update-index --index-info <<EOF
|
| 2630 | 100644 $(oid 45b983be36b73c0788dc9cbcb76cbb80fc7bb057) 0 greeting
|
| 2631 | 100644 $(oid 09c277aa66897c58157f57a374eacc63a407dcab) 0 numbers
|
| 2632 | 100644 $(oid 5716ca5987cbf97d6bb54920bea6adde242d87e6) 0 whatever
|
| 2633 | EOF
|
| 2634 | make_resolve_tree ours side1 side2
|
| 2635 |
|
| 2636 | rm .git/index
|
| 2637 | git update-index --index-info <<EOF
|
| 2638 | 100644 $(oid 092bfb9bdf74dd8cfd22e812151281ee9aa6f01a) 0 greeting
|
| 2639 | 100644 $(oid 09c277aa66897c58157f57a374eacc63a407dcab) 0 numbers
|
| 2640 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 whatever/empty
|
| 2641 | EOF
|
| 2642 | make_resolve_tree ours side2 side1
|
| 2643 |
|
| 2644 | rm .git/index
|
| 2645 | git update-index --index-info <<EOF
|
| 2646 | 100644 $(oid 9dc97bdc2426e68423360e3e5299280b2cf6b8ff) 0 greeting
|
| 2647 | 100644 $(oid 09c277aa66897c58157f57a374eacc63a407dcab) 0 numbers
|
| 2648 | 100644 $(oid 257cc5642cb1a054f08cc83f2d943e56fd3ebe99) 0 whatever
|
| 2649 | EOF
|
| 2650 | make_resolve_tree ancestor side1 side2
|
| 2651 |
|
| 2652 | rm .git/index
|
| 2653 | git update-index --index-info <<EOF
|
| 2654 | 100644 $(oid 1a2664a9924754c698e323f756f9f87f3f2fb337) 0 greeting
|
| 2655 | 100644 $(oid 09c277aa66897c58157f57a374eacc63a407dcab) 0 numbers
|
| 2656 | 100644 $(oid 257cc5642cb1a054f08cc83f2d943e56fd3ebe99) 0 whatever
|
| 2657 | EOF
|
| 2658 | make_resolve_tree ancestor side2 side1
|
| 2659 |
|
| 2660 | rm .git/index
|
| 2661 | git update-index --index-info <<EOF
|
| 2662 | 100644 $(oid a4ae6e4709228b5da6001cb9d1cfa7736851e2a6) 0 greeting
|
| 2663 | 100644 $(oid 257cc5642cb1a054f08cc83f2d943e56fd3ebe99) 0 whatever
|
| 2664 | 100644 $(oid 542802a799ded74fa01c47ba2f8925e284a369e2) 0 Αυτά μου φαίνονται κινέζικα
|
| 2665 | EOF
|
| 2666 | make_resolve_tree ancestor tweak1 side2
|
| 2667 |
|
| 2668 | rm .git/index
|
| 2669 | git update-index --index-info <<EOF
|
| 2670 | 100644 $(oid 45b983be36b73c0788dc9cbcb76cbb80fc7bb057) 0 greeting
|
| 2671 | 100644 $(oid 5716ca5987cbf97d6bb54920bea6adde242d87e6) 0 whatever
|
| 2672 | 100644 $(oid 65bc6a1e238f4bf05b28fd05240636e2cfb657e0) 0 Αυτά μου φαίνονται κινέζικα
|
| 2673 | EOF
|
| 2674 | make_resolve_tree ours tweak1 side2
|
| 2675 |
|
| 2676 | rm .git/index
|
| 2677 | git update-index --index-info <<EOF
|
| 2678 | 100644 blob $(oid ea28dcd7f627a2a7bbd09daa679c452180617c9f) greeting
|
| 2679 | 100644 blob $(oid 257cc5642cb1a054f08cc83f2d943e56fd3ebe99) whatever
|
| 2680 | 100644 blob $(oid f801a62deed900f8a80ff35e3339474ad6352a93) Αυτά μου φαίνονται κινέζικα
|
| 2681 | EOF
|
| 2682 | make_resolve_tree ancestor side2 tweak1
|
| 2683 |
|
| 2684 | rm .git/index
|
| 2685 | git update-index --index-info <<EOF
|
| 2686 | 100644 blob $(oid 092bfb9bdf74dd8cfd22e812151281ee9aa6f01a) greeting
|
| 2687 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) whatever/empty
|
| 2688 | 100644 blob $(oid 09c277aa66897c58157f57a374eacc63a407dcab) Αυτά μου φαίνονται κινέζικα
|
| 2689 | EOF
|
| 2690 | make_resolve_tree ours side2 tweak1
|
| 2691 | )
|
| 2692 |
|
| 2693 | (cd rename-add-symlink
|
| 2694 | rm .git/index
|
| 2695 | # the symlink of 'bar' from A
|
| 2696 | git update-index --index-info <<EOF
|
| 2697 | 120000 blob $(oid 19102815663d23f8b75a47e7a01965dcdc96468c) bar
|
| 2698 | EOF
|
| 2699 | make_resolve_tree ours A B
|
| 2700 |
|
| 2701 | rm .git/index
|
| 2702 | # the merged form of 'bar' from B, not replaced by symlink
|
| 2703 | git update-index --index-info <<EOF
|
| 2704 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) bar
|
| 2705 | EOF
|
| 2706 | make_resolve_tree ours B A
|
| 2707 |
|
| 2708 | rm .git/index
|
| 2709 | # foo is renamed to bar, type clash means neither A nor B can be added - empty tree
|
| 2710 | # It is not able to 'get foo back', it can't track that currently.
|
| 2711 | make_resolve_tree ancestor A B
|
| 2712 | make_resolve_tree ancestor B A
|
| 2713 | )
|
| 2714 |
|
| 2715 | (cd deleted-file-added-dir-with-rename
|
| 2716 | rm .git/index
|
| 2717 | # Unlike Git, we don't retain the base stage at the rename destination.
|
| 2718 | git update-index --index-info <<EOF
|
| 2719 | 100644 blob $(oid df967b96a579e45a18b8251732d16804b2e56a55) 3 renamed
|
| 2720 | 100644 blob $(oid d5f7fc3f74f7dec08280f370a975b112e8f60818) x/a
|
| 2721 | EOF
|
| 2722 | make_conflict_index deleted-file-added-dir-with-rename-A-B
|
| 2723 |
|
| 2724 | rm .git/index
|
| 2725 | git update-index --index-info <<EOF
|
| 2726 | 100644 blob $(oid df967b96a579e45a18b8251732d16804b2e56a55) 2 renamed
|
| 2727 | 100644 blob $(oid d5f7fc3f74f7dec08280f370a975b112e8f60818) x/a
|
| 2728 | EOF
|
| 2729 | make_conflict_index deleted-file-added-dir-with-rename-A-B-reversed
|
| 2730 |
|
| 2731 | rm .git/index
|
| 2732 | git update-index --index-info <<EOF
|
| 2733 | 100644 blob $(oid df967b96a579e45a18b8251732d16804b2e56a55) x
|
| 2734 | EOF
|
| 2735 | make_resolve_tree ancestor A B
|
| 2736 | make_resolve_tree ancestor B A
|
| 2737 | )
|
| 2738 |
|
| 2739 | (cd same-rename-and-file-to-directory
|
| 2740 | # Forced ours keeps the agreed rename and resolves the added child's content in favor
|
| 2741 | # of the current side. Use each complete side tree as the directional expectation.
|
| 2742 | git read-tree A
|
| 2743 | make_resolve_tree ours A B
|
| 2744 |
|
| 2745 | git read-tree B
|
| 2746 | make_resolve_tree ours B A
|
| 2747 | )
|
| 2748 |
|
| 2749 | (cd rename-change-matrix
|
| 2750 | # `different-renames` needs Git's content-conflicted blob at both rename destinations.
|
| 2751 | # The first NUL-delimited field is the merged tree written by `git merge-tree`.
|
| 2752 | IFS= read -r -d '' merged_tree_id <A-B.merge-info
|
| 2753 | different_merged_id=$(git rev-parse "$merged_tree_id:different-renames/ours")
|
| 2754 | IFS= read -r -d '' merged_reversed_tree_id <A-B-reversed.merge-info
|
| 2755 | different_merged_reversed_id=$(git rev-parse "$merged_reversed_tree_id:different-renames/theirs")
|
| 2756 |
|
| 2757 | # Expected A/B index, grouped by the matrix above. It differs from Git only in two places,
|
| 2758 | # neither of which alters the merged tree:
|
| 2759 | #
|
| 2760 | # * delete-source: only A's renamed side remains. Git also places the source's base blob at
|
| 2761 | # stage 1 of the renamed path; gix doesn't invent that path for the base entry.
|
| 2762 | # * directory-old: gix considers the added child relocated by the directory rename and records
|
| 2763 | # it at stage 0. Git reports a "file location" conflict and records the relocated child at
|
| 2764 | # stage 3, even though its diagnostic also suggests the same destination.
|
| 2765 | #
|
| 2766 | # The other matrix entries match Git's index:
|
| 2767 | # * add-destination: A's rename and B's addition occupy stages 2 and 3 at `target`.
|
| 2768 | # * delete-destination: the old target is stage 1 and A's replacement is stage 2.
|
| 2769 | # * different-renames: retain the base source and put the merged conflict blob at both destinations.
|
| 2770 | # * modify-destination: the old destination and both replacements occupy stages 1, 2, and 3.
|
| 2771 | # * modify-source: the edit follows the rename and resolves cleanly at stage 0.
|
| 2772 | rm .git/index
|
| 2773 | git update-index --index-info <<EOF
|
| 2774 | 100644 blob $(git rev-parse main:.gitattributes) .gitattributes
|
| 2775 | 100644 blob $(git rev-parse A:add-destination/target) 2 add-destination/target
|
| 2776 | 100644 blob $(git rev-parse B:add-destination/target) 3 add-destination/target
|
| 2777 | 100644 blob $(git rev-parse main:delete-destination/target) 1 delete-destination/target
|
| 2778 | 100644 blob $(git rev-parse A:delete-destination/target) 2 delete-destination/target
|
| 2779 | 100644 blob $(git rev-parse A:delete-source/renamed) 2 delete-source/renamed
|
| 2780 | 100644 blob $(git rev-parse main:different-renames/file) 1 different-renames/file
|
| 2781 | 100644 blob $different_merged_id 2 different-renames/ours
|
| 2782 | 100644 blob $different_merged_id 3 different-renames/theirs
|
| 2783 | 100644 blob $(git rev-parse B:directory-old/added) directory-renamed/added
|
| 2784 | 100644 blob $(git rev-parse A:directory-renamed/file) directory-renamed/file
|
| 2785 | 100644 blob $(git rev-parse main:modify-destination/target) 1 modify-destination/target
|
| 2786 | 100644 blob $(git rev-parse A:modify-destination/target) 2 modify-destination/target
|
| 2787 | 100644 blob $(git rev-parse B:modify-destination/target) 3 modify-destination/target
|
| 2788 | 100644 blob $(git rev-parse B:modify-source/file) modify-source/renamed
|
| 2789 | EOF
|
| 2790 | make_conflict_index rename-change-matrix-A-B
|
| 2791 |
|
| 2792 | # The reversed index has the same shape, with stages 2 and 3 exchanged and directional
|
| 2793 | # content-conflict labels reversed.
|
| 2794 | rm .git/index
|
| 2795 | git update-index --index-info <<EOF
|
| 2796 | 100644 blob $(git rev-parse main:.gitattributes) .gitattributes
|
| 2797 | 100644 blob $(git rev-parse B:add-destination/target) 2 add-destination/target
|
| 2798 | 100644 blob $(git rev-parse A:add-destination/target) 3 add-destination/target
|
| 2799 | 100644 blob $(git rev-parse main:delete-destination/target) 1 delete-destination/target
|
| 2800 | 100644 blob $(git rev-parse A:delete-destination/target) 3 delete-destination/target
|
| 2801 | 100644 blob $(git rev-parse A:delete-source/renamed) 3 delete-source/renamed
|
| 2802 | 100644 blob $(git rev-parse main:different-renames/file) 1 different-renames/file
|
| 2803 | 100644 blob $different_merged_reversed_id 3 different-renames/ours
|
| 2804 | 100644 blob $different_merged_reversed_id 2 different-renames/theirs
|
| 2805 | 100644 blob $(git rev-parse B:directory-old/added) directory-renamed/added
|
| 2806 | 100644 blob $(git rev-parse A:directory-renamed/file) directory-renamed/file
|
| 2807 | 100644 blob $(git rev-parse main:modify-destination/target) 1 modify-destination/target
|
| 2808 | 100644 blob $(git rev-parse B:modify-destination/target) 2 modify-destination/target
|
| 2809 | 100644 blob $(git rev-parse A:modify-destination/target) 3 modify-destination/target
|
| 2810 | 100644 blob $(git rev-parse B:modify-source/file) modify-source/renamed
|
| 2811 | EOF
|
| 2812 | make_conflict_index rename-change-matrix-A-B-reversed
|
| 2813 | )
|
| 2814 |
|
| 2815 | (cd same-rename-with-content
|
| 2816 | # The merged tree matches Git, but the conflict index differs. Git puts the base and the
|
| 2817 | # original A and B blobs at stages 1, 2, and 3 of `target`. gix instead keeps the base at
|
| 2818 | # its original path `file` and puts the already-merged conflict blob into both destination
|
| 2819 | # stages. The structured conflict still retains the original side entries.
|
| 2820 | rm .git/index
|
| 2821 | git update-index --index-info <<EOF
|
| 2822 | 100644 blob $(git rev-parse main:file) 1 file
|
| 2823 | 100644 blob $(git rev-parse expected:target) 2 target
|
| 2824 | 100644 blob $(git rev-parse expected:target) 3 target
|
| 2825 | EOF
|
| 2826 | make_conflict_index same-rename-with-content-A-B
|
| 2827 |
|
| 2828 | rm .git/index
|
| 2829 | git update-index --index-info <<EOF
|
| 2830 | 100644 blob $(git rev-parse main:file) 1 file
|
| 2831 | 100644 blob $(git rev-parse expected-reversed:target) 2 target
|
| 2832 | 100644 blob $(git rev-parse expected-reversed:target) 3 target
|
| 2833 | EOF
|
| 2834 | make_conflict_index same-rename-with-content-A-B-reversed
|
| 2835 | )
|
| 2836 |
|
| 2837 | (cd renames-to-same-destination
|
| 2838 | # Git leaves this unresolved as an add/add at `target`, with A at stage 2 and B at stage 3
|
| 2839 | # and neither original path in the index. The following trees instead record gix's explicit
|
| 2840 | # conflict-resolution modes.
|
| 2841 | #
|
| 2842 | # Ancestor resolution applies neither rename, so both original files remain in both directions.
|
| 2843 | rm .git/index
|
| 2844 | git update-index --index-info <<EOF
|
| 2845 | 100644 blob $(git rev-parse main:one) one
|
| 2846 | 100644 blob $(git rev-parse main:two) two
|
| 2847 | EOF
|
| 2848 | make_resolve_tree ancestor A B
|
| 2849 | make_resolve_tree ancestor B A
|
| 2850 |
|
| 2851 | # "Ours" for A/B applies A's `one` -> `target` and leaves B's source `two` untouched,
|
| 2852 | # unlike Git's unresolved index described above.
|
| 2853 | rm .git/index
|
| 2854 | git update-index --index-info <<EOF
|
| 2855 | 100644 blob $(git rev-parse A:target) target
|
| 2856 | 100644 blob $(git rev-parse main:two) two
|
| 2857 | EOF
|
| 2858 | make_resolve_tree ours A B
|
| 2859 |
|
| 2860 | # Reversing the merge makes B ours: apply `two` -> `target` and leave `one` untouched,
|
| 2861 | # again replacing Git's unresolved add/add with a resolved tree.
|
| 2862 | rm .git/index
|
| 2863 | git update-index --index-info <<EOF
|
| 2864 | 100644 blob $(git rev-parse main:one) one
|
| 2865 | 100644 blob $(git rev-parse B:target) target
|
| 2866 | EOF
|
| 2867 | make_resolve_tree ours B A
|
| 2868 | )
|
| 2869 |
|
| 2870 | (cd identical-renames-to-same-destination
|
| 2871 | # Identical entries make the two renames compatible rather than a tree
|
| 2872 | # conflict, so conflict-resolution policy must not alter the clean result.
|
| 2873 | IFS= read -r -d '' merged_tree_id <A-B.merge-info
|
| 2874 | git read-tree "$merged_tree_id"
|
| 2875 | make_resolve_tree ancestor A B
|
| 2876 | make_resolve_tree ancestor B A
|
| 2877 | make_resolve_tree ours A B
|
| 2878 | make_resolve_tree ours B A
|
| 2879 | )
|
| 2880 |
|
| 2881 | (cd identical-renames-to-same-destination-with-mode-change
|
| 2882 | # Git leaves the two destination modes at stages 2 and 3. gix resolves the
|
| 2883 | # identical content and the one-sided executable change into a stage-0 entry.
|
| 2884 | git read-tree expected
|
| 2885 | make_conflict_index identical-renames-to-same-destination-with-mode-change-A-B
|
| 2886 | make_conflict_index identical-renames-to-same-destination-with-mode-change-A-B-reversed
|
| 2887 |
|
| 2888 | # Ancestor rejects both colliding renames.
|
| 2889 | git read-tree main
|
| 2890 | make_resolve_tree ancestor A B
|
| 2891 | make_resolve_tree ancestor B A
|
| 2892 |
|
| 2893 | # Ours applies the selected side's rename and retains the other source.
|
| 2894 | git read-tree A
|
| 2895 | make_resolve_tree ours A B
|
| 2896 | git read-tree B
|
| 2897 | make_resolve_tree ours B A
|
| 2898 | )
|
| 2899 |
|
| 2900 | (cd rename-rename-plus-content
|
| 2901 | rm .git/index
|
| 2902 | # both sides rename 'foo' into something else.
|
| 2903 | git update-index --index-info <<EOF
|
| 2904 | 100644 blob $(oid 8a1218a1024a212bb3db30becd860315f9f3ac52) foo
|
| 2905 | EOF
|
| 2906 | make_resolve_tree ancestor A B
|
| 2907 | make_resolve_tree ancestor B A
|
| 2908 |
|
| 2909 | rm .git/index
|
| 2910 | # 'bar' is the name in 'A', and there is a merge with the content from 'B'
|
| 2911 | # which we auto-resolve.
|
| 2912 | git update-index --index-info <<EOF
|
| 2913 | 100644 blob $(oid d0549c3d3c96a464289f3b820b7d96aedc58924b) bar
|
| 2914 | EOF
|
| 2915 | make_resolve_tree ours A B
|
| 2916 |
|
| 2917 | rm .git/index
|
| 2918 | # 'baz' is the name in 'B', and there is a merge with the content from 'A'
|
| 2919 | # which we auto-resolve.
|
| 2920 | git update-index --index-info <<EOF
|
| 2921 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) baz
|
| 2922 | EOF
|
| 2923 | make_resolve_tree ours B A
|
| 2924 | )
|
| 2925 |
|
| 2926 | (cd rename-add-delete
|
| 2927 | rm .git/index
|
| 2928 | # 'foo' is deleted, 'bar' is added in 'A', but renamed to 'bar' in 'B'.
|
| 2929 | # Do nothing, *should* keep 'foo', and it's re-added later, which copies it.
|
| 2930 | # But instead we keep foo the first time, but then it 'turns' and we process a remaining
|
| 2931 | # addition that once again sees the rename from the other side, which is not a conflict
|
| 2932 | # and thus removes 'foo' after all, and merges 'bar'.
|
| 2933 | # It's not super-correct, but it's only an issue for virtual merge bases, which are kind of
|
| 2934 | # hidden anyway.
|
| 2935 | git update-index --index-info <<EOF
|
| 2936 | 100644 blob $(oid 0cde534c2fca6c92c07b3e7a696665e844b9b933) bar
|
| 2937 | EOF
|
| 2938 | make_resolve_tree ancestor A B
|
| 2939 | # B A isn't tested, as it is not an Err() conflict.
|
| 2940 |
|
| 2941 | # This case ends up being exactly the same as the ancestor, but with the merge-conflict
|
| 2942 | # auto-resolved to 'ours'.
|
| 2943 | # This time, it's expected to not have 'foo', but 'ours' in the clashing pair is a deletion. The rename side
|
| 2944 | # is dropped, but what's left is the rename/add pair once the algorithm turns around/flips.
|
| 2945 | rm .git/index
|
| 2946 | git update-index --index-info <<EOF
|
| 2947 | 100644 blob $(oid f286e5cdd97ac6895438ea4548638bb98ac9bd6b) bar
|
| 2948 | EOF
|
| 2949 | make_resolve_tree ours A B
|
| 2950 | )
|
| 2951 |
|
| 2952 | (cd rename-rename-delete-delete
|
| 2953 | rm .git/index
|
| 2954 | # 'A' deletes 'bar' and 'B' turns 'bar' into 'baz'. 'A' renames 'foo' into 'bar', and
|
| 2955 | # 'B' deletes 'foo'. 'ancestor' resolves to avoid any edits, leaving the state from 'main'.
|
| 2956 | git update-index --index-info <<EOF
|
| 2957 | 100644 blob $(oid 5716ca5987cbf97d6bb54920bea6adde242d87e6) bar
|
| 2958 | 100644 blob $(oid 257cc5642cb1a054f08cc83f2d943e56fd3ebe99) foo
|
| 2959 | EOF
|
| 2960 | make_resolve_tree ancestor A B
|
| 2961 | # this works in reverse as well (this time).
|
| 2962 | make_resolve_tree ancestor B A
|
| 2963 |
|
| 2964 | rm .git/index
|
| 2965 | # As 'ours' is a deletion of 'foo', it goes through, but we also acknowledge 'theirs'
|
| 2966 | # as it gives better results, so end up with `baz`.
|
| 2967 | git update-index --index-info <<EOF
|
| 2968 | 100644 blob $(oid 257cc5642cb1a054f08cc83f2d943e56fd3ebe99) baz
|
| 2969 | EOF
|
| 2970 | make_resolve_tree ours A B
|
| 2971 |
|
| 2972 | rm .git/index
|
| 2973 | # Here we end up in exactly the same spot as if we'd do a normal merge,
|
| 2974 | # which ends `baz` in a conflict. However, with content-merges set to 'ours'
|
| 2975 | # it ends up like it should, giving a good result.
|
| 2976 | git update-index --index-info <<EOF
|
| 2977 | 100644 blob $(oid 5716ca5987cbf97d6bb54920bea6adde242d87e6) baz
|
| 2978 | EOF
|
| 2979 | make_resolve_tree ours B A
|
| 2980 | )
|
| 2981 |
|
| 2982 | (cd super-1
|
| 2983 | # Each of the ancestor files are renamed in a conflicting way, and here
|
| 2984 | # with ancestor choice, nothing happens, making this equivalent to `main`
|
| 2985 | git checkout main
|
| 2986 | make_resolve_tree ancestor A B
|
| 2987 | make_resolve_tree ancestor B A
|
| 2988 |
|
| 2989 | rm .git/index
|
| 2990 | # We do indeed perform the renames like this, and the content is merges as well as possible,
|
| 2991 | # (here) configured to content-merge with 'ours' as well where needed.
|
| 2992 | git update-index --index-info <<EOF
|
| 2993 | 100644 blob $(oid 4b5599c7c2ed4390417d9699bec86144a386873d) four
|
| 2994 | 100644 blob $(oid 64012489f118cb4011c8902b4a635f70dcb0c0ca) six
|
| 2995 | 100644 blob $(oid e33f5e94470d3b5fa0220ff6a9cabb78a3f72fa3) two
|
| 2996 | EOF
|
| 2997 | make_resolve_tree ours A B
|
| 2998 |
|
| 2999 | rm .git/index
|
| 3000 | # The same, but from the other side.
|
| 3001 | git update-index --index-info <<EOF
|
| 3002 | 100644 blob $(oid 64012489f118cb4011c8902b4a635f70dcb0c0ca) four
|
| 3003 | 100644 blob $(oid e33f5e94470d3b5fa0220ff6a9cabb78a3f72fa3) six
|
| 3004 | 100644 blob $(oid 4178ea6795c4c3e07b4e17e6a04aa49584b07ecd) two
|
| 3005 | EOF
|
| 3006 | make_resolve_tree ours B A
|
| 3007 | )
|
| 3008 |
|
| 3009 | (cd super-2
|
| 3010 | rm .git/index
|
| 3011 | # 'B' changes foo, and moves it into 'olddir/bar', but `A' deleted 'foo', and adds 'newdir/bar/file'
|
| 3012 | # after renaming 'olddir' to 'newdir'.
|
| 3013 | # As `B` only has a single change that gets dropped when it clashes with the deletion of 'foo',
|
| 3014 | # all other changes of 'A' can just be applied without any conflict whatsoever.
|
| 3015 | git update-index --index-info <<EOF
|
| 3016 | 100644 blob $(oid 8a1218a1024a212bb3db30becd860315f9f3ac52) foo
|
| 3017 | 100644 blob $(oid 78981922613b2afb6025042ff6bd878ac1994e85) newdir/a
|
| 3018 | 100644 blob $(oid 61780798228d17af2d34fce4cfbdf35556832472) newdir/b
|
| 3019 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) newdir/bar/file
|
| 3020 | 100644 blob $(oid f2ad6c76f0115a6ba5b00456a849810e7ec0af20) newdir/c
|
| 3021 | EOF
|
| 3022 | make_resolve_tree ancestor A B
|
| 3023 | make_resolve_tree ancestor B A
|
| 3024 |
|
| 3025 | rm .git/index
|
| 3026 | # Similar to the ancestor version, but now we choose 'ours', so the rename of 'foo' gets
|
| 3027 | # dropped and it just gets deleted. Everything else is then 'A'.
|
| 3028 | git update-index --index-info <<EOF
|
| 3029 | 100644 blob $(oid 78981922613b2afb6025042ff6bd878ac1994e85) newdir/a
|
| 3030 | 100644 blob $(oid 61780798228d17af2d34fce4cfbdf35556832472) newdir/b
|
| 3031 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) newdir/bar/file
|
| 3032 | 100644 blob $(oid f2ad6c76f0115a6ba5b00456a849810e7ec0af20) newdir/c
|
| 3033 | EOF
|
| 3034 | make_resolve_tree ours A B
|
| 3035 |
|
| 3036 | rm .git/index
|
| 3037 | # 'B' changes 'foo' and moves it to 'olddir/bar', which gets tracked to be
|
| 3038 | # 'newdir/bar' and is taken verbatim. The clash that it finds it
|
| 3039 | # resolves in 'B's favor, leaving only 'newdir/bar'.
|
| 3040 | git update-index --index-info <<EOF
|
| 3041 | 100644 blob $(oid 78981922613b2afb6025042ff6bd878ac1994e85) newdir/a
|
| 3042 | 100644 blob $(oid 61780798228d17af2d34fce4cfbdf35556832472) newdir/b
|
| 3043 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) newdir/bar
|
| 3044 | 100644 blob $(oid f2ad6c76f0115a6ba5b00456a849810e7ec0af20) newdir/c
|
| 3045 | EOF
|
| 3046 | make_resolve_tree ours B A
|
| 3047 | )
|
| 3048 |
|
| 3049 | (cd conflicting-rename
|
| 3050 | rm .git/index
|
| 3051 | # 'A' renames 'a' to 'a-renamed', 'B' renames 'a' to 'a-different'.
|
| 3052 | # All these conflicts are dropped in favor of keeping the 'ancestor' *location*.
|
| 3053 | git update-index --index-info <<EOF
|
| 3054 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/sub/y.f
|
| 3055 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub/z
|
| 3056 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/w
|
| 3057 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/x.f
|
| 3058 | EOF
|
| 3059 | make_resolve_tree ancestor A B
|
| 3060 | make_resolve_tree ancestor B A
|
| 3061 |
|
| 3062 | rm .git/index
|
| 3063 | # Much like the ancestor version, except that it applied the 'A' rename,
|
| 3064 | # along with its *merged* content.
|
| 3065 | git update-index --index-info <<EOF
|
| 3066 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a-renamed/sub/y.f
|
| 3067 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-renamed/sub/z
|
| 3068 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-renamed/w
|
| 3069 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a-renamed/x.f
|
| 3070 | EOF
|
| 3071 | make_resolve_tree ours A B
|
| 3072 | rm .git/index
|
| 3073 | # Just like 'A' above, but with the 'B' rename chosen and all the merges.
|
| 3074 | git update-index --index-info <<EOF
|
| 3075 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a-different/sub/y.f
|
| 3076 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-different/sub/z
|
| 3077 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-different/w
|
| 3078 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a-different/x.f
|
| 3079 | EOF
|
| 3080 | make_resolve_tree ours B A
|
| 3081 | )
|
| 3082 |
|
| 3083 | (cd conflicting-rename-2
|
| 3084 | rm .git/index
|
| 3085 | # Like 'conflicting-rename', but this one only renames a single sub-directory for very much the same effect.
|
| 3086 | # Thus, keeping the 'ancestor' version is the same as 'main', except for merged content.
|
| 3087 | git update-index --index-info <<EOF
|
| 3088 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/sub/y.f
|
| 3089 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub/z
|
| 3090 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/w
|
| 3091 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/x.f
|
| 3092 | EOF
|
| 3093 | make_resolve_tree ancestor A B
|
| 3094 | make_resolve_tree ancestor B A
|
| 3095 |
|
| 3096 | rm .git/index
|
| 3097 | git update-index --index-info <<EOF
|
| 3098 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/sub-renamed/y.f
|
| 3099 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub-renamed/z
|
| 3100 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/w
|
| 3101 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/x.f
|
| 3102 | EOF
|
| 3103 | make_resolve_tree ours A B
|
| 3104 | rm .git/index
|
| 3105 | git update-index --index-info <<EOF
|
| 3106 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/sub-different/y.f
|
| 3107 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub-different/z
|
| 3108 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/w
|
| 3109 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/x.f
|
| 3110 | EOF
|
| 3111 | make_resolve_tree ours B A
|
| 3112 | )
|
| 3113 |
|
| 3114 | (cd conflicting-rename-complex
|
| 3115 | rm .git/index
|
| 3116 | # 'A" renames 'a' to 'a-renamed', but 'B' moves 'a/sub/' up one level, and replaces everything in its wake
|
| 3117 | # so its two files are the only ones left.
|
| 3118 | # As result, we actually have one unconflicting change which ends up creating the new directory 'a-renamed',
|
| 3119 | # but everything else is conflicting so it keeps the 'ancestor' version.
|
| 3120 | git update-index --index-info <<EOF
|
| 3121 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-renamed/z
|
| 3122 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/sub/y.f
|
| 3123 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub/z
|
| 3124 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/w
|
| 3125 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/x.f
|
| 3126 | EOF
|
| 3127 | make_resolve_tree ancestor A B
|
| 3128 | make_resolve_tree ancestor B A
|
| 3129 |
|
| 3130 | rm .git/index
|
| 3131 | # 'Ours' keeps its own version of the files 'B' deleted along with its own rename destinations,
|
| 3132 | # where the cleanly mergeable 'y.f' content is still used. Of 'theirs', only the unconflicting
|
| 3133 | # composed rename destination 'a-renamed/z' remains.
|
| 3134 | git update-index --index-info <<EOF
|
| 3135 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a-renamed/sub/y.f
|
| 3136 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-renamed/sub/z
|
| 3137 | 100644 blob $(oid 8a1218a1024a212bb3db30becd860315f9f3ac52) a-renamed/x.f
|
| 3138 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-renamed/z
|
| 3139 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-renamed/w
|
| 3140 | EOF
|
| 3141 | make_resolve_tree ours A B
|
| 3142 |
|
| 3143 | rm .git/index
|
| 3144 | # It applies the merged result of the content, and interestingly also managed to reconcile the rename from 'A'.
|
| 3145 | # However, it also drops all of 'their' conflicting changes in favor of 'ours', a respectable result.
|
| 3146 | git update-index --index-info <<EOF
|
| 3147 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a-renamed/y.f
|
| 3148 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a-renamed/z
|
| 3149 | EOF
|
| 3150 | make_resolve_tree ours B A
|
| 3151 | )
|
| 3152 |
|
| 3153 | (cd renamed-symlink-with-conflict
|
| 3154 | rm .git/index
|
| 3155 | # 'A' changes 'a/x.f' and renames the 'link', while 'B' also changes 'a/x.f' in a mergable fashion,
|
| 3156 | # while renaming 'link' to something else which is where the conflict comes from.
|
| 3157 | # Choosing the 'ancestor' means to not rename 'link' at all, while merging the file.
|
| 3158 | git update-index --index-info <<EOF
|
| 3159 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/x.f
|
| 3160 | 120000 blob $(oid e29fa63dae4ccf0788897a7025da868083178fdf) link
|
| 3161 | EOF
|
| 3162 | make_resolve_tree ancestor A B
|
| 3163 | make_resolve_tree ancestor B A
|
| 3164 |
|
| 3165 | rm .git/index
|
| 3166 | # Here we choose the name of 'link' in 'A'.
|
| 3167 | git update-index --index-info <<EOF
|
| 3168 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/x.f
|
| 3169 | 120000 blob $(oid e29fa63dae4ccf0788897a7025da868083178fdf) link-renamed
|
| 3170 | EOF
|
| 3171 | make_resolve_tree ours A B
|
| 3172 |
|
| 3173 | rm .git/index
|
| 3174 | # Here we choose the name of 'link' in 'B'.
|
| 3175 | git update-index --index-info <<EOF
|
| 3176 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/x.f
|
| 3177 | 120000 blob $(oid e29fa63dae4ccf0788897a7025da868083178fdf) link-different
|
| 3178 | EOF
|
| 3179 | make_resolve_tree ours B A
|
| 3180 | )
|
| 3181 |
|
| 3182 | (cd type-change-and-renamed
|
| 3183 | rm .git/index
|
| 3184 | # 'A' changes `link` to a file, while 'B' keeps the link, but renames it.
|
| 3185 | # 'ancestor' just keeps the original version of 'link'
|
| 3186 | git update-index --index-info <<EOF
|
| 3187 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/x.f
|
| 3188 | 120000 blob $(oid e29fa63dae4ccf0788897a7025da868083178fdf) link
|
| 3189 | EOF
|
| 3190 | make_resolve_tree ancestor A B
|
| 3191 | make_resolve_tree ancestor B A
|
| 3192 |
|
| 3193 | rm .git/index
|
| 3194 | # 'A' changes the type of 'link' to be a file, and that's what's used here.
|
| 3195 | git update-index --index-info <<EOF
|
| 3196 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/x.f
|
| 3197 | 100644 blob $(oid f89a08d1e226b9a319210641b63b07dcf0bd705f) link
|
| 3198 | EOF
|
| 3199 | make_resolve_tree ours A B
|
| 3200 |
|
| 3201 | rm .git/index
|
| 3202 | # 'B' renames the link, and that is picked up as well.
|
| 3203 | git update-index --index-info <<EOF
|
| 3204 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/x.f
|
| 3205 | 120000 blob $(oid e29fa63dae4ccf0788897a7025da868083178fdf) link-renamed
|
| 3206 | EOF
|
| 3207 | make_resolve_tree ours B A
|
| 3208 | )
|
| 3209 |
|
| 3210 | (cd change-and-delete
|
| 3211 | rm .git/index
|
| 3212 | # 'A' changes 'link' to be a file, and changes the file, while 'B' deletes everything,
|
| 3213 | # causing each file to be irreconcilable.
|
| 3214 | # 'ancestor' keeps everything as is.
|
| 3215 | git update-index --index-info <<EOF
|
| 3216 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/x.f
|
| 3217 | 120000 blob $(oid e29fa63dae4ccf0788897a7025da868083178fdf) link
|
| 3218 | EOF
|
| 3219 | make_resolve_tree ancestor A B
|
| 3220 | make_resolve_tree ancestor B A
|
| 3221 |
|
| 3222 | rm .git/index
|
| 3223 | # 'A' changes everything, and that's the change we keep.
|
| 3224 | git update-index --index-info <<EOF
|
| 3225 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/x.f
|
| 3226 | 100644 blob $(oid f89a08d1e226b9a319210641b63b07dcf0bd705f) link
|
| 3227 | EOF
|
| 3228 | make_resolve_tree ours A B
|
| 3229 |
|
| 3230 | rm .git/index
|
| 3231 | # 'B' deletes everything, which is what we keep.
|
| 3232 | make_resolve_tree ours B A
|
| 3233 | )
|
| 3234 |
|
| 3235 | (cd submodule-both-modify
|
| 3236 | rm .git/index
|
| 3237 | # There is only one submodule. 'A' and 'B' change it in a fast-forwardable manner,
|
| 3238 | # but we can't handle this at all yet, and thus have to consider it irreconcilable.
|
| 3239 | # The 'ancestor' resolution just keeps what was.
|
| 3240 | git update-index --index-info <<EOF
|
| 3241 | 160000 commit $(oid e835c0c403c8e494c0ca98f3d25d0b8464c18d38) sub
|
| 3242 | EOF
|
| 3243 | make_resolve_tree ancestor A B
|
| 3244 | make_resolve_tree ancestor B A
|
| 3245 |
|
| 3246 | rm .git/index
|
| 3247 | # Otherwise it's the state of 'A'.
|
| 3248 | git update-index --index-info <<EOF
|
| 3249 | 160000 commit $(oid 64466ebdff775ad618d9cc993cf52840e0af528c) sub
|
| 3250 | EOF
|
| 3251 | make_resolve_tree ours A B
|
| 3252 |
|
| 3253 | rm .git/index
|
| 3254 | # Otherwise it's the state of 'B'.
|
| 3255 | git update-index --index-info <<EOF
|
| 3256 | 160000 commit $(oid ea6eb701e03c2497915c25a851f3da8f8e362ca0) sub
|
| 3257 | EOF
|
| 3258 | make_resolve_tree ours B A
|
| 3259 | )
|
| 3260 |
|
| 3261 | (cd gitlink-replaced-by-files
|
| 3262 | # Resolving tree conflicts with the ancestor does not resolve the content
|
| 3263 | # conflict, so retain Git's directional conflict-marker trees.
|
| 3264 | IFS= read -r -d '' merged_tree_id <A-B.merge-info
|
| 3265 | git read-tree "$merged_tree_id"
|
| 3266 | make_resolve_tree ancestor A B
|
| 3267 | IFS= read -r -d '' merged_reversed_tree_id <A-B-reversed.merge-info
|
| 3268 | git read-tree "$merged_reversed_tree_id"
|
| 3269 | make_resolve_tree ancestor B A
|
| 3270 |
|
| 3271 | # ResolveWith::Ours also configures the blob merge to keep the current side.
|
| 3272 | git read-tree A
|
| 3273 | make_resolve_tree ours A B
|
| 3274 | git read-tree B
|
| 3275 | make_resolve_tree ours B A
|
| 3276 | )
|
| 3277 |
|
| 3278 | (cd multiple-merge-bases
|
| 3279 | rm .git/index
|
| 3280 | # 'A' modifies and 'B' deletes the single file in the tree.
|
| 3281 | # 'ancestor' keeps the original, which is already the result of the merge of
|
| 3282 | # the merge-bases.
|
| 3283 | git update-index --index-info <<EOF
|
| 3284 | 100644 blob $(oid 09c277aa66897c58157f57a374eacc63a407dcab) content
|
| 3285 | EOF
|
| 3286 | make_resolve_tree ancestor A B
|
| 3287 | make_resolve_tree ancestor B A
|
| 3288 |
|
| 3289 | rm .git/index
|
| 3290 | # 'A' keeps the modified version.
|
| 3291 | git update-index --index-info <<EOF
|
| 3292 | 100644 blob $(oid 0a6a0ba83635bc00e7c79a4b5b6e50381385c1af) content
|
| 3293 | EOF
|
| 3294 | make_resolve_tree ours A B
|
| 3295 |
|
| 3296 | rm .git/index
|
| 3297 | # 'B' applies the deletion to get an empty tree.
|
| 3298 | make_resolve_tree ours B A
|
| 3299 | )
|
| 3300 |
|
| 3301 | (cd non-tree-to-tree
|
| 3302 | rm .git/index
|
| 3303 | # 'A' changes the single file 'a', while 'B' replaces it with a directory structure 'a',
|
| 3304 | # without a rename though.
|
| 3305 | # We manage to pick the 'ancestor', just a single file, while discarding all follow-up changes.
|
| 3306 | git update-index --index-info <<EOF
|
| 3307 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a
|
| 3308 | EOF
|
| 3309 | make_resolve_tree ancestor A B
|
| 3310 | make_resolve_tree ancestor B A
|
| 3311 |
|
| 3312 | rm .git/index
|
| 3313 | # Picks 'A' which is just a single, modified (and mergable) file.
|
| 3314 | git update-index --index-info <<EOF
|
| 3315 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a
|
| 3316 | EOF
|
| 3317 | make_resolve_tree ours A B
|
| 3318 |
|
| 3319 | rm .git/index
|
| 3320 | # Picks 'B' which is a whole directory tree.
|
| 3321 | git update-index --index-info <<EOF
|
| 3322 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/d
|
| 3323 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/e
|
| 3324 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub/b
|
| 3325 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub/c
|
| 3326 | EOF
|
| 3327 | make_resolve_tree ours B A
|
| 3328 | )
|
| 3329 |
|
| 3330 | (cd tree-to-non-tree
|
| 3331 | rm .git/index
|
| 3332 | # 'A' modifies a nested file 'a/sub/b', while 'B' replaces 'a/' with file 'a'.
|
| 3333 | # Ignore *their* changes for 'ancestor' resolution, and the modification,
|
| 3334 | # but apply all others which are deletions.
|
| 3335 | git update-index --index-info <<EOF
|
| 3336 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/sub/b
|
| 3337 | EOF
|
| 3338 | make_resolve_tree ancestor A B
|
| 3339 | make_resolve_tree ancestor B A
|
| 3340 | # *ours* is the same as ancestor, we want to keep the tree and changes, but it only
|
| 3341 | # applies to the one modification that protects the change.
|
| 3342 | rm .git/index
|
| 3343 | git update-index --index-info <<EOF
|
| 3344 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/sub/b
|
| 3345 | EOF
|
| 3346 | make_resolve_tree ours A B
|
| 3347 |
|
| 3348 | rm .git/index
|
| 3349 | # Now *ours* is the single file which replaces a tree.
|
| 3350 | git update-index --index-info <<EOF
|
| 3351 | 100644 blob $(oid fa49b077972391ad58037050f2a75f74e3671e92) a
|
| 3352 | EOF
|
| 3353 | make_resolve_tree ours B A
|
| 3354 | )
|
| 3355 |
|
| 3356 | (cd tree-to-non-tree-with-rename
|
| 3357 | rm .git/index
|
| 3358 | # 'A' modifies a nested file 'a/sub/b', while 'B' replaces 'a/' with file 'a'.
|
| 3359 | # I let it pass as it's an edge-case to some extent.
|
| 3360 | git update-index --index-info <<EOF
|
| 3361 | 100644 blob $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) a/sub/b
|
| 3362 | EOF
|
| 3363 | make_resolve_tree ancestor A B
|
| 3364 | make_resolve_tree ancestor B A
|
| 3365 |
|
| 3366 | rm .git/index
|
| 3367 | # Thanks to the rename, this version keeps one additional file, 'a/e'
|
| 3368 | git update-index --index-info <<EOF
|
| 3369 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/sub/b
|
| 3370 | EOF
|
| 3371 | make_resolve_tree ours A B
|
| 3372 |
|
| 3373 | rm .git/index
|
| 3374 | # Now *ours* is the single file which replaces a tree.
|
| 3375 | git update-index --index-info <<EOF
|
| 3376 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a
|
| 3377 | EOF
|
| 3378 | make_resolve_tree ours B A
|
| 3379 | )
|
| 3380 |
|
| 3381 | (cd non-tree-to-tree-with-rename
|
| 3382 | # 'A' changes the single file 'a', while 'B' replaces it with a directory structure 'a'.
|
| 3383 | # The rename now sends this off-course, as it removes the previously 'protective' entry
|
| 3384 | # and thus makes all changes from 'B' succeed without us detecting any problem with that.
|
| 3385 | # Also, here we don't actually have irreconcilable tree-changes because of that.
|
| 3386 | rm .git/index
|
| 3387 | git update-index --index-info <<EOF
|
| 3388 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/d
|
| 3389 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/e
|
| 3390 | 100644 blob $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) a/sub/b
|
| 3391 | 100644 blob $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) a/sub/c
|
| 3392 | EOF
|
| 3393 | make_resolve_tree ancestor A B
|
| 3394 | make_resolve_tree ancestor B A
|
| 3395 |
|
| 3396 | # Thanks to the rename, this time there isn't even an irreconcilable conflict.
|
| 3397 | # This is deactivated as the test-suite can't handle this (one) special case.
|
| 3398 | # The state really is the one from the ancestors, as there are no irreconcilable
|
| 3399 | # tree changes, it's all the same. But the test expects to see changes when 'ours'
|
| 3400 | # is chosen so we can't easily run this here.
|
| 3401 | # make_resolve_tree ours A B
|
| 3402 | # make_resolve_tree ours B A
|
| 3403 | )
|
| 3404 |
|
| 3405 | (cd rename-within-rename
|
| 3406 | # 'A' and 'B' change all content in a mergable manner. 'A' renames 'a' to 'a-renamed',
|
| 3407 | # and 'B' renames 'a/sub' to 'a/sub-renamed'.
|
| 3408 | # Ideally, we get both together, but doing so added a lot of complexity so maybe give
|
| 3409 | # that another go and try to keep it simple.
|
| 3410 | # In ancestor mode, only those ancestors of conflicts are kept unchanged, so some renames
|
| 3411 | # go through.
|
| 3412 | rm .git/index
|
| 3413 | git update-index --index-info <<EOF
|
| 3414 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/w
|
| 3415 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/x.f
|
| 3416 | 100644 $(oid 44065282f89b9bd6439ed2e4674721383fd987eb) 0 a/sub/y.f
|
| 3417 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a/sub/z
|
| 3418 | EOF
|
| 3419 | make_resolve_tree ancestor A B
|
| 3420 | make_resolve_tree ancestor B A
|
| 3421 |
|
| 3422 | # *ours* is `a-renamed` everything, with merges.
|
| 3423 | rm .git/index
|
| 3424 | git update-index --index-info <<EOF
|
| 3425 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/sub/y.f
|
| 3426 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/sub/z
|
| 3427 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/w
|
| 3428 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/x.f
|
| 3429 | EOF
|
| 3430 | make_resolve_tree ours A B
|
| 3431 |
|
| 3432 | # Now ours is the renamed sub-directory, with merges. It can bring everything together even.
|
| 3433 | rm .git/index
|
| 3434 | git update-index --index-info <<EOF
|
| 3435 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/sub-renamed/y.f
|
| 3436 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/sub-renamed/z
|
| 3437 | 100644 $(oid e69de29bb2d1d6434b8b29ae775ad8c2e48c5391) 0 a-renamed/w
|
| 3438 | 100644 $(oid b414108e81e5091fe0974a1858b4d0d22b107f70) 0 a-renamed/x.f
|
| 3439 | EOF
|
| 3440 | make_resolve_tree ours B A
|
| 3441 | )
|