3 test_description
='compare & swap push force/delete safety'
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
8 TEST_PASSES_SANITIZE_LEAK
=true
11 setup_srcdst_basic
() {
13 git clone
--no-local . src
&&
14 git clone
--no-local src dst
&&
16 cd src
&& git checkout HEAD^
0
20 # For tests with "--force-if-includes".
21 setup_src_dup_dst
() {
23 git init
--bare dst
&&
24 git clone
--no-local dst src
&&
25 git clone
--no-local dst dup
36 git merge origin
/main
&&
37 git switch
-c branch main~
2 &&
46 git branch branch
--track origin
/branch
&&
47 git rebase origin
/main
60 test_expect_success setup
'
61 # create template repository
67 test_expect_success
'push to update (protected)' '
72 test_must_fail git push --force-with-lease=main:main origin main 2>err &&
75 git ls-remote . refs/heads/main >expect &&
76 git ls-remote src refs/heads/main >actual &&
77 test_cmp expect actual
80 test_expect_success
'push to update (protected, forced)' '
85 git push --force --force-with-lease=main:main origin main 2>err &&
86 grep "forced update" err
88 git ls-remote dst refs/heads/main >expect &&
89 git ls-remote src refs/heads/main >actual &&
90 test_cmp expect actual
93 test_expect_success
'push to update (protected, tracking)' '
101 git ls-remote src refs/heads/main >expect &&
105 git ls-remote . refs/remotes/origin/main >expect &&
106 test_must_fail git push --force-with-lease=main origin main &&
107 git ls-remote . refs/remotes/origin/main >actual &&
108 test_cmp expect actual
110 git ls-remote src refs/heads/main >actual &&
111 test_cmp expect actual
114 test_expect_success
'push to update (protected, tracking, forced)' '
115 setup_srcdst_basic &&
125 git ls-remote . refs/remotes/origin/main >expect &&
126 git push --force --force-with-lease=main origin main
128 git ls-remote dst refs/heads/main >expect &&
129 git ls-remote src refs/heads/main >actual &&
130 test_cmp expect actual
133 test_expect_success
'push to update (allowed)' '
134 setup_srcdst_basic &&
138 git push --force-with-lease=main:main^ origin main
140 git ls-remote dst refs/heads/main >expect &&
141 git ls-remote src refs/heads/main >actual &&
142 test_cmp expect actual
145 test_expect_success
'push to update (allowed, tracking)' '
146 setup_srcdst_basic &&
150 git push --force-with-lease=main origin main 2>err &&
151 ! grep "forced update" err
153 git ls-remote dst refs/heads/main >expect &&
154 git ls-remote src refs/heads/main >actual &&
155 test_cmp expect actual
158 test_expect_success
'push to update (allowed even though no-ff)' '
159 setup_srcdst_basic &&
162 git reset --hard HEAD^ &&
164 git push --force-with-lease=main origin main 2>err &&
165 grep "forced update" err
167 git ls-remote dst refs/heads/main >expect &&
168 git ls-remote src refs/heads/main >actual &&
169 test_cmp expect actual
172 test_expect_success
'push to delete (protected)' '
173 setup_srcdst_basic &&
174 git ls-remote src refs/heads/main >expect &&
177 test_must_fail git push --force-with-lease=main:main^ origin :main
179 git ls-remote src refs/heads/main >actual &&
180 test_cmp expect actual
183 test_expect_success
'push to delete (protected, forced)' '
184 setup_srcdst_basic &&
187 git push --force --force-with-lease=main:main^ origin :main
189 git ls-remote src refs/heads/main >actual &&
190 test_must_be_empty actual
193 test_expect_success
'push to delete (allowed)' '
194 setup_srcdst_basic &&
197 git push --force-with-lease=main origin :main 2>err &&
200 git ls-remote src refs/heads/main >actual &&
201 test_must_be_empty actual
204 test_expect_success
'cover everything with default force-with-lease (protected)' '
205 setup_srcdst_basic &&
208 git branch nain main^
210 git ls-remote src refs/heads/\* >expect &&
213 test_must_fail git push --force-with-lease origin main main:nain
215 git ls-remote src refs/heads/\* >actual &&
216 test_cmp expect actual
219 test_expect_success
'cover everything with default force-with-lease (allowed)' '
220 setup_srcdst_basic &&
223 git branch nain main^
228 git push --force-with-lease origin main main:nain
230 git ls-remote dst refs/heads/main |
231 sed -e "s/main/nain/" >expect &&
232 git ls-remote src refs/heads/nain >actual &&
233 test_cmp expect actual
236 test_expect_success
'new branch covered by force-with-lease' '
237 setup_srcdst_basic &&
240 git branch branch main &&
241 git push --force-with-lease=branch origin branch
243 git ls-remote dst refs/heads/branch >expect &&
244 git ls-remote src refs/heads/branch >actual &&
245 test_cmp expect actual
248 test_expect_success
'new branch covered by force-with-lease (explicit)' '
249 setup_srcdst_basic &&
252 git branch branch main &&
253 git push --force-with-lease=branch: origin branch
255 git ls-remote dst refs/heads/branch >expect &&
256 git ls-remote src refs/heads/branch >actual &&
257 test_cmp expect actual
260 test_expect_success
'new branch already exists' '
261 setup_srcdst_basic &&
264 git checkout -b branch main &&
269 git branch branch main &&
270 test_must_fail git push --force-with-lease=branch: origin branch
274 test_expect_success
'background updates of REMOTE can be mitigated with a non-updated REMOTE-push' '
276 git init --bare src.bare &&
277 test_when_finished "rm -rf src.bare" &&
278 git clone --no-local src.bare dst &&
279 test_when_finished "rm -rf dst" &&
283 git remote add origin-push ../src.bare &&
284 git push origin-push main:main
286 git clone --no-local src.bare dst2 &&
287 test_when_finished "rm -rf dst2" &&
297 test_must_fail git push --force-with-lease origin-push &&
298 git fetch origin-push &&
299 git push --force-with-lease origin-push
303 test_expect_success
'background updates to remote can be mitigated with "--force-if-includes"' '
305 test_when_finished "rm -fr dst src dup" &&
306 git ls-remote dst refs/heads/main >expect.main &&
307 git ls-remote dst refs/heads/branch >expect.branch &&
315 test_must_fail git push --force-with-lease --force-if-includes --all
317 git ls-remote dst refs/heads/main >actual.main &&
318 git ls-remote dst refs/heads/branch >actual.branch &&
319 test_cmp expect.main actual.main &&
320 test_cmp expect.branch actual.branch
323 test_expect_success
'background updates to remote can be mitigated with "push.useForceIfIncludes"' '
325 test_when_finished "rm -fr dst src dup" &&
326 git ls-remote dst refs/heads/main >expect.main &&
334 git config --local push.useForceIfIncludes true &&
335 test_must_fail git push --force-with-lease=main origin main
337 git ls-remote dst refs/heads/main >actual.main &&
338 test_cmp expect.main actual.main
341 test_expect_success
'"--force-if-includes" should be disabled for --force-with-lease="<refname>:<expect>"' '
343 test_when_finished "rm -fr dst src dup" &&
344 git ls-remote dst refs/heads/main >expect.main &&
351 remote_head="$(git rev-parse refs/remotes/origin/main)" &&
353 test_must_fail git push --force-if-includes --force-with-lease="main:$remote_head" 2>err &&
354 grep "stale info" err
356 git ls-remote dst refs/heads/main >actual.main &&
357 test_cmp expect.main actual.main
360 test_expect_success
'"--force-if-includes" should allow forced update after a rebase ("pull --rebase")' '
362 test_when_finished "rm -fr dst src dup" &&
369 git pull --rebase origin main &&
370 git push --force-if-includes --force-with-lease="main"
374 test_expect_success
'"--force-if-includes" should allow forced update after a rebase ("pull --rebase", local rebase)' '
376 test_when_finished "rm -fr dst src dup" &&
383 git pull --rebase origin main &&
384 git rebase --onto HEAD~4 HEAD~1 &&
385 git push --force-if-includes --force-with-lease="main"
389 test_expect_success
'"--force-if-includes" should allow deletes' '
391 test_when_finished "rm -fr dst src dup" &&
395 git pull --rebase origin branch &&
396 git push --force-if-includes --force-with-lease="branch" origin :branch