gpt4 book ai didi

git - 为什么 "git fetch origin branch:branch"只适用于非当前分支?

转载 作者:IT王子 更新时间:2023-10-29 00:52:58 24 4
gpt4 key购买 nike

在处理功能分支时,我使用此 Git 命令将我的“开发”分支更新到最新状态,然后立即将我的功能分支与“开发”分支 merge :

git fetch origin develop:develop

这行得通,即本地“develop”指向与“origin/develop”相同的提交,并且处于 origin 的最新状态。

但是,不知何故,当 checkout “develop”分支时,此命令失败:

fatal: Refusing to fetch into current branch refs/heads/develop of non-bare repository
fatal: The remote end hung up unexpectedly

如果我知道为什么会这样,那将有助于我更好地理解 Git。

最佳答案

错误信息来自builtin/fetch.c#check_not_current_branch() .
该函数一直追溯到 commit 8ee5d73, Oct. 2008, git 1.6.0.4 .
(另请参阅“Git refusing to fetch into current branch ”)。

评论很有启发性:

Some confusing tutorials suggested that it would be a good idea to fetchinto the current branch with something like this:

git fetch origin master:master

(or even worse: the same command line with "pull" instead of "fetch").
While it might make sense to store what you want to pull, it typically isplain wrong when the current branch is "master".
This should only be allowed when (an incorrect) "git pull origin master:master" tries to work around by giving --update-head-ok to underlying "git fetch", and otherwise we should refuse it, but somewhere along the lines we lost that behavior.

The check for the current branch is now only performed in non-barerepositories, which is an improvement from the original behaviour.

考虑到函数 check_not_current_branch()called with :

if (!update_head_ok)
check_not_current_branch(ref_map);

这意味着 git fetch -u origin develop:develop 应该可以工作。

-u
--update-head-ok

By default git fetch refuses to update the head which corresponds to the current branch. This flag disables the check.
This is purely for the internal use for git pull to communicate with git fetch, and unless you are implementing your own Porcelain you are not supposed to use it.

即使您不应该使用该选项,它也确实满足了您的初始要求,使“git fetch origin branch:branch”在当前 分支上工作。


关于这个补丁的来源,follow the discussion there .

While it might make sense to store what you want to pull

那是 fetch 部分:它存储来自更新后的 origin/master 的远程历史。
但当当前本地分支也是 master 时,这种情况尤其严重。
如前所述 in this answer :

I think "git fetch url side:master" when master is the current branchand we have omitted --update-head-ok is broken.
The test fails on current master.

It would also fail to update the working directory and would leavethe index as if you're removing everything.


以“git pull with refspec”为例。
torek 显示了一个示例,其中:

suppose that I run git fetch and it brings in two new commits that I will label C and D.
C's parent is A, and D's is the node just before B:

                C
/
...--o--o--A <-- master
\
o--B <-- develop
\
D

The output from this git fetch will list this as:

  aaaaaaa..ccccccc  master     -> origin/master
+ bbbbbbb...ddddddd develop -> origin/develop (forced update)

如果您当前的分支不是 develop,那么强制更新可能就是您想要的。
但是,如果您在 develop 时键入git fetch origin develop:develop,并且允许获取更新 HEAD,...那么您当前的索引将反射(reflect) D,而不再是 B
因此,在您的工作树中完成的 git diff 将显示您的文件和 D 之间的差异,而不是您之前的 HEAD B

这很糟糕,因为您最初的 git checkout develop 创建了一个与 B HEAD 文件相同的工作树。
即使你的 git status 是干净的(没有任何类型的修改),如果 git fetch origin develop:develop 更新了 HEAD(强制从 B 更新到 D),git status 现在会报告在获取之前没有差异的地方。

这就是为什么默认情况下 git fetch 拒绝更新对应于当前分支的头部


注意:Git 2.29 中的一个错误也会触发类似的错误消息。

当“git commit-graph( man ) 在 merge 层时检测到同一提交记录不止一次时,它曾经死掉。
该代码现在忽略除其中一个之外的所有内容并继续,已在 Git 2.30(2021 年第一季度)中修复。

