1#!/bin/sh 2 3test_description='compare & swap push force/delete safety' 4 5GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main 6export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME 7 8. ./test-lib.sh 9 10setup_srcdst_basic () { 11 rm -fr src dst && 12 git clone --no-local . src && 13 git clone --no-local src dst && 14 ( 15 cd src && git checkout HEAD^0 16 ) 17} 18 19# For tests with "--force-if-includes". 20setup_src_dup_dst () { 21 rm -fr src dup dst && 22 git init --bare dst && 23 git clone --no-local dst src && 24 git clone --no-local dst dup 25 ( 26 cd src && 27 test_commit A && 28 test_commit B && 29 test_commit C && 30 git push origin 31 ) && 32 ( 33 cd dup && 34 git fetch && 35 git merge origin/main && 36 git switch -c branch main~2 && 37 test_commit D && 38 test_commit E && 39 git push origin --all 40 ) && 41 ( 42 cd src && 43 git switch main && 44 git fetch --all && 45 git branch branch --track origin/branch && 46 git rebase origin/main 47 ) && 48 ( 49 cd dup && 50 git switch main && 51 test_commit F && 52 test_commit G && 53 git switch branch && 54 test_commit H && 55 git push origin --all 56 ) 57} 58 59test_expect_success setup ' 60 # create template repository 61 test_commit A && 62 test_commit B && 63 test_commit C 64' 65 66test_expect_success 'push to update (protected)' ' 67 setup_srcdst_basic && 68 ( 69 cd dst && 70 test_commit D && 71 test_must_fail git push --force-with-lease=main:main origin main 2>err && 72 grep "stale info" err 73 ) && 74 git ls-remote . refs/heads/main >expect && 75 git ls-remote src refs/heads/main >actual && 76 test_cmp expect actual 77' 78 79test_expect_success 'push to update (protected, forced)' ' 80 setup_srcdst_basic && 81 ( 82 cd dst && 83 test_commit D && 84 git push --force --force-with-lease=main:main origin main 2>err && 85 grep "forced update" err 86 ) && 87 git ls-remote dst refs/heads/main >expect && 88 git ls-remote src refs/heads/main >actual && 89 test_cmp expect actual 90' 91 92test_expect_success 'push to update (protected, tracking)' ' 93 setup_srcdst_basic && 94 ( 95 cd src && 96 git checkout main && 97 test_commit D && 98 git checkout HEAD^0 99 ) && 100 git ls-remote src refs/heads/main >expect && 101 ( 102 cd dst && 103 test_commit E && 104 git ls-remote . refs/remotes/origin/main >expect && 105 test_must_fail git push --force-with-lease=main origin main && 106 git ls-remote . refs/remotes/origin/main >actual && 107 test_cmp expect actual 108 ) && 109 git ls-remote src refs/heads/main >actual && 110 test_cmp expect actual 111' 112 113test_expect_success 'push to update (protected, tracking, forced)' ' 114 setup_srcdst_basic && 115 ( 116 cd src && 117 git checkout main && 118 test_commit D && 119 git checkout HEAD^0 120 ) && 121 ( 122 cd dst && 123 test_commit E && 124 git ls-remote . refs/remotes/origin/main >expect && 125 git push --force --force-with-lease=main origin main 126 ) && 127 git ls-remote dst refs/heads/main >expect && 128 git ls-remote src refs/heads/main >actual && 129 test_cmp expect actual 130' 131 132test_expect_success 'push to update (allowed)' ' 133 setup_srcdst_basic && 134 ( 135 cd dst && 136 test_commit D && 137 git push --force-with-lease=main:main^ origin main 138 ) && 139 git ls-remote dst refs/heads/main >expect && 140 git ls-remote src refs/heads/main >actual && 141 test_cmp expect actual 142' 143 144test_expect_success 'push to update (allowed, tracking)' ' 145 setup_srcdst_basic && 146 ( 147 cd dst && 148 test_commit D && 149 git push --force-with-lease=main origin main 2>err && 150 ! grep "forced update" err 151 ) && 152 git ls-remote dst refs/heads/main >expect && 153 git ls-remote src refs/heads/main >actual && 154 test_cmp expect actual 155' 156 157test_expect_success 'push to update (allowed even though no-ff)' ' 158 setup_srcdst_basic && 159 ( 160 cd dst && 161 git reset --hard HEAD^ && 162 test_commit D && 163 git push --force-with-lease=main origin main 2>err && 164 grep "forced update" err 165 ) && 166 git ls-remote dst refs/heads/main >expect && 167 git ls-remote src refs/heads/main >actual && 168 test_cmp expect actual 169' 170 171test_expect_success 'push to delete (protected)' ' 172 setup_srcdst_basic && 173 git ls-remote src refs/heads/main >expect && 174 ( 175 cd dst && 176 test_must_fail git push --force-with-lease=main:main^ origin :main 177 ) && 178 git ls-remote src refs/heads/main >actual && 179 test_cmp expect actual 180' 181 182test_expect_success 'push to delete (protected, forced)' ' 183 setup_srcdst_basic && 184 ( 185 cd dst && 186 git push --force --force-with-lease=main:main^ origin :main 187 ) && 188 git ls-remote src refs/heads/main >actual && 189 test_must_be_empty actual 190' 191 192test_expect_success 'push to delete (allowed)' ' 193 setup_srcdst_basic && 194 ( 195 cd dst && 196 git push --force-with-lease=main origin :main 2>err && 197 grep deleted err 198 ) && 199 git ls-remote src refs/heads/main >actual && 200 test_must_be_empty actual 201' 202 203test_expect_success 'cover everything with default force-with-lease (protected)' ' 204 setup_srcdst_basic && 205 ( 206 cd src && 207 git branch nain main^ 208 ) && 209 git ls-remote src refs/heads/\* >expect && 210 ( 211 cd dst && 212 test_must_fail git push --force-with-lease origin main main:nain 213 ) && 214 git ls-remote src refs/heads/\* >actual && 215 test_cmp expect actual 216' 217 218test_expect_success 'cover everything with default force-with-lease (allowed)' ' 219 setup_srcdst_basic && 220 ( 221 cd src && 222 git branch nain main^ 223 ) && 224 ( 225 cd dst && 226 git fetch && 227 git push --force-with-lease origin main main:nain 228 ) && 229 git ls-remote dst refs/heads/main | 230 sed -e "s/main/nain/" >expect && 231 git ls-remote src refs/heads/nain >actual && 232 test_cmp expect actual 233' 234 235test_expect_success 'new branch covered by force-with-lease' ' 236 setup_srcdst_basic && 237 ( 238 cd dst && 239 git branch branch main && 240 git push --force-with-lease=branch origin branch 241 ) && 242 git ls-remote dst refs/heads/branch >expect && 243 git ls-remote src refs/heads/branch >actual && 244 test_cmp expect actual 245' 246 247test_expect_success 'new branch covered by force-with-lease (explicit)' ' 248 setup_srcdst_basic && 249 ( 250 cd dst && 251 git branch branch main && 252 git push --force-with-lease=branch: origin branch 253 ) && 254 git ls-remote dst refs/heads/branch >expect && 255 git ls-remote src refs/heads/branch >actual && 256 test_cmp expect actual 257' 258 259test_expect_success 'new branch already exists' ' 260 setup_srcdst_basic && 261 ( 262 cd src && 263 git checkout -b branch main && 264 test_commit F 265 ) && 266 ( 267 cd dst && 268 git branch branch main && 269 test_must_fail git push --force-with-lease=branch: origin branch 270 ) 271' 272 273test_expect_success 'background updates of REMOTE can be mitigated with a non-updated REMOTE-push' ' 274 rm -rf src dst && 275 git init --bare src.bare && 276 test_when_finished "rm -rf src.bare" && 277 git clone --no-local src.bare dst && 278 test_when_finished "rm -rf dst" && 279 ( 280 cd dst && 281 test_commit G && 282 git remote add origin-push ../src.bare && 283 git push origin-push main:main 284 ) && 285 git clone --no-local src.bare dst2 && 286 test_when_finished "rm -rf dst2" && 287 ( 288 cd dst2 && 289 test_commit H && 290 git push 291 ) && 292 ( 293 cd dst && 294 test_commit I && 295 git fetch origin && 296 test_must_fail git push --force-with-lease origin-push && 297 git fetch origin-push && 298 git push --force-with-lease origin-push 299 ) 300' 301 302test_expect_success 'background updates to remote can be mitigated with "--force-if-includes"' ' 303 setup_src_dup_dst && 304 test_when_finished "rm -fr dst src dup" && 305 git ls-remote dst refs/heads/main >expect.main && 306 git ls-remote dst refs/heads/branch >expect.branch && 307 ( 308 cd src && 309 git switch branch && 310 test_commit I && 311 git switch main && 312 test_commit J && 313 git fetch --all && 314 test_must_fail git push --force-with-lease --force-if-includes --all 315 ) && 316 git ls-remote dst refs/heads/main >actual.main && 317 git ls-remote dst refs/heads/branch >actual.branch && 318 test_cmp expect.main actual.main && 319 test_cmp expect.branch actual.branch 320' 321 322test_expect_success 'background updates to remote can be mitigated with "push.useForceIfIncludes"' ' 323 setup_src_dup_dst && 324 test_when_finished "rm -fr dst src dup" && 325 git ls-remote dst refs/heads/main >expect.main && 326 ( 327 cd src && 328 git switch branch && 329 test_commit I && 330 git switch main && 331 test_commit J && 332 git fetch --all && 333 git config --local push.useForceIfIncludes true && 334 test_must_fail git push --force-with-lease=main origin main 335 ) && 336 git ls-remote dst refs/heads/main >actual.main && 337 test_cmp expect.main actual.main 338' 339 340test_expect_success '"--force-if-includes" should be disabled for --force-with-lease="<refname>:<expect>"' ' 341 setup_src_dup_dst && 342 test_when_finished "rm -fr dst src dup" && 343 git ls-remote dst refs/heads/main >expect.main && 344 ( 345 cd src && 346 git switch branch && 347 test_commit I && 348 git switch main && 349 test_commit J && 350 remote_head="$(git rev-parse refs/remotes/origin/main)" && 351 git fetch --all && 352 test_must_fail git push --force-if-includes --force-with-lease="main:$remote_head" 2>err && 353 grep "stale info" err 354 ) && 355 git ls-remote dst refs/heads/main >actual.main && 356 test_cmp expect.main actual.main 357' 358 359test_expect_success '"--force-if-includes" should allow forced update after a rebase ("pull --rebase")' ' 360 setup_src_dup_dst && 361 test_when_finished "rm -fr dst src dup" && 362 ( 363 cd src && 364 git switch branch && 365 test_commit I && 366 git switch main && 367 test_commit J && 368 git pull --rebase origin main && 369 git push --force-if-includes --force-with-lease="main" 370 ) 371' 372 373test_expect_success '"--force-if-includes" should allow forced update after a rebase ("pull --rebase", local rebase)' ' 374 setup_src_dup_dst && 375 test_when_finished "rm -fr dst src dup" && 376 ( 377 cd src && 378 git switch branch && 379 test_commit I && 380 git switch main && 381 test_commit J && 382 git pull --rebase origin main && 383 git rebase --onto HEAD~4 HEAD~1 && 384 git push --force-if-includes --force-with-lease="main" 385 ) 386' 387 388test_expect_success '"--force-if-includes" should allow deletes' ' 389 setup_src_dup_dst && 390 test_when_finished "rm -fr dst src dup" && 391 ( 392 cd src && 393 git switch branch && 394 git pull --rebase origin branch && 395 git push --force-if-includes --force-with-lease="branch" origin :branch 396 ) 397' 398 399test_done 400