当在本地master分支上未完成任何工作时,git pull --rebase是否与git pull相同?

时间:2019-06-12 21:46:12

标签: git merge git-merge git-rebase git-pull

我了解到git rebasegit merge之间的区别在于git rebase将分支的开头移到另一个分支的尖端,其中git merge会创建一个新的表示(即包括或集成)来自另一个分支的分支提交的提交。例如:

由于git pull等效于git fetch + git merge,而git pull --rebase等效于git fetch + git rebase,因此假设您有一个本地主分支和远程主分支:

- o - o - o - H - A - B - C (master)
               \
                P - Q - R (origin/master)

HEAD在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 pullgit pull --rebase不同,因为git pull --rebase在HEAD的C'处给HEAD,这是本地主分支的提交C,而{{1} }的使用是HEAD在R处。换句话说,通过git pull提交历史的内容与来自git pull的提交历史的内容是相同的,但是提交历史中的提交顺序是

但是当您在本地master分支上未完成任何工作时从远程分支中拉出时会发生什么:

本地主分支和远程主分支:

git pull --rebase

HEAD在H

如果您- o - o - o - H (master) \ P - Q - R (origin/master) 会得到以下结果:

git pull

HEAD现在将位于X(即回购的提交R)处,因为合并提交代表了已合并的远程分支

如果您另一方面做了- o - o - o - H - X (master) \ \ P - Q - R --- (origin/master) ,您是否会得到这个结果?:

git pull --rebase

意味着HEAD位于R处,这意味着- o - o - o - H - P - Q - R (master) | (origin/master) git pull --rebase相同,而在本地分支上没有任何工作

1 个答案:

答案 0 :(得分:2)

git pull运行git merge时,除非您明确要求,否则它既不指定--ff-only也不--no-ff

  

[给出提交图]

...--o--o--o--H   <-- master (HEAD)
               \
                P--Q--R   <-- origin/master
     

[您建议git合并,从而产生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将其称为快进合并,尽管没有实际的合并发生:Git实际上只是执行{{ 1}}提交git checkout,同时移动分支名称R,使其指向提交master(并将R附加到分支名称HEAD)。

master选项告诉Git:即使可以也不要进行快速转发。结果是新的合并提交(或错误,或者其他可能出错的错误)。 , 当然)。 --no-ff选项告诉Git:如果可以进行快进,请执行;如果没有,则什么也不要做,只是出错。

--ff-only运行git pull时,您将获得相同的选项集。如果可以(a)允许(b)进行快进,则git merge的结果与git merge的结果相同:名称git rebase得到更新,里面没有任何内容提交图以任何方式改变。如果快进不可能 或通过master禁止,则--no-ff的结果与git merge的结果不同,因为存在新的合并提交git rebase

新合并提交X内容(保存的快照)与提交X的快照相同。但是,由于RR是不同的提交,因此它们具有不同的哈希ID,并且随后的Git操作将具有不同的行为。


1 Xgit push都可以对通过refspecs更新的引用执行此操作。当git fetch以快进方式移动服务器的分支时,通常没有什么特别的。当git push 不能以这种方式移动分支时,通常会收到服务器的拒绝。 git push注释是git fetch,而不是! rejected (non-fast-forward)。 (好吧,这是三个(!)(forced update)注释之一。)请参见下面的示例。

我在这里要强调的是,快进是标签运动的属性。如果在动作之前识别出的提交(在这种情况下为提交git fetch)是之后要识别的提交的始祖,即提交H,则可以进行快进。

这是一个非快速获取更新的示例。我有一个Git Git存储库的本地克隆。上游的一个分支称为R,代表建议的更新。该分支定期重绕并使用新提交进行重建:有人提出了一些新功能,在其中写了第一个刺,然后进行测试。发现了错误,对功能进行了重新设计,并且放弃了提交的提交,而转而使用了经过改进的新提交pu分支。因此,我的pu将被强制更新:

origin/pu

请注意,我的Git更新了我的$ 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 $ ,我的origin/next和我的origin/pu。其中有两个更新是快进操作:例如,commit origin/todo(我的旧d8fdbe21b5)是origin/next(我的更新95628af9bb)的祖先。但是我的旧origin/next b6268ac8c6不是origin/pu的祖先。无论如何,我的Git更新了我的465df7fb28 ,失去了提交origin/pu的权限(通过引用日志除外)。

要宣布这一事实,b6268ac8c6

  1. 在行的前面加上git fetch;
  2. 在更新中
  3. 打印了三个点,而不是两个;和
  4. 在行尾添加了+

由于对(forced update)origin/next 的更改是快进操作,因此我的Git对此没有多说。