git push --atomic - 没有失败

git push --atomic - Not failing

我一直在尝试为 git push 使用相对较新的 --atomic 选项,但它对我不起作用,即,即使其他引用失败,它仍然允许更改一些引用。

从差异 here 看来,远程服务器上也需要一些东西来接受原子标志。虽然这是有道理的,但似乎默认是使用它。

我正在使用 http 协议推送到 BitBucket 服务器实例。服务器上 Git 的当前版本是 "git version 2.8.1"。

我需要在服务器上配置什么才能让它工作吗?

编辑:

下面是一个可以复现的例子。

服务器配置:

$ git --version
git version 2.8.1

$ git config --get-all --show-origin  receive.advertiseatomic
file:/home/bitbucket/.gitconfig 1

在客户端:

$ 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'

Git2.23(2019 年第 3 季度)的更新:通过传输助手(即智能 http 传输)的“git push --atomic”未能阻止在可以推送引用时推送引用在本地告诉 ref 更新之一将失败,而不 必须咨询另一端,已更正。

commit 3bca1e7 (11 Jul 2019) by Emily Shaffer (nasamuffin)
(由 Junio C Hamano -- gitster -- in commit f87ee7f 合并,2019 年 7 月 25 日)

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

注意:通过智能 HTTP 传输的原子推送不起作用,已通过 Git 2.24(2019 年第 4 季度)更正。

参见 commit 6f11942 (16 Oct 2019) by brian m. carlson (bk2204)
(由 Junio C Hamano -- gitster -- in commit d45d771 合并,2019 年 10 月 23 日)

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.

因此 Documentation/gitremote-helpers.txt 现在包括:

'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.


在 Git 2.27(2020 年第 2 季度)之前,“git push --atomic”用于显示甚至未推送的 ref 失败,已得到纠正。

commit dfe1b7f, commit f38b168, commit 46701bd, commit 865e23f, commit 7dcbeaa (17 Apr 2020) by Jiang Xin (jiangxin)
(由 Junio C Hamano -- gitster -- in commit 5b6864c 合并,2020 年 4 月 28 日)

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.

原始答案(2016 年 5 月)

I am pushing to a BitBucket server

只有 BitBucket 支持可以与您确认:

  • 他们 git 托管服务器 git 的确切版本
  • 该功能是否已明确停用 (git config receive.advertiseatomic 0)。

我怀疑它尚未激活,因为大多数 git 客户端可能未达到 git 2.4 或更高级别 that I mentioned in February 2015

我是 Bitbucket Server 开发人员之一。很抱歉这么晚才回答这个问题,但我刚刚才注意到它。

这似乎就是 Git 的工作原理。例如,如果您通过 HTTPS 使用 GitHub 重新测试 git push --atomic,您将看到相同的行为。

查看Git源代码,remote-curl.c,其中为git-remote-httpgit-remote-https提供了main,没有通过--atomic当它调用 git send-pack 发送包文件时。 (See how the send-pack command line is constructed here) 因此,当将 git push --atomic 与 HTTP(S) 遥控器一起使用时,--atomic 将被忽略,而推送 运行s 将照常进行。这就是您看到正在创建分支的原因。

请注意,这根本不是服务器端行为。在这种情况下,Bitbucket Server 或任何其他托管服务提供商都无能为力。如果您使用 GIT_TRACE_PACKET=1 来跟踪客户端和服务器相互发送的内容,您将看到如下对话:

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[=10=]report-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[=10=]report-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[=10=]
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[=10=]
report-status side-band-64k agent=git/2.4.00000

在这个输出中,我有 运行 git push --atomic https://github.com/... non-fast-forward:refs/heads/master non-fast-forward:refs/heads/branch-4。请注意,当 git send-pack 为 运行 时,没有设置 --atomic 选项(但 git send-pack does support it being set). That means the atomic handling in send-pack.c 永远不会被触发。

您可以从下面的 "conversation" 中看到实际效果。 "git<" 行是 服务器 对客户端所说的内容,因此您可以看到发送了 ref 广告。 "git>" 行是 客户端 对服务器说的。请注意,有一条 "git>" 行发送 "refs/heads/branch-4",但没有类似的行 "refs/heads/master"。 客户端 甚至根本不会尝试将 "master" 更新发送到服务器,因为使用服务器的 ref 广告,它 已经知道 该更新是非快进的,并且由于未使用 --force,该更新将失败。

SSH 的 wire 协议输出更简单:

22:56:08.609608 pkt-line.c:46           packet:         push<
1b9c21b7aeb6ad03957cc8a023b2406d3ccee319
refs/heads/branch-1[=11=]report-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

与 HTTPS 类似,"push<" 行是 服务器 对客户端所说的内容。如您所见,服务器发送一个 ref 通告,然后客户端简单地中止——它永远不会向服务器写入一个数据包。

所以在这两种情况下,--atomic 根本就没有被服务器处理过。这并不是说它永远不会可以,但是对于这些简单的例子,客户端可以检测到至少一个更新肯定会失败,--atomic 完全在本地处理(或不处理)。