Git fork

Merge branch 'ps/send-pack-unhide-error-in-atomic-push'

"git push --atomic --porcelain" used to ignore failures from the
other side, losing the error status from the child process, which
has been corrected.

* ps/send-pack-unhide-error-in-atomic-push:
send-pack: gracefully close the connection for atomic push
t5543: atomic push reports exit code failure
send-pack: new return code "ERROR_SEND_PACK_BAD_REF_STATUS"
t5548: add porcelain push test cases for dry-run mode
t5548: add new porcelain test cases
t5548: refactor test cases by resetting upstream
t5548: refactor to reuse setup_upstream() function
t5504: modernize test by moving heredocs into test bodies

+406 -142
+3 -7
send-pack.c
··· 632 632 reject_atomic_push(remote_refs, args->send_mirror); 633 633 error("atomic push failed for ref %s. status: %d", 634 634 ref->name, ref->status); 635 - ret = args->porcelain ? 0 : -1; 635 + ret = ERROR_SEND_PACK_BAD_REF_STATUS; 636 + packet_flush(out); 636 637 goto out; 637 638 } 638 639 /* else fallthrough */ ··· 763 764 if (ret < 0) 764 765 goto out; 765 766 766 - if (args->porcelain) { 767 - ret = 0; 768 - goto out; 769 - } 770 - 771 767 for (ref = remote_refs; ref; ref = ref->next) { 772 768 switch (ref->status) { 773 769 case REF_STATUS_NONE: ··· 775 771 case REF_STATUS_OK: 776 772 break; 777 773 default: 778 - ret = -1; 774 + ret = ERROR_SEND_PACK_BAD_REF_STATUS; 779 775 goto out; 780 776 } 781 777 }
+13
send-pack.h
··· 13 13 #define SEND_PACK_PUSH_CERT_IF_ASKED 1 14 14 #define SEND_PACK_PUSH_CERT_ALWAYS 2 15 15 16 + /* At least one reference has been rejected by the remote side. */ 17 + #define ERROR_SEND_PACK_BAD_REF_STATUS 1 18 + 16 19 struct send_pack_args { 17 20 const char *url; 18 21 unsigned verbose:1, ··· 36 39 int option_parse_push_signed(const struct option *opt, 37 40 const char *arg, int unset); 38 41 42 + /* 43 + * Compute a packfile and write it to a file descriptor. The `fd` array needs 44 + * to contain two file descriptors: `fd[0]` is the file descriptor used as 45 + * input for the packet reader, whereas `fd[1]` is the file descriptor the 46 + * packfile will be written to. 47 + * 48 + * Returns 0 on success, non-zero otherwise. Negative return values indicate a 49 + * generic error, whereas positive return values indicate specific error 50 + * conditions as documented with the `ERROR_SEND_PACK_*` constants. 51 + */ 39 52 int send_pack(struct repository *r, struct send_pack_args *args, 40 53 int fd[], struct child_process *conn, 41 54 struct ref *remote_refs, struct oid_array *extra_have);
+16 -19
t/t5504-fetch-receive-strict.sh
··· 64 64 ) 65 65 ' 66 66 67 - cat >exp <<EOF 68 - To dst 69 - ! refs/heads/main:refs/heads/test [remote rejected] (missing necessary objects) 70 - Done 71 - EOF 72 - 73 67 test_expect_success 'push without strict' ' 74 68 rm -rf dst && 75 69 git init dst && ··· 78 72 git config fetch.fsckobjects false && 79 73 git config transfer.fsckobjects false 80 74 ) && 75 + cat >exp <<-\EOF && 76 + To dst 77 + ! refs/heads/main:refs/heads/test [remote rejected] (missing necessary objects) 78 + Done 79 + EOF 81 80 test_must_fail git push --porcelain dst main:refs/heads/test >act && 82 81 test_cmp exp act 83 82 ' ··· 94 93 test_cmp exp act 95 94 ' 96 95 97 - cat >exp <<EOF 98 - To dst 99 - ! refs/heads/main:refs/heads/test [remote rejected] (unpacker error) 100 - EOF 101 - 102 96 test_expect_success 'push with receive.fsckobjects' ' 103 97 rm -rf dst && 104 98 git init dst && ··· 107 101 git config receive.fsckobjects true && 108 102 git config transfer.fsckobjects false 109 103 ) && 104 + cat >exp <<-\EOF && 105 + To dst 106 + ! refs/heads/main:refs/heads/test [remote rejected] (unpacker error) 107 + EOF 110 108 test_must_fail git push --porcelain dst main:refs/heads/test >act && 111 109 test_cmp exp act 112 110 ' ··· 129 127 git fsck 130 128 ' 131 129 132 - cat >bogus-commit <<EOF 133 - tree $EMPTY_TREE 134 - author Bugs Bunny 1234567890 +0000 135 - committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000 130 + test_expect_success 'setup bogus commit' ' 131 + cat >bogus-commit <<-EOF && 132 + tree $EMPTY_TREE 133 + author Bugs Bunny 1234567890 +0000 134 + committer Bugs Bunny <bugs@bun.ni> 1234567890 +0000 136 135 137 - This commit object intentionally broken 138 - EOF 139 - 140 - test_expect_success 'setup bogus commit' ' 136 + This commit object intentionally broken 137 + EOF 141 138 commit="$(git hash-object --literally -t commit -w --stdin <bogus-commit)" 142 139 ' 143 140
+30
t/t5543-atomic-push.sh
··· 280 280 test_cmp expect actual 281 281 ' 282 282 283 + test_expect_success 'atomic push reports exit code failure' ' 284 + write_script receive-pack-wrapper <<-\EOF && 285 + git-receive-pack "$@" 286 + exit 1 287 + EOF 288 + test_must_fail git -C workbench push --atomic \ 289 + --receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \ 290 + up HEAD:refs/heads/no-conflict 2>err && 291 + cat >expect <<-EOF && 292 + To ../upstream 293 + * [new branch] HEAD -> no-conflict 294 + error: failed to push some refs to ${SQ}../upstream${SQ} 295 + EOF 296 + test_cmp expect err 297 + ' 298 + 299 + test_expect_success 'atomic push reports exit code failure with porcelain' ' 300 + write_script receive-pack-wrapper <<-\EOF && 301 + git-receive-pack "$@" 302 + exit 1 303 + EOF 304 + test_must_fail git -C workbench push --atomic --porcelain \ 305 + --receive-pack="${SQ}$(pwd)${SQ}/receive-pack-wrapper" \ 306 + up HEAD:refs/heads/no-conflict-porcelain 2>err && 307 + cat >expect <<-EOF && 308 + error: failed to push some refs to ${SQ}../upstream${SQ} 309 + EOF 310 + test_cmp expect err 311 + ' 312 + 283 313 test_done
+336 -107
t/t5548-push-porcelain.sh
··· 54 54 sed -e 's/^> //' -e 's/Z$//' >expect 55 55 } 56 56 57 + create_upstream_template () { 58 + git init --bare upstream-template.git && 59 + git clone upstream-template.git tmp_work_dir && 60 + create_commits_in tmp_work_dir A B && 61 + ( 62 + cd tmp_work_dir && 63 + git push origin \ 64 + $B:refs/heads/main \ 65 + $A:refs/heads/foo \ 66 + $A:refs/heads/bar \ 67 + $A:refs/heads/baz 68 + ) && 69 + rm -rf tmp_work_dir 70 + } 71 + 72 + setup_upstream () { 73 + if test $# -ne 1 74 + then 75 + BUG "location of upstream repository is not provided" 76 + fi && 77 + rm -rf "$1" && 78 + if ! test -d upstream-template.git 79 + then 80 + create_upstream_template 81 + fi && 82 + git clone --mirror upstream-template.git "$1" && 83 + # The upstream repository provides services using the HTTP protocol. 84 + if ! test "$1" = "upstream.git" 85 + then 86 + git -C "$1" config http.receivepack true 87 + fi 88 + } 89 + 57 90 setup_upstream_and_workbench () { 58 - # Upstream after setup : main(B) foo(A) bar(A) baz(A) 59 - # Workbench after setup : main(A) 91 + if test $# -ne 1 92 + then 93 + BUG "location of upstream repository is not provided" 94 + fi 95 + upstream="$1" 96 + 97 + # Upstream after setup: main(B) foo(A) bar(A) baz(A) 98 + # Workbench after setup: main(A) baz(A) next(A) 60 99 test_expect_success "setup upstream repository and workbench" ' 61 - rm -rf upstream.git workbench && 62 - git init --bare upstream.git && 63 - git init workbench && 64 - create_commits_in workbench A B && 100 + setup_upstream "$upstream" && 101 + rm -rf workbench && 102 + git clone "$upstream" workbench && 65 103 ( 66 104 cd workbench && 105 + git update-ref refs/heads/main $A && 106 + git update-ref refs/heads/baz $A && 107 + git update-ref refs/heads/next $A && 67 108 # Try to make a stable fixed width for abbreviated commit ID, 68 109 # this fixed-width oid will be replaced with "<OID>". 69 110 git config core.abbrev 7 && 70 - git remote add origin ../upstream.git && 71 - git update-ref refs/heads/main $A && 72 - git push origin \ 73 - $B:refs/heads/main \ 74 - $A:refs/heads/foo \ 75 - $A:refs/heads/bar \ 76 - $A:refs/heads/baz 111 + git config advice.pushUpdateRejected false 77 112 ) && 78 - git -C "workbench" config advice.pushUpdateRejected false && 79 - upstream=upstream.git 113 + # The upstream repository provides services using the HTTP protocol. 114 + if ! test "$upstream" = "upstream.git" 115 + then 116 + git -C workbench remote set-url origin "$HTTPD_URL/smart/upstream.git" 117 + fi 80 118 ' 81 119 } 82 120 ··· 88 126 ;; 89 127 file) 90 128 PROTOCOL="builtin protocol" 91 - URL_PREFIX="\.\." 129 + URL_PREFIX=".*" 92 130 ;; 93 131 esac 94 132 95 133 # Refs of upstream : main(B) foo(A) bar(A) baz(A) 96 134 # Refs of workbench: main(A) baz(A) next(A) 97 135 # git-push : main(A) NULL (B) baz(A) next(A) 98 - test_expect_success "porcelain output of successful git-push ($PROTOCOL)" ' 99 - ( 100 - cd workbench && 101 - git update-ref refs/heads/main $A && 102 - git update-ref refs/heads/baz $A && 103 - git update-ref refs/heads/next $A && 104 - git push --porcelain --force origin \ 105 - main \ 106 - :refs/heads/foo \ 107 - $B:bar \ 108 - baz \ 109 - next 110 - ) >out && 136 + test_expect_success ".. git-push --porcelain ($PROTOCOL)" ' 137 + test_when_finished "setup_upstream \"$upstream\"" && 138 + test_must_fail git -C workbench push --porcelain origin \ 139 + main \ 140 + :refs/heads/foo \ 141 + $B:bar \ 142 + baz \ 143 + next >out && 144 + make_user_friendly_and_stable_output <out >actual && 145 + format_and_save_expect <<-\EOF && 146 + > To <URL/of/upstream.git> 147 + > = refs/heads/baz:refs/heads/baz [up to date] 148 + > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 149 + > - :refs/heads/foo [deleted] 150 + > * refs/heads/next:refs/heads/next [new branch] 151 + > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 152 + > Done 153 + EOF 154 + test_cmp expect actual && 155 + 156 + git -C "$upstream" show-ref >out && 157 + make_user_friendly_and_stable_output <out >actual && 158 + cat >expect <<-EOF && 159 + <COMMIT-B> refs/heads/bar 160 + <COMMIT-A> refs/heads/baz 161 + <COMMIT-B> refs/heads/main 162 + <COMMIT-A> refs/heads/next 163 + EOF 164 + test_cmp expect actual 165 + ' 166 + 167 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 168 + # Refs of workbench: main(A) baz(A) next(A) 169 + # git-push : main(A) NULL (B) baz(A) next(A) 170 + test_expect_success ".. git-push --porcelain --force ($PROTOCOL)" ' 171 + test_when_finished "setup_upstream \"$upstream\"" && 172 + git -C workbench push --porcelain --force origin \ 173 + main \ 174 + :refs/heads/foo \ 175 + $B:bar \ 176 + baz \ 177 + next >out && 111 178 make_user_friendly_and_stable_output <out >actual && 112 179 format_and_save_expect <<-EOF && 113 180 > To <URL/of/upstream.git> ··· 131 198 test_cmp expect actual 132 199 ' 133 200 134 - # Refs of upstream : main(A) bar(B) baz(A) next(A) 135 - # Refs of workbench: main(B) bar(A) baz(A) next(A) 136 - # git-push : main(B) bar(A) NULL next(A) 137 - test_expect_success "atomic push failed ($PROTOCOL)" ' 201 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 202 + # Refs of workbench: main(A) baz(A) next(A) 203 + # git-push : main(A) NULL (B) baz(A) next(A) 204 + test_expect_success ".. git push --porcelain --atomic ($PROTOCOL)" ' 205 + test_when_finished "setup_upstream \"$upstream\"" && 206 + test_must_fail git -C workbench push --porcelain --atomic origin \ 207 + main \ 208 + :refs/heads/foo \ 209 + $B:bar \ 210 + baz \ 211 + next >out && 212 + make_user_friendly_and_stable_output <out >actual && 213 + format_and_save_expect <<-EOF && 214 + > To <URL/of/upstream.git> 215 + > = refs/heads/baz:refs/heads/baz [up to date] 216 + > ! <COMMIT-B>:refs/heads/bar [rejected] (atomic push failed) 217 + > ! (delete):refs/heads/foo [rejected] (atomic push failed) 218 + > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 219 + > ! refs/heads/next:refs/heads/next [rejected] (atomic push failed) 220 + > Done 221 + EOF 222 + test_cmp expect actual && 223 + 224 + git -C "$upstream" show-ref >out && 225 + make_user_friendly_and_stable_output <out >actual && 226 + cat >expect <<-EOF && 227 + <COMMIT-A> refs/heads/bar 228 + <COMMIT-A> refs/heads/baz 229 + <COMMIT-A> refs/heads/foo 230 + <COMMIT-B> refs/heads/main 231 + EOF 232 + test_cmp expect actual 233 + ' 234 + 235 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 236 + # Refs of workbench: main(A) baz(A) next(A) 237 + # git-push : main(A) NULL (B) baz(A) next(A) 238 + test_expect_success ".. pre-receive hook declined ($PROTOCOL)" ' 239 + test_when_finished "rm -f \"$upstream/hooks/pre-receive\" && 240 + setup_upstream \"$upstream\"" && 241 + test_hook --setup -C "$upstream" pre-receive <<-EOF && 242 + exit 1 243 + EOF 244 + test_must_fail git -C workbench push --porcelain --force origin \ 245 + main \ 246 + :refs/heads/foo \ 247 + $B:bar \ 248 + baz \ 249 + next >out && 250 + make_user_friendly_and_stable_output <out >actual && 251 + format_and_save_expect <<-EOF && 252 + > To <URL/of/upstream.git> 253 + > = refs/heads/baz:refs/heads/baz [up to date] 254 + > ! <COMMIT-B>:refs/heads/bar [remote rejected] (pre-receive hook declined) 255 + > ! :refs/heads/foo [remote rejected] (pre-receive hook declined) 256 + > ! refs/heads/main:refs/heads/main [remote rejected] (pre-receive hook declined) 257 + > ! refs/heads/next:refs/heads/next [remote rejected] (pre-receive hook declined) 258 + > Done 259 + EOF 260 + test_cmp expect actual && 261 + 262 + git -C "$upstream" show-ref >out && 263 + make_user_friendly_and_stable_output <out >actual && 264 + cat >expect <<-EOF && 265 + <COMMIT-A> refs/heads/bar 266 + <COMMIT-A> refs/heads/baz 267 + <COMMIT-A> refs/heads/foo 268 + <COMMIT-B> refs/heads/main 269 + EOF 270 + test_cmp expect actual 271 + ' 272 + 273 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 274 + # Refs of workbench: main(A) baz(A) next(A) 275 + # git-push : main(A) next(A) 276 + test_expect_success ".. non-fastforward push ($PROTOCOL)" ' 277 + test_when_finished "setup_upstream \"$upstream\"" && 138 278 ( 139 279 cd workbench && 140 - git update-ref refs/heads/main $B && 141 - git update-ref refs/heads/bar $A && 142 - test_must_fail git push --atomic --porcelain origin \ 280 + test_must_fail git push --porcelain origin \ 143 281 main \ 144 - bar \ 145 - :baz \ 146 282 next 147 283 ) >out && 148 284 make_user_friendly_and_stable_output <out >actual && 149 285 format_and_save_expect <<-EOF && 150 - To <URL/of/upstream.git> 151 - > = refs/heads/next:refs/heads/next [up to date] 152 - > ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward) 153 - > ! (delete):refs/heads/baz [rejected] (atomic push failed) 154 - > ! refs/heads/main:refs/heads/main [rejected] (atomic push failed) 155 - Done 286 + > To <URL/of/upstream.git> 287 + > * refs/heads/next:refs/heads/next [new branch] 288 + > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 289 + > Done 290 + EOF 291 + test_cmp expect actual && 292 + 293 + git -C "$upstream" show-ref >out && 294 + make_user_friendly_and_stable_output <out >actual && 295 + cat >expect <<-EOF && 296 + <COMMIT-A> refs/heads/bar 297 + <COMMIT-A> refs/heads/baz 298 + <COMMIT-A> refs/heads/foo 299 + <COMMIT-B> refs/heads/main 300 + <COMMIT-A> refs/heads/next 301 + EOF 302 + test_cmp expect actual 303 + ' 304 + 305 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 306 + # Refs of workbench: main(A) baz(A) next(A) 307 + # git-push : main(A) NULL (B) baz(A) next(A) 308 + test_expect_success ".. git push --porcelain --atomic --force ($PROTOCOL)" ' 309 + git -C workbench push --porcelain --atomic --force origin \ 310 + main \ 311 + :refs/heads/foo \ 312 + $B:bar \ 313 + baz \ 314 + next >out && 315 + make_user_friendly_and_stable_output <out >actual && 316 + format_and_save_expect <<-\EOF && 317 + > To <URL/of/upstream.git> 318 + > = refs/heads/baz:refs/heads/baz [up to date] 319 + > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 320 + > - :refs/heads/foo [deleted] 321 + > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update) 322 + > * refs/heads/next:refs/heads/next [new branch] 323 + > Done 156 324 EOF 157 325 test_cmp expect actual && 158 326 ··· 166 334 EOF 167 335 test_cmp expect actual 168 336 ' 337 + } 169 338 170 - test_expect_success "prepare pre-receive hook ($PROTOCOL)" ' 171 - test_hook --setup -C "$upstream" pre-receive <<-EOF 172 - exit 1 339 + run_git_push_dry_run_porcelain_output_test() { 340 + case $1 in 341 + http) 342 + PROTOCOL="HTTP protocol" 343 + URL_PREFIX="http://.*" 344 + ;; 345 + file) 346 + PROTOCOL="builtin protocol" 347 + URL_PREFIX=".*" 348 + ;; 349 + esac 350 + 351 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 352 + # Refs of workbench: main(A) baz(A) next(A) 353 + # git-push : main(A) NULL (B) baz(A) next(A) 354 + test_expect_success ".. git-push --porcelain --dry-run ($PROTOCOL)" ' 355 + test_must_fail git -C workbench push --porcelain --dry-run origin \ 356 + main \ 357 + :refs/heads/foo \ 358 + $B:bar \ 359 + baz \ 360 + next >out && 361 + make_user_friendly_and_stable_output <out >actual && 362 + format_and_save_expect <<-EOF && 363 + > To <URL/of/upstream.git> 364 + > = refs/heads/baz:refs/heads/baz [up to date] 365 + > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 366 + > - :refs/heads/foo [deleted] 367 + > * refs/heads/next:refs/heads/next [new branch] 368 + > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 369 + > Done 173 370 EOF 371 + test_cmp expect actual && 372 + 373 + git -C "$upstream" show-ref >out && 374 + make_user_friendly_and_stable_output <out >actual && 375 + cat >expect <<-EOF && 376 + <COMMIT-A> refs/heads/bar 377 + <COMMIT-A> refs/heads/baz 378 + <COMMIT-A> refs/heads/foo 379 + <COMMIT-B> refs/heads/main 380 + EOF 381 + test_cmp expect actual 174 382 ' 175 383 176 - # Refs of upstream : main(A) bar(B) baz(A) next(A) 177 - # Refs of workbench: main(B) bar(A) baz(A) next(A) 178 - # git-push : main(B) bar(A) NULL next(A) 179 - test_expect_success "pre-receive hook declined ($PROTOCOL)" ' 180 - ( 181 - cd workbench && 182 - git update-ref refs/heads/main $B && 183 - git update-ref refs/heads/bar $A && 184 - test_must_fail git push --porcelain --force origin \ 185 - main \ 186 - bar \ 187 - :baz \ 188 - next 189 - ) >out && 384 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 385 + # Refs of workbench: main(A) baz(A) next(A) 386 + # push : main(A) NULL (B) baz(A) next(A) 387 + test_expect_success ".. git-push --porcelain --dry-run --force ($PROTOCOL)" ' 388 + git -C workbench push --porcelain --dry-run --force origin \ 389 + main \ 390 + :refs/heads/foo \ 391 + $B:bar \ 392 + baz \ 393 + next >out && 190 394 make_user_friendly_and_stable_output <out >actual && 191 395 format_and_save_expect <<-EOF && 192 - To <URL/of/upstream.git> 193 - > = refs/heads/next:refs/heads/next [up to date] 194 - > ! refs/heads/bar:refs/heads/bar [remote rejected] (pre-receive hook declined) 195 - > ! :refs/heads/baz [remote rejected] (pre-receive hook declined) 196 - > ! refs/heads/main:refs/heads/main [remote rejected] (pre-receive hook declined) 197 - Done 396 + > To <URL/of/upstream.git> 397 + > = refs/heads/baz:refs/heads/baz [up to date] 398 + > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 399 + > - :refs/heads/foo [deleted] 400 + > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update) 401 + > * refs/heads/next:refs/heads/next [new branch] 402 + > Done 198 403 EOF 199 404 test_cmp expect actual && 200 405 201 406 git -C "$upstream" show-ref >out && 202 407 make_user_friendly_and_stable_output <out >actual && 203 408 cat >expect <<-EOF && 204 - <COMMIT-B> refs/heads/bar 409 + <COMMIT-A> refs/heads/bar 205 410 <COMMIT-A> refs/heads/baz 206 - <COMMIT-A> refs/heads/main 207 - <COMMIT-A> refs/heads/next 411 + <COMMIT-A> refs/heads/foo 412 + <COMMIT-B> refs/heads/main 208 413 EOF 209 414 test_cmp expect actual 210 415 ' 211 416 212 - test_expect_success "remove pre-receive hook ($PROTOCOL)" ' 213 - rm "$upstream/hooks/pre-receive" 417 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 418 + # Refs of workbench: main(A) baz(A) next(A) 419 + # git-push : main(A) NULL (B) baz(A) next(A) 420 + test_expect_success ".. git-push --porcelain --dry-run --atomic ($PROTOCOL)" ' 421 + test_must_fail git -C workbench push --porcelain --dry-run --atomic origin \ 422 + main \ 423 + :refs/heads/foo \ 424 + $B:bar \ 425 + baz \ 426 + next >out && 427 + make_user_friendly_and_stable_output <out >actual && 428 + format_and_save_expect <<-EOF && 429 + > To <URL/of/upstream.git> 430 + > = refs/heads/baz:refs/heads/baz [up to date] 431 + > ! <COMMIT-B>:refs/heads/bar [rejected] (atomic push failed) 432 + > ! (delete):refs/heads/foo [rejected] (atomic push failed) 433 + > ! refs/heads/main:refs/heads/main [rejected] (non-fast-forward) 434 + > ! refs/heads/next:refs/heads/next [rejected] (atomic push failed) 435 + > Done 436 + EOF 437 + test_cmp expect actual && 438 + 439 + git -C "$upstream" show-ref >out && 440 + make_user_friendly_and_stable_output <out >actual && 441 + cat >expect <<-EOF && 442 + <COMMIT-A> refs/heads/bar 443 + <COMMIT-A> refs/heads/baz 444 + <COMMIT-A> refs/heads/foo 445 + <COMMIT-B> refs/heads/main 446 + EOF 447 + test_cmp expect actual 214 448 ' 215 449 216 - # Refs of upstream : main(A) bar(B) baz(A) next(A) 217 - # Refs of workbench: main(B) bar(A) baz(A) next(A) 218 - # git-push : main(B) bar(A) NULL next(A) 219 - test_expect_success "non-fastforward push ($PROTOCOL)" ' 220 - ( 221 - cd workbench && 222 - test_must_fail git push --porcelain origin \ 223 - main \ 224 - bar \ 225 - :baz \ 226 - next 227 - ) >out && 450 + # Refs of upstream : main(B) foo(A) bar(A) baz(A) 451 + # Refs of workbench: main(A) baz(A) next(A) 452 + # push : main(A) NULL (B) baz(A) next(A) 453 + test_expect_success ".. git-push --porcelain --dry-run --atomic --force ($PROTOCOL)" ' 454 + git -C workbench push --porcelain --dry-run --atomic --force origin \ 455 + main \ 456 + :refs/heads/foo \ 457 + $B:bar \ 458 + baz \ 459 + next >out && 228 460 make_user_friendly_and_stable_output <out >actual && 229 461 format_and_save_expect <<-EOF && 230 - To <URL/of/upstream.git> 231 - > = refs/heads/next:refs/heads/next [up to date] 232 - > - :refs/heads/baz [deleted] 233 - > refs/heads/main:refs/heads/main <COMMIT-A>..<COMMIT-B> 234 - > ! refs/heads/bar:refs/heads/bar [rejected] (non-fast-forward) 235 - Done 462 + > To <URL/of/upstream.git> 463 + > = refs/heads/baz:refs/heads/baz [up to date] 464 + > <COMMIT-B>:refs/heads/bar <COMMIT-A>..<COMMIT-B> 465 + > - :refs/heads/foo [deleted] 466 + > + refs/heads/main:refs/heads/main <COMMIT-B>...<COMMIT-A> (forced update) 467 + > * refs/heads/next:refs/heads/next [new branch] 468 + > Done 236 469 EOF 237 470 test_cmp expect actual && 238 471 239 472 git -C "$upstream" show-ref >out && 240 473 make_user_friendly_and_stable_output <out >actual && 241 474 cat >expect <<-EOF && 242 - <COMMIT-B> refs/heads/bar 475 + <COMMIT-A> refs/heads/bar 476 + <COMMIT-A> refs/heads/baz 477 + <COMMIT-A> refs/heads/foo 243 478 <COMMIT-B> refs/heads/main 244 - <COMMIT-A> refs/heads/next 245 479 EOF 246 480 test_cmp expect actual 247 481 ' 248 482 } 249 483 250 - # Initialize the upstream repository and local workbench. 251 - setup_upstream_and_workbench 484 + setup_upstream_and_workbench upstream.git 252 485 253 - # Run git-push porcelain test on builtin protocol 254 486 run_git_push_porcelain_output_test file 255 487 488 + setup_upstream_and_workbench upstream.git 489 + 490 + run_git_push_dry_run_porcelain_output_test file 491 + 256 492 ROOT_PATH="$PWD" 257 493 . "$TEST_DIRECTORY"/lib-gpg.sh 258 494 . "$TEST_DIRECTORY"/lib-httpd.sh 259 495 . "$TEST_DIRECTORY"/lib-terminal.sh 260 496 start_httpd 497 + setup_askpass_helper 261 498 262 - # Re-initialize the upstream repository and local workbench. 263 - setup_upstream_and_workbench 499 + setup_upstream_and_workbench "$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" 264 500 265 - test_expect_success "setup for http" ' 266 - git -C upstream.git config http.receivepack true && 267 - upstream="$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" && 268 - mv upstream.git "$upstream" && 501 + run_git_push_porcelain_output_test http 269 502 270 - git -C workbench remote set-url origin $HTTPD_URL/smart/upstream.git 271 - ' 272 - 273 - setup_askpass_helper 503 + setup_upstream_and_workbench "$HTTPD_DOCUMENT_ROOT_PATH/upstream.git" 274 504 275 - # Run git-push porcelain test on HTTP protocol 276 - run_git_push_porcelain_output_test http 505 + run_git_push_dry_run_porcelain_output_test http 277 506 278 507 test_done
+8 -9
transport.c
··· 935 935 case protocol_v0: 936 936 ret = send_pack(the_repository, &args, data->fd, data->conn, remote_refs, 937 937 &data->extra_have); 938 + /* 939 + * Ignore the specific error code to maintain consistent behavior 940 + * with the "push_refs()" function across different transports, 941 + * such as "push_refs_with_push()" for HTTP protocol. 942 + */ 943 + if (ret == ERROR_SEND_PACK_BAD_REF_STATUS) 944 + ret = 0; 938 945 break; 939 946 case protocol_unknown_version: 940 947 BUG("unknown protocol version"); ··· 942 949 943 950 close(data->fd[1]); 944 951 close(data->fd[0]); 945 - /* 946 - * Atomic push may abort the connection early and close the pipe, 947 - * which may cause an error for `finish_connect()`. Ignore this error 948 - * for atomic git-push. 949 - */ 950 - if (ret || args.atomic) 951 - finish_connect(data->conn); 952 - else 953 - ret = finish_connect(data->conn); 952 + ret |= finish_connect(data->conn); 954 953 data->conn = NULL; 955 954 data->finished_handshake = 0; 956 955