【问题标题】:Using colon in `git pull origin <remote-branch> : <local-branch>` does not pull to correct branch?在 `git pull origin <remote-branch> : <local-branch>` 中使用冒号不会拉到正确的分支?
【发布时间】:2015-11-15 20:02:39
【问题描述】:

假设我在一个与&lt;local-branch&gt; 不同的分支上,称为&lt;different-branch&gt;

当我尝试从远程分支拉到本地分支时,我会执行以下操作:

git pull origin <remote-branch>:<local-branch>

而且,据我了解,这应该拉入我的&lt;local-branch&gt;,而拉入&lt;different-branch&gt;

但是,当我在&lt;different-branch&gt; 上检查git log 时,我看到这些提交来自&lt;remote-branch&gt;

当本地分支与我当前所在的分支不同时,如何从远程分支拉入本地分支?谢谢你。

【问题讨论】:

  • 冒号周围的空格是否包含在内?因为那些不应该在那里。

标签: git github version-control git-merge git-pull


【解决方案1】:

在 refspec 中使用 git pull 不会影响 pull 命令的合并部分。您可能知道,git pull 本质上只是git fetchgit merge 的组合;首先,它将从远程获取最新的更改并更新远程跟踪分支,然后将远程跟踪分支合并到当前分支

现在,正如我所说,refspec 不会影响合并部分,但它只会影响git pull 内部的获取。现在要了解这最终意味着什么,您首先必须了解 refspec 是什么。

refspec 基本上只是远程分支映射到远程跟踪分支的配置。远程分支在这里是远程实际存在的分支,远程跟踪分支是为了跟踪远程分支的状态而创建的分支;对于名为“origin”的远程,其远程跟踪分支都以origin/开头。

如果您没有明确指定 refspec,它会从配置文件中获取。默认表单通常如下所示:

+refs/heads/*:refs/remotes/origin/*

这告诉 Git 获取位于 refs/heads/* 的远程分支并将它们映射到位于 refs/remotes/origin/* 的远程跟踪分支。所以对于远程分支masterrefs/heads/master 将映射到refs/remotes/origin/master。领先的 + 还告诉 Git 覆盖远程跟踪分支,无论更改是否可以快进:毕竟,您通常希望远程跟踪分支与 完全远程状态,所以如果历史记录在那里被重写(应该避免)或分支被重命名,你会希望远程跟踪分支仍然尊重这一点。

现在,当您指定 refspec(使用 git fetchgit pull)时,默认映射将被覆盖。而是使用您的映射。例如,当您使用git fetch origin master:foo 时,本地分支foo 将被快速转发(如果可能)以指向远程分支master。所以这实际上是更新本地分支的好方法,而不必检查它:如果你遗漏了领先的+,那么如果它不是快进合并,那么更新本地引用(分支)将失败,所以你也可以安全地避免冲突。

但是回到git pull——当你运行命令时发生了什么?正如我所说,拉动只是获取和合并,因此您的 git pull 命令首先执行此操作:

git fetch origin <remote-branch>:<local-branch>

所以从远程获取远程分支,并更新本地分支——如果是快进合并的话。这已经完全符合您的要求:更新&lt;local-branch&gt;

然后,git pull 的合并部分发生了;为此,Git 通常会运行 git merge FETCH_HEADFETCH_HEAD 是对最后获取的分支的引用。在这种情况下,它指向&lt;local-branch&gt;。所以在获取到&lt;local-branch&gt; 之后,正在执行的命令是git merge &lt;local-branch&gt;。并且运行git merge 将合并到当前分支

因此,当您在 &lt;different-branch&gt; 并运行 git pull origin &lt;remote-branch&gt;:&lt;local-branch&gt; 时,您将正确更新 &lt;local-branch&gt; 以匹配远程分支,但随后您还将这些更改合并到当前分支 &lt;different-branch&gt;。这就是为什么你会在当前分支的日志中看到那个分支的变化;它们只是简单地合并了。

如果您想避免这种情况,按照我上面的解释,只需将git fetch 与 refspec 一起使用。它已经正确地更新了本地分支(如果可以的话)而不影响当前分支。

【讨论】:

  • 感谢您的回答。当你说“在这种情况下,它指向 。所以在获取到 之后,正在执行的命令是 git merge 。运行 git merge 将合并到当前分支。” ....这里&lt;local branch&gt; 是什么?您是否将远程跟踪分支与本地分支合并?如果是这样,您如何使用 refspec 做到这一点?
  • 我想我的部分困惑是......什么时候使用冒号,什么时候只使用空格?例如git fetch origin &lt;remote-branch&gt;:&lt;local-branch&gt;git merge origin &lt;remote-branch&gt; &lt;local-branch&gt;?
  • 通常,除非您明确想要获取到不同的本地跟踪分支,否则您永远不应该手动使用 refspec。如果您遇到默认 refspec 不合适的情况,您应该调整配置。所以你可能永远不需要 fetch 的 refspec。对于 pull,永远不要使用它,因为它不会达到您的预期。
  • 问题在于 refspec 似乎假定您的本地和远程分支将始终使用相同的名称。如果有人远程更改了其中一个分支名称,但您想保留本地名称,那么您需要手动使用 refspec,例如:git fetch origin &lt;remote name&gt;:&lt;local name&gt;git checkout &lt;local name&gt;git merge remotes/origin/&lt;local name&gt;。对吗?
  • 通常,您只会使用 git fetch 而不使用 refspec,这已经获取了所有远程分支。如果一个分支在远程被重命名(这有点罕见),你可以更新你的本地分支来跟踪那个新分支:git branch -u origin/new_remote。这将更新当前分支以跟踪远程上的new_remote。那么你可以在没有任何参考规范的情况下使用git pushgit pull 用于该分支。
【解决方案2】:

你总是可以去低科技:

git fetch origin #fetches all the remote branches
git checkout <local-branch>
git merge origin/<remote-branch>

或者如果你练习 rebase pulls

git rebase -i origin/<remote-branch> <local-branch>

【讨论】:

  • 我猜你的意思是remotes/origin/&lt;remote-branch&gt;而不是origin/&lt;remote-branch&gt;,对吧?
  • @Candic3 任何适合你的东西。通常'origin'就足够了。
【解决方案3】:

如果您也想跟踪远程分支,您可以使用以下命令:

git checkout --track -b local-branch origin/remote-branch

如果远程分支是在您上次提取后创建的,您可能需要先运行 git fetch

【讨论】:

    猜你喜欢
    • 2018-10-18
    • 2018-10-07
    • 2015-01-20
    • 2013-05-04
    • 2020-04-12
    • 2012-04-17
    • 2015-10-03
    • 2018-07-05
    • 1970-01-01
    相关资源
    最近更新 更多