执行'git fetch-upstream-master:master'与'git-pull-upstream-master:master'的确切区别是什么`
我知道执行'git fetch-upstream-master:master'与'git-pull-upstream-master:master'的确切区别是什么`,git,git-pull,git-fetch,Git,Git Pull,Git Fetch,我知道git-fetch和git-pull之间的区别git pull基本上是一个git fetch+git merge命令 然而,我正在研究如何在不签出主分支的情况下使用上游更新我的fork(主分支)。我遇到了这样的答案- 但当我在master上签出后使用git-fetch-upstream-master:master时,我遇到了这个错误- fatal: Refusing to fetch into current branch refs/heads/master of non-bare rep
git-fetch
和git-pull
之间的区别git pull
基本上是一个git fetch
+git merge
命令
然而,我正在研究如何在不签出主分支的情况下使用上游更新我的fork(主分支)。我遇到了这样的答案-
但当我在master上签出后使用git-fetch-upstream-master:master
时,我遇到了这个错误-
fatal: Refusing to fetch into current branch refs/heads/master of non-bare repository
所以,我尝试了git-pull-upstream-master:master
,结果成功了。有趣的是,无论我是否在master上,使用git-pull-upstream-master:master
都会用upstream更新我的fork。而git-fetch-upstream-master:master
仅在我不在master分支上时工作
这将是非常有趣的阅读解释,从知识渊博的人在这里
git pull
基本上是一个git fetch
+git merge
命令
是的,但是,正如你所怀疑的,事情远不止这些
,在您链接到的答案中,实际上有一个关键项。他提到你可以:
使用fetchoriginbranchb:branchB
,如果合并不是快进的,它将安全地失败
另一个没有很好的文档记录:它是git fetch
中的-u
aka-updateheadok
选项,它设置了git pull
。确实定义了它的功能,但有点神秘和可怕:
默认情况下,git fetch拒绝更新对应的头
到当前分支。此标志将禁用检查。这纯粹是
对于git pull与git fetch通信的内部使用,
除非你正在实现你自己的瓷器,否则你不会
我应该用它
这让我们了解您的观察:
所以,我尝试了git拉上游master:master
,它成功了。有趣的是,无论我是否在master上,使用git-pull-upstream-master:master
都会用upstream更新我的fork。然而,git-fetch-upstream-master:master
仅在我不在master分支上时工作
这是由于-u
标志。若您运行了git-fetch-upstream-master:master
,从某种意义上讲,这是可行的,但会给您带来一个不同的问题。警告的存在是有原因的。让我们看看原因是什么,看看警告是否过于严厉。警告:这里有很多!下面的许多复杂性是为了弥补历史错误,同时保留向后兼容性
分支名称、引用和快进
首先,让我们谈谈引用和快进操作
在Git中,引用只是谈论分支名称(如master
)或标记名称(如v1.2
),或远程跟踪名称(如origin/master
),或任何数量的其他名称的一种奇特方式,所有这些名称都以一种常见且合理的方式进行:我们将每种特定的名称分组为一组。分支名称位于refs/heads/
下,标记名称位于refs/tags/
下,等等,因此master
实际上就是refs/heads/master
这些名称中的每一个都以refs/
开头,都是一个参考。还有一些额外的引用也不是以refs
开头的,尽管Git在决定HEAD
和ORIG\u HEAD
和MERGE\u HEAD
等名称是否真的是引用时内部有点不稳定,引用主要用于为Git对象哈希ID提供有用的名称。分支名称特别有一个有趣的特性:它们从一个提交移动到另一个提交,通常以Git称为快进的方式
也就是说,给定一个包含一些提交的分支(此处用大写字母表示),以及一个包含更多提交(包括第一个分支上的所有提交)的第二个分支:
...--E--F--G <-- branch1
\
H--I <-- branch2
如果我们将名称branch1
移动到指向commitI
而不是commitJ
,commitJ
本身会发生什么情况?3这种移动会留下commit,是对分支名称的非快进操作
这些名称可以通过省略refs/
部分来缩短,或者通常,甚至可以省略refs/heads/
部分或refs/tags/
部分或任何内容。Git将使用中描述的六步规则在其引用名称数据库4中查找第一个匹配的数据库。例如,如果您有一个refs/tags/master
和一个refs/heads/master
,并且说master
,Git将首先匹配refs/tags/master
,然后使用标记。5
1如果引用是具有或可以具有reflog的名称,则
HEAD
是引用,而ORIG\u HEAD
和其他*\u HEAD
名称不是引用。不过,这里的边缘有点模糊
2可以通过更多名称访问这些提交。重要的是,在快进之前无法通过branch1
访问它们,而在快进之后才能访问它们
3直接的答案实际上是什么都没有发生,但最终,如果无法通过某个名称访问commitI
,Git将对commit进行垃圾收集
4这个“数据库”实际上只是目录.git/refs
和文件.git/packed refs
的组合,至少目前是这样。如果Git同时找到一个文件条目和一个路径名,则路径名的散列将覆盖压缩引用文件中的散列
5异常:git checkout
将参数作为br进行尝试
...--E--F--G------J <-- branch1
\
H--I <-- branch2
$ git rev-parse master
468165c1d8a442994a825f3684528361727cd8c0
$ git checkout master
Switched to branch 'master'
$ cat .git/HEAD
ref: refs/heads/master
$ git checkout --detach master
HEAD is now at 468165c1d... Git 2.17
$ cat .git/HEAD
468165c1d8a442994a825f3684528361727cd8c0
$ git status
... nothing to commit, working tree clean
$ git rev-parse master^
1614dd0fbc8a14f488016b7855de9f0566706244
$ echo 1614dd0fbc8a14f488016b7855de9f0566706244 > .git/refs/heads/master
$ git status
...
Changes to be committed:
...
modified: GIT-VERSION-GEN
$ echo 468165c1d8a442994a825f3684528361727cd8c0 > .git/refs/heads/master
$ git status
...
nothing to commit, working tree clean
git fetch --update-head-ok upstream master:master
git merge -m <message> <hash ID extracted from .git/FETCH_HEAD>