【问题标题】:Why does git fetch origin master:master fast forward the local branch?为什么 git fetch origin master:master 快进本地分支?
【发布时间】:2019-10-30 03:28:50
【问题描述】:

我一直在玩 git 并坚持使用 git fetch 的概念。

我已经尝试并观察到以下场景:

1) $ git fetch

获取所有远程分支并更新所有相应的远程跟踪分支。我知道它查看 .git/config 文件并使用默认远程存储库位置和默认获取 refspec,通常为“refs/heads/:refs/remotes/origin/”。它不会快进任何本地分支。

2) $ git fetch origin

观察与 1) 相同

3) $ git fetch origin master

仅获取 master 分支并更新远程跟踪分支 origin/master。不快进本地 'master' 分支。

4) $ git fetch origin master:master

仅获取 master 分支并更新远程跟踪分支 origin/master。快进本地“master”分支。

理解 1) 和 2) 很简单。然而 3) 和 4) 让我感到困惑。

fetch 命令对本地分支有什么作用?为什么它快进本地分支? (影响本地分支的证明是当我尝试git fetch origin master:master时,在签出master分支时,它会抛出以下错误:fatal: Refusing to fetch into current branch refs/heads/master of non-bare repository

根据我的直觉,在任何类型的 fetch 命令上,更新远程跟踪分支都是默认行为。然而,当git fetch origin master 被执行时,它具有更新FETCH_HEAD 的附加行为。当git fetch origin master:master 被执行时,它有一个更新本地分支'master'的附加行为。我的直觉对吗?

它是否将git fetch origin master:master 解释为git fetch origin refs/heads/master:refs/heads/master? (可能对我之前的问题是多余的)

它是否将git fetch origin master 解释为git fetch origin refs/heads/master:

【问题讨论】:

    标签: git version-control git-fetch


    【解决方案1】:

    RomainValeri's answer大部分正确,但遗漏了一些内容。

    首先,我们必须注意一个关于 1.8.4 之前的 Git 版本的特殊情况。 The 1.8.4 release notes 提一下

    • “git fetch origin master”不同于“git fetch origin”或“git fetch” 没有更新“refs/remotes/origin/master”;这是一个早期的 设计决策以保持远程跟踪分支的更新 可预测的,但在实践中,人们发现它更多 方便我们有机会随时更新它们 机会,我们在运行“git push”时一直在更新它们 反正已经打破了原来的“可预测性”。

    因此:

    git fetch origin master
    

    在 Git 1.8.3 及更早版本中表现不同。在 1.8.4 及更高版本中,这会更新 refs/remotes/origin/master(默认情况下,但它取决于您的默认 fetch refspecs)。

    对 refspec 的描述是正确的,但缺少一项:一般的语法是:

    • 可选的前导加号 + 表示 --force(仅适用于本特定的参考规范);
    • 源参考;
    • 分隔符:;和
    • 目的地参考。

    源和目标都可以是完全限定的,例如,refs/heads/master,或者不是,例如,master。如果你使用不合格的变体,Git 会找出完全合格的拼写。

    通常,源和目标中的任何一个(或有时甚至两者)都可以省略。对于git fetchgit push,这样的refspec 的含义是不同的。省略源需要包含冒号,而省略目标也可以省略冒号。那就是:

    • master:master,或branch1:branch2,或tag:tag等,都提供源和目标。
    • master 是没有目的地的来源。
    • master: 也是没有目的地的来源。
    • :master 是没有来源的目的地。这仅对 git push 有效,这意味着 要求其他 Git 删除他们的引用
    • : 表示源和目标都被省略。这仅对git push 有效,这意味着找到匹配的分支名称并推送它们

    忽略git push,然后我们只允许源和目标,如master:origin/mastermaster:master,或无目标的源,如mastermaster:。所以只有两种情况:

    1. 您提供了来源,但没有提供目的地。 git fetch 不会更新任何名称,除了 Git 自 1.8.4 起将机会性地更新任何 remote-tracking 默认提取 refspec 中指定的名称。因此,如果您的 Git 至少为 1.8.4,git fetch origin master 会更新您的 origin/master,这是您的 Git 远程跟踪名称,用于 origin 的 Git 的 master

    2. 您提供了源和目标。 git fetch 将尝试更新目标名称。如果您没有设置强制标志——无论是全局标志还是领先的+——此更新必须是快进的。如果您没有指定--update-head-ok,则目的地也不能是当前分支。1 无论如何,如果您的 Git 是 1.8.4 或更高版本,您的 Git 将适时更新远程跟踪源名称的名称。

    注意:

    git fetch origin
    

    (在命令行上不指定参考规范)将使用您配置中的默认参考规范。假设这是 origin,请参阅 git config --get-all remote.origin.fetch 以查看这些默认参考规范。


    1在我认为相当于一个错误的情况下,这里的测试,对于 branch is check-out,只测试 main 工作-tree的HEAD。如果当前在添加的工作树中签出分支,则添加的工作树的索引和工作树不再与其分支同步。另请参阅 Why does Git allow pushing to a checked-out branch in an added worktree? How shall I recover? — 该错误在 fetch 和 push 中是对称的。

    【讨论】:

    • 非常感谢!我曾多次阅读--update-head-ok 段落,但不确定它的预期效果。除此之外,我还忽略了配置部分。
    【解决方案2】:

    更新匹配的本地引用当您在<refspec> 中明确提及目标时的预期行为。

    格式:

    git fetch [options] <remote> <refspec>
    

    refspec 采用的形式

    <src>:<dst>
    

    (显然,对于“源”和“目的地”)

    据说in the manual那个

    获取匹配&lt;src&gt; 的远程引用,如果&lt;dst&gt; 不是空字符串,则尝试更新与其匹配的本地引用。

    你也可以看看this paragraph上面这个具体的语法。


    并回答附带问题:

    但是,当git fetch origin master 被执行时,它具有更新FETCH_HEAD 的附加行为。当git fetch origin master:master 被执行时,它具有更新本地分支'master'的附加行为。我的直觉对吗?

    不完全是。如果&lt;refspec&gt; 不是&lt;src&gt;:&lt;dst&gt;,则给定名称将被视为&lt;src&gt;,因此当您使用git fetch origin master 时,它与@987654336 相同@。 FETCH_HEAD 用于内部,即git pull 的内部,可用于编写脚本,但您无需为日常 git 使用而烦恼。

    “它是否将 git fetch origin master:master 解释为 git fetch origin refs/heads/master:refs/heads/master?(可能对我之前的问题是多余的)”

    是的。

    它是否将git fetch origin master 解释为git fetch origin refs/heads/master:

    ,如果&lt;refspec&gt;&lt;dst&gt; 侧为空,则根本不会更新任何内容,因为您没有指向任何内容。 (不要与上面提到的省略 : 本身的情况相混淆。有趣的是,相反的 :my-branch 正在删除 my-branch,因为它已使用 void ref 更新)

    【讨论】:

    • 如果git fetch origin mastergit fetch origin master:master一样,那为什么不更新本地分支呢?
    猜你喜欢
    • 2016-07-12
    • 2021-04-04
    • 2016-10-06
    • 2019-09-18
    • 2018-05-20
    • 2018-09-21
    • 2015-05-15
    • 2014-01-18
    • 2011-09-28
    相关资源
    最近更新 更多