如果我中途取消 'pull remote changes' 会怎样?

What happens if I cancel a 'pull remote changes' midway?

我只是在 Xcode 中从远程拉取。

它现在已经获取更改 15 分钟('fetching changes' 仍在旋转)...通常需要 5-30 秒。不知道是有什么问题还是怎么的。我的网速没问题。

如果我取消,我会破坏任何东西吗?即得到一个混乱的代码。那会发生吗?进程是原子的吗?

执行 git pull 与执行 git fetch 后跟 git merge 相同。后面的merge操作完全发生在local branch与其对应的tracking branch之间,与你的实际问题无关。

关于 git fetchthis blog 似乎声明 Git 操作(可能包括 git fetch)是原子的:

Git is known to have atomic operations i.e. an environment issue will not cause git to commit half of the files into the repository and leave the rest.

假设这是准确的,那么远程跟踪分支要么在 git fetch 期间完全更新,要么保持原样。

fetch 部分,您现在对其原子性有了更多的保证。

使用 Git 2.31(2021 年第一季度),“git fetch"(man) learns to treat ref updates atomically in all-or-none fashion, just like "git push"(man) 使用新的“--atomic”选项。

参见 commit c7b190d, commit d4c8db8, commit c45889f, commit 929d044, commit 58a646a (12 Jan 2021) by Patrick Steinhardt (pks-t)
(由 Junio C Hamano -- gitster -- in commit 60ecad0 合并,2021 年 1 月 25 日)

fetch: implement support for atomic reference updates

Signed-off-by: Patrick Steinhardt

When executing a fetch, then Git will currently allocate one reference transaction per reference update and directly commit it.
This means that fetches are non-atomic: even if some of the reference updates fail, others may still succeed and modify local references.

This is fine in many scenarios, but this strategy has its downsides.

  • The view of remote references may be inconsistent and may show a bastardized state of the remote repository.
  • Batching together updates may improve performance in certain scenarios.
    While the impact probably isn't as pronounced with loose references, the upcoming reftable backend may benefit as it needs to write less files in case the update is batched.
  • The reference-update hook is currently being executed twice per updated reference.
    While this doesn't matter when there is no such hook, we have seen severe performance regressions when doing a git-fetch(1) with reference-transaction hook when the remote repository has hundreds of thousands of references.

Similar to git push(man) --atomic, this commit thus introduces atomic fetches.

Instead of allocating one reference transaction per updated reference, it causes us to only allocate a single transaction and commit it as soon as all updates were received.
If locking of any reference fails, then we abort the complete transaction and don't update any reference, which gives us an all-or-nothing fetch.

Note that this may not completely fix the first of above downsides, as the consistent view also depends on the server-side.
If the server doesn't have a consistent view of its own references during the reference negotiation phase, then the client would get the same inconsistent view the server has.
This is a separate problem though and, if it actually exists, can be fixed at a later point.

This commit also changes the way we write FETCH_HEAD in case --atomic is passed.

Instead of writing changes as we go, we need to accumulate all changes first and only commit them at the end when we know that all reference updates succeeded.
Ideally, we'd just do so via a temporary file so that we don't need to carry all updates in-memory.
This isn't trivially doable though considering the --append mode, where we do not truncate the file but simply append to it.
And given that we support concurrent processes appending to FETCH_HEAD at the same time without any loss of data, seeding the temporary file with current contents of FETCH_HEAD initially and then doing a rename wouldn't work either.
So this commit implements the simple strategy of buffering all changes and appending them to the file on commit.

fetch-options 现在包含在其 man page 中:

--atomic

Use an atomic transaction to update local refs. Either all refs are updated, or on error, no refs are updated.