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