问题
I have been trying to use the relatively new --atomic
option for git push
, but it has not worked for me, i.e., it still lets some refs change even though others failed.
It seems from the diff here that there needs to be something on the remote server that will accept the atomic flag as well. While this makes sense, it seems that the default is to use it.
I am pushing to a BitBucket server instance with http protocol. The current version of Git on the server is "git version 2.8.1".
Is there something that I need to configure on the server to enable this to work?
Edit:
Below is an example which can reproduced.
Configuration on server:
$ git --version
git version 2.8.1
$ git config --get-all --show-origin receive.advertiseatomic
file:/home/bitbucket/.gitconfig 1
On the client:
$ git --version
git version 2.8.2.windows.1
$ git push <local-path>/.git HEAD:refs/heads/wwww HEAD:refs/heads/zzz --force-with-lease=zzz --atomic
error: atomic push failed for ref refs/heads/zzz. status: 7
fatal: The remote end hung up unexpectedly
To <local-path>/.git
! [rejected] HEAD -> wwww (atomic push failed)
! [rejected] HEAD -> zzz (stale info)
error: failed to push some refs to '<local-path>/.git'
$ git push origin HEAD:refs/heads/wwww HEAD:refs/heads/zzz --force-with-lease=zzz --atomic
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote:
To http://me@bitbucket-local.com/scm/proj/repo.git
* [new branch] HEAD -> wwww
! [rejected] HEAD -> zzz (stale info)
error: failed to push some refs to 'http://me@bitbucket-local.com/scm/proj/repo.git'
回答1:
I'm one of the Bitbucket Server developers. Apologies for such a late response to this question but I only just noticed it.
This appears to be just how Git works. If you re-test your git push --atomic
with GitHub via HTTPS, for example, you'll see identical behavior.
Looking at the Git source code, remote-curl.c
, which provides main
for git-remote-http
and git-remote-https
, does not pass --atomic
when it invokes git send-pack
to send a pack file. (See how the send-pack command line is constructed here) So when using git push --atomic
with an HTTP(S) remote, the --atomic
is simply ignored and the push runs as normal. That's why you see the branch being created.
Note that this isn't a server-side behavior at all. There's nothing Bitbucket Server, or any other hosting provider, can do in this situation. If you use GIT_TRACE_PACKET=1
to trace what the client and server send to each other, you'll see a conversation like this:
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
In this output, I've run git push --atomic https://github.com/... non-fast-forward:refs/heads/master non-fast-forward:refs/heads/branch-4
. Notice that when git send-pack
is run, there's no --atomic
option set (but git send-pack
does support it being set). That means the atomic handling in send-pack.c is never triggered.
You can see that in action from the "conversation" that follows. "git<" lines are things the server said to the client, so you can see the ref advertisement is sent. "git>" lines are things the client said to the server. Notice that there's a "git>" line sending "refs/heads/branch-4", but there is no similar line for "refs/heads/master". The client never even tries to send the "master" update to the server at all, because, using the server's ref advertisement, it already knows that update is non-fast-forward and, since --force
wasn't used, that that update is going to fail.
SSH's wire protocol output is even more simple:
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
Similar to HTTPS, "push<" lines are what the server said to the client. As you can see, the server sends a ref advertisement, and then the client simply aborts--it never writes a single packet to the server.
So in neither of these cases was the --atomic
handled by the server at all. That's not to say it never can be, but for these simple examples, where the client can detect at least one update is sure to fail, --atomic
is handled (or not handled) entirely locally.
回答2:
Update for Git 2.23 (Q3 2019): "git push --atomic
" that goes over the transport-helper (namely, the smart http transport) failed to prevent refs to be pushed when it can locally tell that one of the ref update will fail without
having to consult the other end, which has been corrected.
See commit 3bca1e7 (11 Jul 2019) by Emily Shaffer (nasamuffin).
(Merged by Junio C Hamano -- gitster -- in commit f87ee7f, 25 Jul 2019)
transport-helper: enforce atomic in push_refs_with_push
Teach
transport-helper
how to notice if skipping a ref during push would violate atomicity on the client side.We notice that a ref would be rejected, and choose not to send it, but don't notice that if the client has asked for
--atomic
we are violating atomicity if all the other pushes we are sending would succeed.Asking the server end to uphold atomicity wouldn't work here as the server doesn't have any idea that we tried to update a ref that's broken.
The added test-case is a succinct way to reproduce this issue that fails today.
The same steps work fine when we aren't using atransport-helper
to get to the upstream, i.e. when we've added a local repository as a remote:git remote add ~/upstream upstream
Note: The atomic push over smart HTTP transport did not work, which has been corrected, with Git 2.24 (Q4 2019).
See commit 6f11942 (16 Oct 2019) by brian m. carlson (bk2204).
(Merged by Junio C Hamano -- gitster -- in commit d45d771, 23 Oct 2019)
remote-curl: pass on atomic capability to remote side
Signed-off-by: brian m. carlson
When pushing more than one reference with the
--atomic
option, the server is supposed to perform a single atomic transaction to update the references, leaving them either all to succeed or all to fail.This works fine when pushing locally or over SSH, but when pushing over HTTP, we fail to pass the atomic capability to the remote side.
In fact, we have not reported this capability to any remote helpers during the life of the feature.
Now normally, things happen to work nevertheless, since we actually check for most types of failures, such as non-fast-forward updates, on the client side, and just abort the entire attempt.
However, if the server side reports a problem, such as the inability to lock a ref, the transaction isn't atomic, because we haven't passed the appropriate capability over and the remote side has no way of knowing that we wanted atomic behavior.
Fix this by passing the option from the transport code through to remote helpers, and from the HTTP remote helper down to send-pack.
With this change, we can detect if the server side rejects the push and report back appropriately.
Note the difference in the messages: the remote side reports "atomic transaction failed", while our own checking rejects pushes with the message "atomic push failed".
Document the atomic option in the remote helper documentation, so other implementers can implement it if they like.
So the Documentation/gitremote-helpers.txt now includes:
'option atomic' {'true'|'false'}:
When pushing, request the remote server to update refs in a single atomic transaction.
If successful, all refs will be updated, or none will.
If the remote side does not support this capability, the push will fail.
Before Git 2.27 (Q2 2020), "git push --atomic
" used to show failures for refs that weren't even pushed, which has been corrected.
See commit dfe1b7f, commit f38b168, commit 46701bd, commit 865e23f, commit 7dcbeaa (17 Apr 2020) by Jiang Xin (jiangxin).
(Merged by Junio C Hamano -- gitster -- in commit 5b6864c, 28 Apr 2020)
send-pack: mark failure of atomic push properly
Signed-off-by: Jiang Xin
When pushing with SSH or other smart protocol, references are validated by function
check_to_send_update()
before they are sent in commands tosend_pack()
of "receve-pack
".For atomic push, if a reference is rejected after the validation, only references pushed by user should be marked as failure, instead of report failure on all remote references.
Commit v2.22.0-1-g3bca1e7f9f (transport-helper: enforce atomic in
push_refs_with_push
, 2019-07-11) wanted to fix report issue of HTTP protocol, but marked all remote references failure for atomic push.In order to fix the issue of status report for SSH or other built-in smart protocol, revert part of that commit and add additional status for function
atomic_push_failure()
.The additional status for it except the
"REF_STATUS_EXPECTING_REPORT"
status are:
REF_STATUS_NONE
: Not marked as "REF_STATUS_EXPECTING_REPORT
" yet.REF_STATUS_OK
: Assume OK for dryrun orstatus_report
is disabled.
original answer (May 2016)
I am pushing to a BitBucket server
Only BitBucket support can confirm with you:
- their exact git version for their git hosting server
- if that feature was explicitly deactivated (
git config receive.advertiseatomic 0
) or not.
I suspect it is not yet activated, as most git clients might not be at git 2.4 or more level that I mentioned in February 2015.
来源:https://stackoverflow.com/questions/37531663/git-push-atomic-not-failing