错误信息来自builtin/fetch.c#check_not_current_branch()。
该函数一直追溯到commit 8ee5d73, Oct. 2008, git 1.6.0.4
评论很有启发性:
一些令人困惑的教程建议获取
进入当前分支,如下所示:
git fetch origin master:master
(或者更糟糕的是:使用“pull”而不是“fetch”的同一命令行)。
虽然存储您想要提取的内容可能是有意义的,但通常是
当前分支为“master”时,完全错误。
仅当(不正确的)“git pull origin master:master”试图通过将--update-head-ok 提供给底层“git fetch”来解决此问题时才应允许这样做,否则我们应该拒绝它,但在某些地方我们失去了这种行为。
当前分支的检查现在只在非裸机中执行
存储库,这是对原始行为的改进。
考虑到函数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
默认情况下 git fetch 拒绝更新当前分支对应的头部。此标志禁用检查。
这纯粹是供git pull 与git fetch 通信的内部使用,除非您正在实现自己的Porcelain,否则您不应该使用它。
即使您不应该使用该选项,但它确实满足了您的初始要求,使“git fetch origin branch:branch”在当前分支上工作。
关于这个补丁的来源,follow the discussion there。
虽然存储您想要提取的内容可能很有意义
这是fetch 部分:它存储来自更新的origin/master 的远程历史记录。
但是,当当前本地分支也是 master 时,这一点尤其被打破。
如前所述in this answer:
当master 是当前分支时,我认为“git fetch url side:master”
并且我们省略了--update-head-ok 已损坏。
测试在当前master 上失败。
它也将无法更新工作目录并离开
索引就像你要删除所有东西一样。
以“git pull with refspec”为例。
torek 显示了一个示例,其中:
假设我运行 git fetch 并引入了两个新提交,我将标记为 C 和 D。
C 的父级是 A,D 的父级是B 之前的节点:
C
/
...--o--o--A <-- master
\
o--B <-- develop
\
D
此 git fetch 的输出将其列为:
aaaaaaa..ccccccc master -> origin/master
+ bbbbbbb...ddddddd develop -> origin/develop (forced update)
如果您当前的分支不是develop,那么强制更新可能就是您想要的。
但是如果您在输入git fetch origin develop:develop 时开启 develop,并且如果允许获取更新HEAD,...那么您当前的索引将反映D,而不再是@987654377 @.
因此,在您的工作树中完成 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) 在合并图层时检测到多次记录的同一提交时,它过去会死掉。
代码现在忽略除其中一个之外的所有代码并继续,在 Git 2.30(2021 年第一季度)中修复。
参见Derrick Stolee (derrickstolee) 的commit 85102ac、commit 150f115(2020 年 10 月 9 日)。
(由 Junio C Hamano -- gitster -- 合并到 commit 307a53d,2020 年 11 月 2 日)
报告人:Thomas Braun
帮助人:Taylor Blau
合着人:Jeff King
签字人:Derrick Stolee
Thomas reported 表示“git fetch”(man) 命令失败并显示“意外的重复提交 ID”错误。
$ git fetch origin +refs/head/abcd:refs/remotes/origin/abcd
致命:意外的重复提交 ID
31a13139875bc5f49ddcbd42b4b4d3dc18c16576
根本原因是他们启用了fetch.writeCommitGraph,这会生成commit-graph链,而这个实例正在合并两个包含相同提交ID的层。
最初的假设是,如果提交 ID 已经存在于较低的 commit-graph 层中,Git 不会将提交 ID 写入到 commit-graph 层中。
不知何故,这个特定案例确实陷入了这种情况,导致了这个错误。
虽然出乎意料,但这实际上并不是无效的(只要两层就提交的元数据达成一致)。当我们解析在commit_graph_data_slab, 中没有graph_pos 的提交时,我们在commit-graph 层中使用二进制搜索来查找提交并设置graph_pos。
在这种情况下,该位置不再使用。但是,当我们从 commit-graph 文件解析提交时,我们会从 commit-graph 加载其父项并在此时分配 graph_pos。
如果这些父母已经从commit-graph 中解析出来,那么什么都不需要做。否则,这个graph_pos 是commit-graph 中的有效位置,因此我们可以在必要时解析父母。
因此,这个die() 太激进了。最简单的做法是忽略重复项。
如果我们只忽略重复项,那么我们将生成一个在相邻位置列出的具有相同提交 ID 的提交图。这些多余的数据永远不会从commit-graph 中删除,这可能会级联成显着膨胀的文件大小。
谢天谢地,我们可以折叠列表以删除重复的提交指针。这使我们能够获得我们想要的最终结果,而无需额外的内存成本和最少的 CPU 时间。
根本原因是由于禁用了core.commitGraph,这会阻止在“git commit-graph write --split(man)”命令期间解析来自较低层的提交。
由于我们使用 'graph_pos' 值来确定提交是否在较低层,我们永远不会发现这些提交已经在 commit-graph 链中并将它们添加到顶层。然后将该层向下合并,创建副本。
t5324-split-commit-graph.sh 中添加的测试在没有此更改的情况下失败。但是,我们还没有完全消除这种重复检查的需要。这将在后续更改中出现。
还有:
报告者:Thomas Braun
帮助者:Jeff King
帮助者:Taylor Blau
签字人:Derrick Stolee
core.commitGraph 配置设置可以设置为“false”以防止解析来自commit-graph 文件的提交。这会在尝试使用“--split”进行写入时导致问题,需要区分现有commit-graph 层中的提交和不存在的提交。
现有机制使用parse_commit(),然后检查是否有“graph_pos”表明提交是从commit-graph 文件中解析的。
core.commitGraph=false 时,我们不解析来自commit-graph 的提交,而“graph_pos”表示现有文件中没有提交。
--split 逻辑向前移动,在顶部创建一个新层来保存所有可访问的提交,然后可能向下合并到这些层中,从而导致重复提交。之前的更改使合并过程对这种情况更加稳健,以防它发生在写入的commit-graph 数据中。
这里的简单答案是如果禁用读取提交图,则避免写入commit-graph。因为生成的commit-graph 将不会被后续的 Git 进程读取。这比在“write”进程中强制core.commitGraph 成为true 更自然。
git commit-graph 现在包含在其man page 中:
根据 packfiles 中的提交写一个commit-graph 文件。如果
配置选项core.commitGraph 被禁用,则此命令将
输出警告,然后返回成功而不写入commit-graph 文件。