git-pull调用中不同refspec之间的区别

时间:2013-09-13 10:29:08

标签: git git-pull

使用以下git命令之间的区别是什么

  

git pull origin master
  git pull origin master:master

一些观察

1)第一个告诉我是否有任何冲突,但另一个只是说“拒绝 - 非快进”

2)第二个没有更新我的远程指针,如果它失败则来源/主

3 个答案:

答案 0 :(得分:4)

这有点棘手,所以让我们一次处理一下。

git pull就像这样滚动:

  1. 获取给定的refs 1 (示例中的第二个参数,称为 refspec - 来自“参考规范”的portmaneu) remote(示例中的第一个参数)。

    如果缺少远程参数,Git会尝试使用本地存储库中的branch.<name>.remote配置变量来获取它,其中<name>是当前已检出分支的名称。

    如果缺少refspec参数,G​​it会尝试使用本地存储库中的branch.<name>.merge配置变量来获取它,其中<name>表示与上面相同的内容。

  2. 所有提取的引用合并到当前签出的分支,因此@ Oznerol256不正确。

  3. 现在让我们解释一下引用master时refspec master:mastergit pull之间的区别......

    git pull将refspec直接传递给git fetch,并按以下方式解析refspec:“从远程获取与:左侧的规范匹配的所有引用并且可能使用它们来更新本地存储库中的匹配引用,:右侧的规范指定。这里的关键点是,如果refspec中没有:,或者右边没有任何内容,则git fetch将其解释为“不更新”。

    现在让我们深入挖掘。根据{{​​3}},裸“master”(在大多数情况下 2 )被解释为refs/heads/master,这意味着“名为«master»的分支”。

    好的,现在应该清楚git pull origin master

    1. 调用git fetch origin masterrefs/heads/master指示的遥控器中取出origin,只是将获取的对象存储在数据库中(并更新特殊引用FETCH_HEAD )。它不会更新本地存储库中的任何分支或标记。

    2. 调用git merge FETCH_HEAD尝试将从远程存储库中获取的refs/heads/master状态合并到当前已检出的分支中。

      显然,这可能会导致冲突,而这正是你在第一种情况下所观察到的。

    3. 现在让我们更深入地挖掘。现在应该清楚,master:master refspec(通常是 2 )扩展为refs/heads/master:refs/heads/master,因此git pull origin master:master会像这样滚动:

      1. 它会调用git fetch origin master:master

        1. 从遥控器和
        2. 获取refs/heads/master
        3. 通过提取的对象更新本地 refs/heads/master

          如果本地“主”并非完全包含在遥控器的“主”中,则可能会因“非快进”错误而失败,而这正是您所观察到的。

      2. 此时未尝试合并,因为第一步产生了错误。

        应该注意的是,你的示例正确都没有更新本地引用:第一个只是没有尝试这个,第二个试图更新一个假定的错误引用 - 正确的调用将是{em>强制(因此git pull origin +refs/heads/master:refs/remotes/origin/master+更新正确的远程分支,然后尝试将提取的内容合并到当前签出的分支中

        要理解为什么使用这种“奇怪的”refspec,让我们看看Git在调用git fetch origin时使用的refspec - 因为在这种情况下它会读取本地存储库中的remote.<remotename>.fetch配置变量(这变量由git remote addgit clone)创建:

        $ git config --local --get remote.origin.fetch
        +refs/heads/*:refs/remotes/origin/*
        

        如您所见,它告诉git fetch强制更新并更新远程分支。

        现在可以看出,git pull在没有真正理解其内部运作的情况下经常被无意识地过度使用。在我看来,使用两步操作而不是拉动更好:

        1. git fetch origin - 更新远程分支。
        2. git merge origin/master - 将“origin”上的“master”状态合并到当前已检出的分支中。

          如果当前签出的分支设置为跟踪您要合并的远程分支,则Git调用变得更加简单:

          git merge @{u}
          
        3. 我还建议您阅读rules of interpretation of refspecs


          1 Git用语中的“ref”是名为的实体,它指向提交(简单或直接引用)或另一个引用(符号引用 - { {1}}是一个象征性的参考)。分支和标签是简单引用的示例,HEAD可能是两者:当你有一个分支检出它是一个符号引用,当你有其他任何检出(因此处于“分离的HEAD”状态)它是一个简单的参考。

          2 如果有一个标签和一个名为“master”的分支,则refspec将被解析为标签的名称 - 标签具有优先权。在这种情况下,可以使用完整的引用名称来指定分支。

答案 1 :(得分:0)

第一个告诉git从远程master拉出分支origin。它没有告诉git将获取的提交合并到哪里。它使用配置中指定的合并密钥。

第二个告诉git从remove master中提取分支origin并将其合并到本地分支master中。这会覆盖配置中的合并密钥。

答案 2 :(得分:0)

git pull固有地执行两项操作:首先是git fetch,然后是git merge

使用git pull origin master,您的master遥控器的origin分支将被提取(检索),然后合并到您当前的签出分支。

通过定义两个分支名称,您指定合并到哪个分支的refspec

通用示例如下所示:“从指定的远程控制器检索源分支,将其与目标分支合并。

git pull <remote> <source>:<destination>