使用以下 git 命令有什么区别
git pull origin master
git pull origin master:master
一些观察
1)第一个告诉我是否有任何冲突,但另一个只是说“拒绝 - 非快进”
2)如果失败,第二个不会更新我的远程指针,即原点/主控
这有点棘手,所以让我们一次一点地处理它。
git pull
像这样滚动:
从给定的远程(示例中的第一个参数)获取给定的 refs 1(示例中的第二个参数,称为refspec —“参考规范”的一个端口)。
如果 remote 参数丢失,Git 会尝试使用branch.<name>.remote
本地存储库中的配置变量来获取它,其中<name>
是当前签出分支的名称。
如果缺少 refspec 参数,Git 会尝试使用branch.<name>.merge
本地存储库中的配置变量来获取它,其中<name>
的含义与上述相同。
将所有获取的 ref合并到当前签出的分支,因此 @Oznerol256 不正确。
现在让我们来解释一下 refspecs 之间的区别master
以及master:master
何时git pull
......
git pull
将 refspec 直接传递给git fetch
,并以下列方式解析 refspec:“从远程获取与左侧的规范匹配的所有 refs,:
并可能使用它们来更新本地存储库中的匹配 refs,由规范指定在“的右侧:
。这里的关键是,如果:
refspec 中没有,或者它的右侧没有任何内容,这将被解释为“不更新任何内容” git fetch
。
现在让我们深入挖掘。根据refspecs 的解释规则,裸“master”(在大多数情况下2)被解释为refs/heads/master
,这意味着“名为 «master» 的分支”。
好的,现在应该清楚了git pull origin master
:
从由指示的远程git fetch origin master
获取的调用,并且仅将获取的对象存储在数据库中(加上更新特殊的 ref )。它不会更新本地存储库中的任何分支或标签。refs/heads/master
origin
FETCH_HEAD
git merge FETCH_HEAD
尝试refs/heads/master
将从远程存储库获取的 as 的状态合并到当前签出的分支中的调用。
显然,这可能会导致冲突,这就是您在第一种情况下观察到的。
现在让我们更深入地挖掘。正如现在应该清楚的那样,master:master
refspec (通常2)扩展为refs/heads/master:refs/heads/master
,因此git pull origin master:master
滚动如下:
它调用git fetch origin master:master
哪个
refs/heads/master
从远程获取和 refs/heads/master
通过获取的对象更新本地。
如果本地“主控”未完全包含在远程“主控”中,这可能会因“非快进”错误而失败,这就是您所观察到的。
此时没有尝试合并,因为第一步产生了错误。
应该注意的是,您的两个示例都没有正确更新本地引用:第一个示例只是不尝试此操作,而第二个示例尝试更新所谓的错误引用-正确的调用将git pull origin +refs/heads/master:refs/remotes/origin/master
强制(因此+
)更新正确的远程分支,然后尝试将提取的内容合并到当前签出的分支中。
为了理解为什么会使用这样一个“奇怪”的 refspec,让我们看看 Git 在你调用时使用了什么 refspec——git fetch origin
因为在这种情况下它会读取remote.<remotename>.fetch
本地存储库中的配置变量(这个变量是由git remote add
or创建的git clone
):
$ git config --local --get remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
如您所见,它告诉git fetch
强制更新和更新远程分支。
现在可以看出,git pull
在没有真正了解其内部运作的情况下,它经常被无意识地过度使用。在我看来,最好使用两步操作而不是拉:
git fetch origin
— 更新远程分支。git merge origin/master
— 将上次在“origin”上看到的“master”状态合并到当前签出的分支中。
如果将当前签出的分支设置为跟踪要合并的远程分支,则 Git 调用变得更加简单:
git merge @{u}
我还建议阅读这篇文章。
1 Git 用语中的“ref”是一个命名实体,它指向一个提交(简单或直接 ref)或另一个 ref(符号 ref —HEAD
是符号 ref)。分支和标签是简单引用的示例,HEAD
可能两者兼有:当您签出一个分支时,它是一个符号引用,当您签出其他任何内容时(因此处于“分离的 HEAD”状态),它是一个简单的引用。
2如果有一个标签和一个名为“master”的分支,则 refspec 将被解析为标签的名称——标签具有优先权。在这种情况下,可以使用完整的 ref 名称来指定分支。
Agit pull
固有地执行两个操作:首先, a git fetch
,然后是git merge
。
使用git pull origin master
,master
您的远程分支origin
将被获取(检索),然后合并到您当前的签出分支中。
通过定义两个分支名称,您可以指定将哪个分支合并到哪个分支的refspec 。
通用示例如下:“从指定的远程检索源分支,将其与目标分支合并。
git pull <remote> <source>:<destination>
第一个告诉 gitmaster
从远程拉取分支origin
。它不会告诉 git 将获取的提交合并到哪里。它使用配置中指定的合并键。
第二个告诉 gitmaster
从 remove中拉出分支origin
并将其合并到本地分支master
中。这会覆盖配置中的合并键。