summaryrefslogtreecommitdiffstats
path: root/t/t5533-push-cas.sh
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xt/t5533-push-cas.sh399
1 files changed, 399 insertions, 0 deletions
diff --git a/t/t5533-push-cas.sh b/t/t5533-push-cas.sh
new file mode 100755
index 0000000..cba26a8
--- /dev/null
+++ b/t/t5533-push-cas.sh
@@ -0,0 +1,399 @@
+#!/bin/sh
+
+test_description='compare & swap push force/delete safety'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+. ./test-lib.sh
+
+setup_srcdst_basic () {
+ rm -fr src dst &&
+ git clone --no-local . src &&
+ git clone --no-local src dst &&
+ (
+ cd src && git checkout HEAD^0
+ )
+}
+
+# For tests with "--force-if-includes".
+setup_src_dup_dst () {
+ rm -fr src dup dst &&
+ git init --bare dst &&
+ git clone --no-local dst src &&
+ git clone --no-local dst dup
+ (
+ cd src &&
+ test_commit A &&
+ test_commit B &&
+ test_commit C &&
+ git push origin
+ ) &&
+ (
+ cd dup &&
+ git fetch &&
+ git merge origin/main &&
+ git switch -c branch main~2 &&
+ test_commit D &&
+ test_commit E &&
+ git push origin --all
+ ) &&
+ (
+ cd src &&
+ git switch main &&
+ git fetch --all &&
+ git branch branch --track origin/branch &&
+ git rebase origin/main
+ ) &&
+ (
+ cd dup &&
+ git switch main &&
+ test_commit F &&
+ test_commit G &&
+ git switch branch &&
+ test_commit H &&
+ git push origin --all
+ )
+}
+
+test_expect_success setup '
+ # create template repository
+ test_commit A &&
+ test_commit B &&
+ test_commit C
+'
+
+test_expect_success 'push to update (protected)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ test_must_fail git push --force-with-lease=main:main origin main 2>err &&
+ grep "stale info" err
+ ) &&
+ git ls-remote . refs/heads/main >expect &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force --force-with-lease=main:main origin main 2>err &&
+ grep "forced update" err
+ ) &&
+ git ls-remote dst refs/heads/main >expect &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, tracking)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git checkout main &&
+ test_commit D &&
+ git checkout HEAD^0
+ ) &&
+ git ls-remote src refs/heads/main >expect &&
+ (
+ cd dst &&
+ test_commit E &&
+ git ls-remote . refs/remotes/origin/main >expect &&
+ test_must_fail git push --force-with-lease=main origin main &&
+ git ls-remote . refs/remotes/origin/main >actual &&
+ test_cmp expect actual
+ ) &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (protected, tracking, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git checkout main &&
+ test_commit D &&
+ git checkout HEAD^0
+ ) &&
+ (
+ cd dst &&
+ test_commit E &&
+ git ls-remote . refs/remotes/origin/main >expect &&
+ git push --force --force-with-lease=main origin main
+ ) &&
+ git ls-remote dst refs/heads/main >expect &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force-with-lease=main:main^ origin main
+ ) &&
+ git ls-remote dst refs/heads/main >expect &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed, tracking)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ test_commit D &&
+ git push --force-with-lease=main origin main 2>err &&
+ ! grep "forced update" err
+ ) &&
+ git ls-remote dst refs/heads/main >expect &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to update (allowed even though no-ff)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git reset --hard HEAD^ &&
+ test_commit D &&
+ git push --force-with-lease=main origin main 2>err &&
+ grep "forced update" err
+ ) &&
+ git ls-remote dst refs/heads/main >expect &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (protected)' '
+ setup_srcdst_basic &&
+ git ls-remote src refs/heads/main >expect &&
+ (
+ cd dst &&
+ test_must_fail git push --force-with-lease=main:main^ origin :main
+ ) &&
+ git ls-remote src refs/heads/main >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'push to delete (protected, forced)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git push --force --force-with-lease=main:main^ origin :main
+ ) &&
+ git ls-remote src refs/heads/main >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'push to delete (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git push --force-with-lease=main origin :main 2>err &&
+ grep deleted err
+ ) &&
+ git ls-remote src refs/heads/main >actual &&
+ test_must_be_empty actual
+'
+
+test_expect_success 'cover everything with default force-with-lease (protected)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git branch nain main^
+ ) &&
+ git ls-remote src refs/heads/\* >expect &&
+ (
+ cd dst &&
+ test_must_fail git push --force-with-lease origin main main:nain
+ ) &&
+ git ls-remote src refs/heads/\* >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'cover everything with default force-with-lease (allowed)' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git branch nain main^
+ ) &&
+ (
+ cd dst &&
+ git fetch &&
+ git push --force-with-lease origin main main:nain
+ ) &&
+ git ls-remote dst refs/heads/main |
+ sed -e "s/main/nain/" >expect &&
+ git ls-remote src refs/heads/nain >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'new branch covered by force-with-lease' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git branch branch main &&
+ git push --force-with-lease=branch origin branch
+ ) &&
+ git ls-remote dst refs/heads/branch >expect &&
+ git ls-remote src refs/heads/branch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'new branch covered by force-with-lease (explicit)' '
+ setup_srcdst_basic &&
+ (
+ cd dst &&
+ git branch branch main &&
+ git push --force-with-lease=branch: origin branch
+ ) &&
+ git ls-remote dst refs/heads/branch >expect &&
+ git ls-remote src refs/heads/branch >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'new branch already exists' '
+ setup_srcdst_basic &&
+ (
+ cd src &&
+ git checkout -b branch main &&
+ test_commit F
+ ) &&
+ (
+ cd dst &&
+ git branch branch main &&
+ test_must_fail git push --force-with-lease=branch: origin branch
+ )
+'
+
+test_expect_success 'background updates of REMOTE can be mitigated with a non-updated REMOTE-push' '
+ rm -rf src dst &&
+ git init --bare src.bare &&
+ test_when_finished "rm -rf src.bare" &&
+ git clone --no-local src.bare dst &&
+ test_when_finished "rm -rf dst" &&
+ (
+ cd dst &&
+ test_commit G &&
+ git remote add origin-push ../src.bare &&
+ git push origin-push main:main
+ ) &&
+ git clone --no-local src.bare dst2 &&
+ test_when_finished "rm -rf dst2" &&
+ (
+ cd dst2 &&
+ test_commit H &&
+ git push
+ ) &&
+ (
+ cd dst &&
+ test_commit I &&
+ git fetch origin &&
+ test_must_fail git push --force-with-lease origin-push &&
+ git fetch origin-push &&
+ git push --force-with-lease origin-push
+ )
+'
+
+test_expect_success 'background updates to remote can be mitigated with "--force-if-includes"' '
+ setup_src_dup_dst &&
+ test_when_finished "rm -fr dst src dup" &&
+ git ls-remote dst refs/heads/main >expect.main &&
+ git ls-remote dst refs/heads/branch >expect.branch &&
+ (
+ cd src &&
+ git switch branch &&
+ test_commit I &&
+ git switch main &&
+ test_commit J &&
+ git fetch --all &&
+ test_must_fail git push --force-with-lease --force-if-includes --all
+ ) &&
+ git ls-remote dst refs/heads/main >actual.main &&
+ git ls-remote dst refs/heads/branch >actual.branch &&
+ test_cmp expect.main actual.main &&
+ test_cmp expect.branch actual.branch
+'
+
+test_expect_success 'background updates to remote can be mitigated with "push.useForceIfIncludes"' '
+ setup_src_dup_dst &&
+ test_when_finished "rm -fr dst src dup" &&
+ git ls-remote dst refs/heads/main >expect.main &&
+ (
+ cd src &&
+ git switch branch &&
+ test_commit I &&
+ git switch main &&
+ test_commit J &&
+ git fetch --all &&
+ git config --local push.useForceIfIncludes true &&
+ test_must_fail git push --force-with-lease=main origin main
+ ) &&
+ git ls-remote dst refs/heads/main >actual.main &&
+ test_cmp expect.main actual.main
+'
+
+test_expect_success '"--force-if-includes" should be disabled for --force-with-lease="<refname>:<expect>"' '
+ setup_src_dup_dst &&
+ test_when_finished "rm -fr dst src dup" &&
+ git ls-remote dst refs/heads/main >expect.main &&
+ (
+ cd src &&
+ git switch branch &&
+ test_commit I &&
+ git switch main &&
+ test_commit J &&
+ remote_head="$(git rev-parse refs/remotes/origin/main)" &&
+ git fetch --all &&
+ test_must_fail git push --force-if-includes --force-with-lease="main:$remote_head" 2>err &&
+ grep "stale info" err
+ ) &&
+ git ls-remote dst refs/heads/main >actual.main &&
+ test_cmp expect.main actual.main
+'
+
+test_expect_success '"--force-if-includes" should allow forced update after a rebase ("pull --rebase")' '
+ setup_src_dup_dst &&
+ test_when_finished "rm -fr dst src dup" &&
+ (
+ cd src &&
+ git switch branch &&
+ test_commit I &&
+ git switch main &&
+ test_commit J &&
+ git pull --rebase origin main &&
+ git push --force-if-includes --force-with-lease="main"
+ )
+'
+
+test_expect_success '"--force-if-includes" should allow forced update after a rebase ("pull --rebase", local rebase)' '
+ setup_src_dup_dst &&
+ test_when_finished "rm -fr dst src dup" &&
+ (
+ cd src &&
+ git switch branch &&
+ test_commit I &&
+ git switch main &&
+ test_commit J &&
+ git pull --rebase origin main &&
+ git rebase --onto HEAD~4 HEAD~1 &&
+ git push --force-if-includes --force-with-lease="main"
+ )
+'
+
+test_expect_success '"--force-if-includes" should allow deletes' '
+ setup_src_dup_dst &&
+ test_when_finished "rm -fr dst src dup" &&
+ (
+ cd src &&
+ git switch branch &&
+ git pull --rebase origin branch &&
+ git push --force-if-includes --force-with-lease="branch" origin :branch
+ )
+'
+
+test_done