git push --atomic - Not failing

坚强是说给别人听的谎言 提交于 2021-02-16 08:48:12

问题


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 a transport-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 to send_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 or status_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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!