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