A question came up on Stack Overflow[1], and then again through our support channels, about "git push --atomic" and a behavior mismatch between HTTP(S) and SSH. I'm easily able to reproduce the behavior, but I don't see anything Bitbucket Server-related about how this works (and I get exactly the same mismatched behavior against GitHub; but that's not really a surprise given what I see in the wire protocol. First, a setup: 2 commits, with the second commit then amended to make a 3rd commit. git init foo cd foo echo 'Hello, World' > file.txt git add file.txt git commit -m "Initial commit" echo 'Goodbye, World' > file.txt git commit -am "Second commit" git tag original-message echo 'Goodbye, Cruel World' > file.txt git commit -a --amend --no-edit git tag amended-message Now, given an HTTP remote: (Assume "atomic-pushes" is an empty, just-created repository) git remote add http https://github.com/bturner/atomic-pushes.git git push http original-message:refs/heads/master git push --atomic http amended-message:refs/heads/master amended-message:refs/heads/branch-1 So we push the original message commit to master first, and then we try to push (without --force) the amended commit to both master and a new branch. That'll produce this: Total 0 (delta 0), reused 0 (delta 0) remote: remote: Create a pull request for 'branch-1' on GitHub by visiting: remote: https://github.com/bturner/atomic-pushes/pull/new/branch-1 remote: To https://github.com/bturner/atomic-pushes.git * [new branch] HEAD -> branch-1 ! [rejected] HEAD -> master (non-fast-forward) error: failed to push some refs to 'https://github.com/bturner/atomic-pushes.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. Now let's try it with SSH: (Using a different branch because the HTTP push created branch-1) git remote add ssh git@xxxxxxxxxx:bturner/atomic-pushes.git git push --atomic ssh amended-message:refs/heads/master amended-message:refs/heads/branch-2 Now we see: error: atomic push failed for ref refs/heads/master. status: 2 To git@xxxxxxxxxx:bturner/atomic-pushes.git ! [rejected] HEAD -> master (non-fast-forward) error: failed to push some refs to 'git@xxxxxxxxxx:bturner/atomic-pushes.git' hint: Updates were rejected because the tip of your current branch is behind hint: its remote counterpart. Integrate the remote changes (e.g. hint: 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details. No mention of branch-2 at all, but if I do a "git ls-remote ssh" I see: fe86a3eae65e18787040499c17a567096159b9ce HEAD 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-1 fe86a3eae65e18787040499c17a567096159b9ce refs/heads/master So branch-2 didn't get created. Looking at the wire protocol with GIT_TRACE_PACKET, I see this conversation for HTTP: (At this point I've done several tests, which have created various branches, so I'm now trying to push master and branch-4) 22:16:06.562939 pkt-line.c:46 packet: git< # service=git-receive-pack 22:16:06.562990 pkt-line.c:46 packet: git< 0000 22:16:06.562994 pkt-line.c:46 packet: git< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-1\0report-status delete-refs side-band-64k quiet atomic ofs-delta agent=git/github-g4f6c801f9475 22:16:06.563013 pkt-line.c:46 packet: git< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-2 22:16:06.563016 pkt-line.c:46 packet: git< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-3 22:16:06.563019 pkt-line.c:46 packet: git< fe86a3eae65e18787040499c17a567096159b9ce refs/heads/master 22:16:06.563024 pkt-line.c:46 packet: git< 0000 22:16:06.563329 pkt-line.c:46 packet: git> HEAD:refs/heads/branch-4 22:16:06.563346 pkt-line.c:46 packet: git> 0000 22:16:06.563357 run-command.c:347 trace: run_command: 'send-pack' '--stateless-rpc' '--helper-status' '--thin' '--progress' 'https://github.com/bturner/atomic-pushes.git/' '--stdin' 22:16:06.563765 exec_cmd.c:129 trace: exec: 'git' 'send-pack' '--stateless-rpc' '--helper-status' '--thin' '--progress' 'https://github.com/bturner/atomic-pushes.git/' '--stdin' 22:16:06.564691 git.c:348 trace: built-in: git 'send-pack' '--stateless-rpc' '--helper-status' '--thin' '--progress' 'https://github.com/bturner/atomic-pushes.git/' '--stdin' 22:16:06.564788 pkt-line.c:46 packet: git< HEAD:refs/heads/branch-4 22:16:06.564793 pkt-line.c:46 packet: git< 0000 22:16:06.564797 pkt-line.c:46 packet: git< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-1\0report-status delete-refs side-band-64k quiet atomic ofs-delta agent=git/github-g4f6c801f9475 22:16:06.564805 pkt-line.c:46 packet: git< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-2 22:16:06.564826 pkt-line.c:46 packet: git< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-3 22:16:06.564830 pkt-line.c:46 packet: git< fe86a3eae65e18787040499c17a567096159b9ce refs/heads/master 22:16:06.564834 pkt-line.c:46 packet: git< 0000 22:16:06.564970 pkt-line.c:46 packet: git> 0000000000000000000000000000000000000000 6925c65344e87c65e5cd2b56d392cd06ef96ca71 refs/heads/branch-4\0 report-status side-band-64k agent=git/2.4.0 22:16:06.564989 pkt-line.c:46 packet: git> 0000 22:16:06.565027 pkt-line.c:46 packet: git< 00960000000000000000000000000000000000000000 6925c65344e87c65e5cd2b56d392cd06ef96ca71 refs/heads/branch-4\0 report-status side-band-64k agent=git/2.4.00000 Based on that, I see that the server advertises the existing refs, and "atomic" support, and then the client _only_ sends branch-4; it doesn't send anything for master at all. That implies the non-fast-forward rejection for master is actually being done locally, not on the server. Only one ref change gets sent to the server, which applies without issue. Looking at SSH shows very different output: (branch-4 now exists because of the HTTP test above, so now I'm pushing master and branch-5) 22:56:08.609608 pkt-line.c:46 packet: push< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-1\0report-status delete-refs side-band-64k quiet atomic ofs-delta agent=git/github-g4f6c801f9475 22:56:08.609774 pkt-line.c:46 packet: push< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-2 22:56:08.609798 pkt-line.c:46 packet: push< 1b9c21b7aeb6ad03957cc8a023b2406d3ccee319 refs/heads/branch-3 22:56:08.609801 pkt-line.c:46 packet: push< 6925c65344e87c65e5cd2b56d392cd06ef96ca71 refs/heads/branch-4 22:56:08.609825 pkt-line.c:46 packet: push< fe86a3eae65e18787040499c17a567096159b9ce refs/heads/master 22:56:08.609831 pkt-line.c:46 packet: push< 0000 There are no "push>" lines at all. The server sends its ref advertisement, and then it seems like the non-fast-forward rejection for master happens locally, similar to HTTPS, but then, unlike HTTPS, the SSH push is simply aborted without ever sending anything to the server at all. I've verified this with Git 2.4.0 as a client (which appears to be where "git push --atomic" was first introduced), and with Git 2.20.1 as a client, to ensure there wasn't a regression somewhere, and the behavior is identical for both versions. (I've also verified it with both Linux and Windows clients, just for extra paranoia.) The result seems unexpected from a user perspective, but looking at the code it seems like it's working as implemented. "remote-curl.c" doesn't include "--atomic" when it runs "git send-pack", so it looks like HTTP(S) pushes simply ignore "git push --atomic" entirely. Am I misunderstanding how this is supposed to work? If not, should the documentation be updated to clarify that HTTP(S) remotes don't support "--atomic"? Best regards, Bryan Turner [1] https://stackoverflow.com/questions/37531663/git-push-atomic-not-failing