git - 当本地主分支上没有工作时, git pull --rebase 是否与 git pull 相同?
问题描述
git rebase
我知道和之间的区别在于git merge
将git rebase
一个分支的开头移动到另一个分支的尖端,在那里git merge
创建一个新的提交,代表(即包含或集成)来自另一个分支的分支提交。例如:
由于git pull
等价于git fetch
+ git merge
,并且git pull --rebase
等价于git fetch
+ git rebase
,假设您有一个本地 master 分支和一个远程 master 分支:
- o - o - o - H - A - B - C (master)
\
P - Q - R (origin/master)
头在 C
如果你git pull
最终得到这个:
- o - o - o - H - A - B - C - X (master)
\ /
P - Q - R --- (origin/master)
HEAD 现在将位于 X,这是远程存储库提交历史的提交 R,因为合并提交 (X) 表示(即包含或集成)远程分支的已合并提交历史
另一方面,如果你这样做了git pull --rebase
,你最终会得到这个:
- o - o - o - H - P - Q - R - A' - B' - C' (master)
|
(origin/master)
正如您所看到的,这git pull
与在 C' 处给出 HEAD 不同,后者是本地 master 分支的提交 C,而HEAD 的使用时间是在 R 处。换句话说,提交历史记录的内容与的提交历史的内容,但提交历史中的提交顺序不同git pull --rebase
git pull --rebase
git pull
git pull
git pull --rebase
但是,当您在本地主分支上未完成任何工作时从远程分支拉取时会发生什么:
本地主分支和远程主分支:
- o - o - o - H (master)
\
P - Q - R (origin/master)
HEAD 在 H
如果你git pull
最终得到这个:
- o - o - o - H - X (master)
\ \
P - Q - R --- (origin/master)
HEAD 现在将位于 X,这是 repo 的提交 R,因为合并提交代表已合并的远程分支
另一方面,如果你这样做了git pull --rebase
,你会得到这个吗?:
- o - o - o - H - P - Q - R (master)
|
(origin/master)
意思是 HEAD 在 R 这意味着这与在本地分支上没有完成任何工作时git pull --rebase
相同git pull
解决方案
git pull
运行时git merge
,它既不指定--ff-only
也不指定--no-ff
,除非您特别要求。
[给定提交图]
...--o--o--o--H <-- master (HEAD) \ P--Q--R <-- origin/master
[你建议 git merge,因此 git pull,会产生]
...--o--o--o--H---------X <-- master (HEAD) \ / P--Q--R <-- origin/master
事实并非如此——无论如何,默认情况下并非如此。如果你运行git merge --no-ff origin/master
,你会得到这个结果。如果你运行git merge --ff-only
,或者允许默认操作,你会得到:
...--o--o--o--H
\
P--Q--R <-- master (HEAD), origin/master
Git 称之为快进。当它特别git merge
这样做时,1 Git 将其称为fast-forward merge,尽管没有发生实际的合并:Git 实际上只是在移动分支名称时执行 a git checkout
of commit以使其指向提交(并保留附加到分支名称) .R
master
R
HEAD
master
该--no-ff
选项告诉 Git:即使可以,也不要进行快进。 结果是一个新的合并提交(或者一个错误,或者其他任何可能出错的地方,当然)。该--ff-only
选项告诉 Git:如果你可以快进,那就去做;如果没有,不要做任何事情,只是出错。
git pull
运行后,您git merge
将获得相同的选项集。如果快进是 (a) 可能的并且 (b) 允许的,则结果与 a 的结果git merge
相同git rebase
:名称master
将被更新,并且提交图中的任何内容都不会发生任何变化。如果快进是不可能的,或者被禁止--no-ff
了,则 a 的结果与 a 的结果git merge
不同,git rebase
因为有一个新的合并提交X
。
新合并提交的内容(保存的快照)与提交的内容相X
匹配R
。但是由于R
和X
是不同的提交,它们具有不同的哈希 ID,后续 Git 操作的行为也会有所不同。
1两者都git push
可以git fetch
对通过 refspecs 更新的引用执行此操作。当git push
以快进方式移动服务器的分支时,您通常看不到任何特别之处。当git push
无法以这种方式移动分支时,您通常会收到服务器的拒绝。注释,而git fetch
不是! rejected (non-fast-forward)
,是(forced update)
。(嗯,这是三个 (!)git fetch
注释之一。)请参见下面的示例。
我想在这里强调的是,快进是标签运动的一个属性。H
如果在动议之前确定的提交(在这种情况下是提交)是要在之后确定的提交的祖先,即 commit ,则快进是可能的R
。
这是一个非快进获取更新的示例。我有一个用于 Git 的 Git 存储库的本地克隆。上游分支之一被命名pu
,代表建议更新。这个分支会定期重绕并用新的提交重建:有人提出了一些新特性,写了第一个尝试,然后进行测试。错误被发现,功能被重新设计,进入的提交被丢弃,有利于进入pu
分支的新改进。所以我的origin/pu
将被强制更新:
$ git fetch
remote: Counting objects: 509, done.
remote: Compressing objects: 100% (214/214), done.
remote: Total 509 (delta 325), reused 400 (delta 295)
Receiving objects: 100% (509/509), 468.38 KiB | 1.52 MiB/s, done.
Resolving deltas: 100% (325/325), done.
From [url]
d8fdbe21b5..95628af9bb next -> origin/next
+ b6268ac8c6...465df7fb28 pu -> origin/pu (forced update)
8051bb0ca1..f0bab95d47 todo -> origin/todo
$
请注意,我的 Git 更新了 my origin/next
、 myorigin/pu
和 my origin/todo
. 其中两个更新是快进操作:例如,提交d8fdbe21b5
(my old origin/next
) 是95628af9bb
(my updated origin/next
) 的祖先。只是b6268ac8c6
,我老了origin/pu
,已经不是祖宗了465df7fb28
。我的 Git 更新了我origin/pu
的无论如何,失去了提交的访问权限b6268ac8c6
(通过 reflogs 除外)。
为了宣布这一事实,git fetch
:
+
以;为前缀- 在更新中打印三个点,而不是两个;和
(forced update)
在行尾添加。
因为这些更改是origin/next
快进操作,所以我的 Git 对它们只字未提。origin/todo
推荐阅读
- .net-core - .Net Core 3 自包含的单个可执行文件可以反编译吗?
- javascript - 将 React 提供程序函数添加到全局窗口对象
- html - 使用 BeautifulSoup 抓取网页时无法在 a 标签内显示文本
- javascript - 如何将搜索引擎条目保存到 csv 文件
- pandas - 带有 IntEnum 的 pandas value_counts() 引发 RecursionError
- python - Confusion Matrix-Sklearn 0.22 数字格式错误
- swift - 在 Firebase Crashlytics 中未收到崩溃报告
- c# - 将值分配给 3D 列表无法正常工作
- c# - 小游戏二十一点
- python - 基于跨列的多个条件有效选择 Pandas 数据框中的行