参见 commit 85102ac , commit 150f115 (2020 年 10 月 9 日)Derrick Stolee (derrickstolee) .
(由 Junio C Hamano -- gitster -- merge 于 commit 307a53d,2020 年 11 月 2 日)

commit-graph: ignore duplicates when merging layers

Reported-by: Thomas Braun
Helped-by: Taylor Blau
Co-authored-by: Jeff King
Signed-off-by: Derrick Stolee

Thomas reported that a "git fetch"(man) command was failing with an error saying "unexpected duplicate commit id".

$ git fetch origin +refs/head/abcd:refs/remotes/origin/abcdfatal: unexpected duplicate commit id31a13139875bc5f49ddcbd42b4b4d3dc18c16576

The root cause is that they had fetch.writeCommitGraph enabled which generates commit-graph chains, and this instance was merging two layers that both contained the same commit ID.

The initial assumption is that Git would not write a commit ID into a commit-graph layer if it already exists in a lower commit-graph layer.
Somehow, this specific case did get into that situation, leading to this error.

While unexpected, this isn't actually invalid (as long as the two layers agree on the metadata for the commit). When we parse a commit that does not have a graph_pos in the commit_graph_data_slab, we use binary search in the commit-graph layers to find the commit and set graph_pos.
That position is never used again in this case. However, when we parse a commit from the commit-graph file, we load its parents from the commit-graph and assign graph_pos at that point.
If those parents were already parsed from the commit-graph, then nothing needs to be done. Otherwise, this graph_pos is a valid position in the commit-graph so we can parse the parents, when necessary.

Thus, this die() is too aggressive. The easiest thing to do would be to ignore the duplicates.

If we only ignore the duplicates, then we will produce a commit-graph that has identical commit IDs listed in adjacent positions. This excess data will never be removed from the commit-graph, which could cascade into significantly bloated file sizes.

Thankfully, we can collapse the list to erase the duplicate commit pointers. This allows us to get the end result we want without extra memory costs and minimal CPU time.

The root cause is due to disabling core.commitGraph, which prevents parsing commits from the lower layers during a 'git commit-graph write --split(man)' command.
Since we use the 'graph_pos' value to determine whether a commit is in a lower layer, we never discover that those commits are already in the commit-graph chain and add them to the top layer. This layer is then merged down, creating duplicates.

The test added in t5324-split-commit-graph.sh fails without this change. However, we still have not completely removed the need for this duplicate check. That will come in a follow-up change.

和:

commit-graph: don't write commit-graph when disabled

Reported-by: Thomas Braun
Helped-by: Jeff King
Helped-by: Taylor Blau
Signed-off-by: Derrick Stolee

The core.commitGraph config setting can be set to 'false' to prevent parsing commits from the commit-graph file(s). This causes an issue when trying to write with "--split" which needs to distinguish between commits that are in the existing commit-graph layers and commits that are not.
The existing mechanism uses parse_commit() and follows by checking if there is a 'graph_pos' that shows the commit was parsed from the commit-graph file.

When core.commitGraph=false, we do not parse the commits from the commit-graph and 'graph_pos' indicates that no commits are in the existing file.
The --split logic moves forward creating a new layer on top that holds all reachable commits, then possibly merges down into those layers, resulting in duplicate commits. The previous change makes that merging process more robust to such a situation in case it happens in the written commit-graph data.

The easy answer here is to avoid writing a commit-graph if reading the commit-graph is disabled. Since the resulting commit-graph will would not be read by subsequent Git processes. This is more natural than forcing core.commitGraph to be true for the 'write' process.

git commit-graph 现在包含在其 man page 中:

Write a commit-graph file based on the commits found in packfiles. Ifthe config option core.commitGraph is disabled, then this command willoutput a warning, then return success without writing a commit-graph file.

关于git - 为什么 "git fetch origin branch:branch"只适用于非当前分支?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29028696/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com