Merge branch 'ds/trace2-topo-walk'
[git] / t / t5400-send-pack.sh
1 #!/bin/sh
2 #
3 # Copyright (c) 2005 Junio C Hamano
4 #
5
6 test_description='See why rewinding head breaks send-pack
7
8 '
9 . ./test-lib.sh
10
11 cnt=64
12 test_expect_success setup '
13         test_tick &&
14         mkdir mozart mozart/is &&
15         echo "Commit #0" >mozart/is/pink &&
16         git update-index --add mozart/is/pink &&
17         tree=$(git write-tree) &&
18         commit=$(echo "Commit #0" | git commit-tree $tree) &&
19         zero=$commit &&
20         parent=$zero &&
21         i=0 &&
22         while test $i -le $cnt
23         do
24                 i=$(($i+1)) &&
25                 test_tick &&
26                 echo "Commit #$i" >mozart/is/pink &&
27                 git update-index --add mozart/is/pink &&
28                 tree=$(git write-tree) &&
29                 commit=$(echo "Commit #$i" |
30                          git commit-tree $tree -p $parent) &&
31                 git update-ref refs/tags/commit$i $commit &&
32                 parent=$commit || return 1
33         done &&
34         git update-ref HEAD "$commit" &&
35         git clone ./. victim &&
36         ( cd victim && git config receive.denyCurrentBranch warn && git log ) &&
37         git update-ref HEAD "$zero" &&
38         parent=$zero &&
39         i=0 &&
40         while test $i -le $cnt
41         do
42                 i=$(($i+1)) &&
43                 test_tick &&
44                 echo "Rebase #$i" >mozart/is/pink &&
45                 git update-index --add mozart/is/pink &&
46                 tree=$(git write-tree) &&
47                 commit=$(echo "Rebase #$i" | git commit-tree $tree -p $parent) &&
48                 git update-ref refs/tags/rebase$i $commit &&
49                 parent=$commit || return 1
50         done &&
51         git update-ref HEAD "$commit" &&
52         echo Rebase &&
53         git log'
54
55 test_expect_success 'pack the source repository' '
56         git repack -a -d &&
57         git prune
58 '
59
60 test_expect_success 'pack the destination repository' '
61         (
62                 cd victim &&
63                 git repack -a -d &&
64                 git prune
65         )
66 '
67
68 test_expect_success 'refuse pushing rewound head without --force' '
69         pushed_head=$(git rev-parse --verify master) &&
70         victim_orig=$(cd victim && git rev-parse --verify master) &&
71         test_must_fail git send-pack ./victim master &&
72         victim_head=$(cd victim && git rev-parse --verify master) &&
73         test "$victim_head" = "$victim_orig" &&
74         # this should update
75         git send-pack --force ./victim master &&
76         victim_head=$(cd victim && git rev-parse --verify master) &&
77         test "$victim_head" = "$pushed_head"
78 '
79
80 test_expect_success 'push can be used to delete a ref' '
81         ( cd victim && git branch extra master ) &&
82         git send-pack ./victim :extra master &&
83         ( cd victim &&
84           test_must_fail git rev-parse --verify extra )
85 '
86
87 test_expect_success 'refuse deleting push with denyDeletes' '
88         (
89                 cd victim &&
90                 test_might_fail git branch -D extra &&
91                 git config receive.denyDeletes true &&
92                 git branch extra master
93         ) &&
94         test_must_fail git send-pack ./victim :extra master
95 '
96
97 test_expect_success 'cannot override denyDeletes with git -c send-pack' '
98         (
99                 cd victim &&
100                 test_might_fail git branch -D extra &&
101                 git config receive.denyDeletes true &&
102                 git branch extra master
103         ) &&
104         test_must_fail git -c receive.denyDeletes=false \
105                                         send-pack ./victim :extra master
106 '
107
108 test_expect_success 'override denyDeletes with git -c receive-pack' '
109         (
110                 cd victim &&
111                 test_might_fail git branch -D extra &&
112                 git config receive.denyDeletes true &&
113                 git branch extra master
114         ) &&
115         git send-pack \
116                 --receive-pack="git -c receive.denyDeletes=false receive-pack" \
117                 ./victim :extra master
118 '
119
120 test_expect_success 'denyNonFastforwards trumps --force' '
121         (
122                 cd victim &&
123                 test_might_fail git branch -D extra &&
124                 git config receive.denyNonFastforwards true
125         ) &&
126         victim_orig=$(cd victim && git rev-parse --verify master) &&
127         test_must_fail git send-pack --force ./victim master^:master &&
128         victim_head=$(cd victim && git rev-parse --verify master) &&
129         test "$victim_orig" = "$victim_head"
130 '
131
132 test_expect_success 'send-pack --all sends all branches' '
133         # make sure we have at least 2 branches with different
134         # values, just to be thorough
135         git branch other-branch HEAD^ &&
136
137         git init --bare all.git &&
138         git send-pack --all all.git &&
139         git for-each-ref refs/heads >expect &&
140         git -C all.git for-each-ref refs/heads >actual &&
141         test_cmp expect actual
142 '
143
144 test_expect_success 'push --all excludes remote-tracking hierarchy' '
145         mkdir parent &&
146         (
147                 cd parent &&
148                 git init && : >file && git add file && git commit -m add
149         ) &&
150         git clone parent child &&
151         (
152                 cd child && git push --all
153         ) &&
154         (
155                 cd parent &&
156                 test -z "$(git for-each-ref refs/remotes/origin)"
157         )
158 '
159
160 test_expect_success 'receive-pack runs auto-gc in remote repo' '
161         rm -rf parent child &&
162         git init parent &&
163         (
164                 # Setup a repo with 2 packs
165                 cd parent &&
166                 echo "Some text" >file.txt &&
167                 git add . &&
168                 git commit -m "Initial commit" &&
169                 git repack -adl &&
170                 echo "Some more text" >>file.txt &&
171                 git commit -a -m "Second commit" &&
172                 git repack
173         ) &&
174         cp -R parent child &&
175         (
176                 # Set the child to auto-pack if more than one pack exists
177                 cd child &&
178                 git config gc.autopacklimit 1 &&
179                 git config gc.autodetach false &&
180                 git branch test_auto_gc &&
181                 # And create a file that follows the temporary object naming
182                 # convention for the auto-gc to remove
183                 : >.git/objects/tmp_test_object &&
184                 test-tool chmtime =-1209601 .git/objects/tmp_test_object
185         ) &&
186         (
187                 cd parent &&
188                 echo "Even more text" >>file.txt &&
189                 git commit -a -m "Third commit" &&
190                 git send-pack ../child HEAD:refs/heads/test_auto_gc
191         ) &&
192         test ! -e child/.git/objects/tmp_test_object
193 '
194
195 rewound_push_setup() {
196         rm -rf parent child &&
197         mkdir parent &&
198         (
199                 cd parent &&
200                 git init &&
201                 echo one >file && git add file && git commit -m one &&
202                 git config receive.denyCurrentBranch warn &&
203                 echo two >file && git commit -a -m two
204         ) &&
205         git clone parent child &&
206         (
207                 cd child && git reset --hard HEAD^
208         )
209 }
210
211 test_expect_success 'pushing explicit refspecs respects forcing' '
212         rewound_push_setup &&
213         parent_orig=$(cd parent && git rev-parse --verify master) &&
214         (
215                 cd child &&
216                 test_must_fail git send-pack ../parent \
217                         refs/heads/master:refs/heads/master
218         ) &&
219         parent_head=$(cd parent && git rev-parse --verify master) &&
220         test "$parent_orig" = "$parent_head" &&
221         (
222                 cd child &&
223                 git send-pack ../parent \
224                         +refs/heads/master:refs/heads/master
225         ) &&
226         parent_head=$(cd parent && git rev-parse --verify master) &&
227         child_head=$(cd child && git rev-parse --verify master) &&
228         test "$parent_head" = "$child_head"
229 '
230
231 test_expect_success 'pushing wildcard refspecs respects forcing' '
232         rewound_push_setup &&
233         parent_orig=$(cd parent && git rev-parse --verify master) &&
234         (
235                 cd child &&
236                 test_must_fail git send-pack ../parent \
237                         "refs/heads/*:refs/heads/*"
238         ) &&
239         parent_head=$(cd parent && git rev-parse --verify master) &&
240         test "$parent_orig" = "$parent_head" &&
241         (
242                 cd child &&
243                 git send-pack ../parent \
244                         "+refs/heads/*:refs/heads/*"
245         ) &&
246         parent_head=$(cd parent && git rev-parse --verify master) &&
247         child_head=$(cd child && git rev-parse --verify master) &&
248         test "$parent_head" = "$child_head"
249 '
250
251 test_expect_success 'deny pushing to delete current branch' '
252         rewound_push_setup &&
253         (
254                 cd child &&
255                 test_must_fail git send-pack ../parent :refs/heads/master 2>errs
256         )
257 '
258
259 extract_ref_advertisement () {
260         perl -lne '
261                 # \\ is there to skip capabilities after \0
262                 /push< ([^\\]+)/ or next;
263                 exit 0 if $1 eq "0000";
264                 print $1;
265         '
266 }
267
268 test_expect_success 'receive-pack de-dupes .have lines' '
269         git init shared &&
270         git -C shared commit --allow-empty -m both &&
271         git clone -s shared fork &&
272         (
273                 cd shared &&
274                 git checkout -b only-shared &&
275                 git commit --allow-empty -m only-shared &&
276                 git update-ref refs/heads/foo HEAD
277         ) &&
278
279         # Notable things in this expectation:
280         #  - local refs are not de-duped
281         #  - .have does not duplicate locals
282         #  - .have does not duplicate itself
283         local=$(git -C fork rev-parse HEAD) &&
284         shared=$(git -C shared rev-parse only-shared) &&
285         cat >expect <<-EOF &&
286         $local refs/heads/master
287         $local refs/remotes/origin/HEAD
288         $local refs/remotes/origin/master
289         $shared .have
290         EOF
291
292         GIT_TRACE_PACKET=$(pwd)/trace GIT_TEST_PROTOCOL_VERSION=0 \
293         git push \
294                 --receive-pack="unset GIT_TRACE_PACKET; git-receive-pack" \
295                 fork HEAD:foo &&
296         extract_ref_advertisement <trace >refs &&
297         test_cmp expect refs
298 '
299
300 test_done