Git push --atomic - 不失败

6
我一直在尝试使用相对较新的--atomic选项进行git push,但它并没有奏效,即使其他失败了,它仍然让一些引用更改了。从这里的diff来看,似乎需要在远程服务器上有一些东西也要接受原子标志。虽然这很有道理,但默认使用它似乎是可以的。我正在向一个使用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'

注意:Git 2.23(2019年第三季度)修复了有关“--atomic”选项的错误。请参见下面我编辑过的答案 - VonC
2个回答

6

我是Bitbucket Server开发人员之一。对于这个问题的回复非常晚,但我刚刚注意到它。

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

查看Git源代码中提供main用于git-remote-httpgit-remote-httpsremote-curl.c,在调用git send-pack发送包文件时不会传递--atomic。(请参阅此处如何构建send-pack命令行)因此,在使用HTTP(S)远程执行git push --atomic时,--atomic被简单地忽略,并且推送按照正常方式运行。这就是您看到分支被创建的原因。

请注意,这根本不是服务器端行为。在这种情况下,Bitbucket Server或任何其他托管提供商都无能为力。如果您使用来跟踪客户端和服务器彼此发送的内容,您会看到以下对话:
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

在该输出中,我运行了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支持设置它)。这意味着send-pack.c中的原子处理从未被触发
你可以从以下的“对话”中看到这一过程。 "git<" 行是服务器对客户端说的话,因此您可以看到引用广告被发送了。 "git>" 行是客户端对服务器说的话。请注意,有一个 "git>" 行发送了 "refs/heads/branch-4",但没有类似的行发送 "refs/heads/master"。客户端根本没有尝试将 "master" 更新发送到服务器,因为使用服务器的引用广告,它已经知道该更新不是快进更新,而且由于没有使用 --force,该更新将失败。

SSH 的协议输出甚至更加简单:

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

类似于 HTTPS,"push<" 行是服务器对客户端说的话。正如您所看到的,服务器发送了一个引用广告,然后客户端简单地中止 - 它从未向服务器写入任何数据包。
因此,在这两种情况下,服务器根本没有处理 --atomic。这并不是说它永远不会被处理,但对于这些简单示例,其中客户端可以检测到至少一个更新肯定会失败,--atomic 是完全在本地处理(或不处理)。

3

Git 2.23更新(2019年第三季度):通过传输助手(即智能http传输)进行的"git push --atomic"未能在本地确定其中一个引用更新将失败而无需咨询另一端时阻止推送引用,这已得到纠正。

请参见提交3bca1e7(2019年7月11日),作者为Emily Shaffer(nasamuffin
(由Junio C Hamano -- gitster --提交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季度)中得到纠正。
请参见提交6f11942(2019年10月16日),由brian m. carlson (bk2204)提交。
(由Junio C Hamano -- gitster --合并于提交d45d771,2019年10月23日)

remote-curl: 将原子能力传递给远程端

Signed-off-by: brian m. carlson

使用--atomic选项推送多个引用时,服务器应执行单个原子事务以更新引用,使其全部成功或全部失败。

本地或通过SSH进行推送时可正常工作,但是在HTTP上推送时,我们未能将原子能力传递给远程端。

实际上,在整个功能生命周期中,我们还没有向任何远程帮助程序报告此功能。

通常情况下,尽管客户端实际上检查了大多数类型的失败(例如非快进式更新),并且仅中止整个尝试,但事情仍然会发生。

但是,如果服务器端报告问题,例如无法锁定参考位置,则事务不是原子性的,因为我们没有传递适当的能力,并且远程端无法知道我们想要的原子行为。

通过从传输代码中传递选项到远程帮助程序,然后从HTTP远程帮助程序传递到send-pack来解决此问题。

通过此更改,我们可以检测服务器端是否拒绝推送并适当地报告回来。

请注意消息中的差异:远程端报告“原子事务失败”,而我们自己的检查则拒绝推送并显示“原子推送失败”消息。

在远程帮助程序文档中记录原子选项,以便其他实现者可以根据需要实现它。

现在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年第二季度),"git push --atomic"会显示未推送的引用失败,这已得到纠正。

请查看 提交 dfe1b7f, 提交 f38b168, 提交 46701bd, 提交 865e23f, 提交 7dcbeaa (2020年4月17日) 由Jiang Xin (jiangxin)提交。
(由Junio C Hamano -- gitster --合并于提交 5b6864c, 2020年4月28日)

send-pack: 正确标记原子推送失败

Signed-off-by: Jiang Xin

使用SSH或其他智能协议进行推送时,引用会在发送到“receve-pack”的send_pack()命令之前由函数check_to_send_update()进行验证。

对于原子推送,如果在验证后拒绝了一个引用,则只应将用户推送的引用标记为失败,而不是在所有远程引用上报告失败。

提交v2.22.0-1-g3bca1e7f9f(transport-helper:在push_refs_with_push中强制执行原子操作,2019-07-11)旨在修复HTTP协议的报告问题,但将所有远程引用标记为原子推送失败。

为了解决SSH或其他内置智能协议的状态报告问题,撤销该提交的一部分,并为函数atomic_push_failure()添加附加状态。

它的附加状态除了"REF_STATUS_EXPECTING_REPORT"状态外还有:

  • REF_STATUS_NONE:尚未标记为“REF_STATUS_EXPECTING_REPORT”。
  • REF_STATUS_OK:假设dryrun或status_report已禁用,则为OK。

原始答案(2016年5月)

我正在向BitBucket服务器推送

只有BitBucket支持团队才能确认以下内容:

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

我怀疑它尚未激活,因为大多数git客户端可能没有达到我在2015年2月提到的git 2.4或更高级别。


我并不是说它被推送到了BitBucket云服务器上,而是被推送到了运行BitBucket的私有服务器,而我是管理员。我已经将服务器更新为2.8.1,并且在远程仓库中没有配置receive.advertiseatomic。我想知道这是否与它使用http协议有关,在这种情况下,Web应用程序可能无法接受--atomic选项。有趣的是,客户端并没有失败,并且让我知道远程无法处理原子操作。 - Joseph K. Strauss
@JosephK.Strauss 它应该通过http工作。你尝试过使用显式的 git config receive.advertiseatomic 1 吗(即使它应该是默认值)。你有一个可重现的案例吗? - VonC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接