在阅读该git pull
页面时,它给出了以下严厉警告git pull --rebase
:
这是一种潜在的危险操作模式。它改写了历史,当您已经发布了该历史时,这并不是一个好兆头。除非您仔细阅读 git-rebase(1),否则不要使用此选项。
在git rebase
页面中,它提供了很多描述,但没有此类警告。
另外,我看到有人说
git fetch
git rebase
是相同的
git pull --rebase
而其他人则说它们略有不同。
真相是什么?
在阅读该git pull
页面时,它给出了以下严厉警告git pull --rebase
:
这是一种潜在的危险操作模式。它改写了历史,当您已经发布了该历史时,这并不是一个好兆头。除非您仔细阅读 git-rebase(1),否则不要使用此选项。
在git rebase
页面中,它提供了很多描述,但没有此类警告。
另外,我看到有人说
git fetch
git rebase
是相同的
git pull --rebase
而其他人则说它们略有不同。
真相是什么?
事实是它们是不同的。这是一个非常有用的网页,它很好地解释了它:
http://gitolite.com/git-pull--rebase.html
所以git pull --rebase
有一些重要的魔法git fetch; git rebase
,大多数时候你不会注意到,但是如果上游维护者顽皮地忽略了所有这些严厉的警告并决定重写公共分支的历史,它可以通过咨询你的本地 reflog 并以更智能的方式进行本地 rebase。
也就是说,这仍然是一个变基,所以你仍在改写历史!因此,所有标准的严厉警告仍然适用。但是如果你在一个私人的(即未发布的)分支上工作,那没关系。
关于严厉的警告,我会多说一点。它们是有效的,但就我个人而言,我发现大多数人对 rebase有点过于git rebase
偏执,就像他们年轻时半夜爬进他们的卧室并吃了他们的妹妹之类的东西。它真的不应该那么可怕:
就是这么简单。是的,我会积极鼓励人们定期git rebase -i
在他们的私人分支机构。在推送到公共/上游的某个地方之前抛光历史是一件好事,因为没有人愿意涉足一个充满诸如“哎呀,修复我在 3 次提交前犯的错误”之类的提交的项目历史。(OTOH,不要完全沉迷于寻求完美历史的重新定位。我们是人类。我们会犯错误。处理它。)
关于git pull --rebase
魔法的最后一个观察。如果上游公共分支以合理的方式重新设置了基础(例如压缩/修复提交,或删除不应该放在那里的提交),那么魔法对你有利。但是,如果上游 rebase 不小心丢弃了提交,那么魔法会默默地阻止你把它们放回去。在这种情况下,如果你想放回那些丢弃的提交,你应该改用git fetch; git rebase
.
Git 的规则是,在共享、发布或推送后,您永远不应尝试更改历史记录。当然,如果你真的想要并且拥有足够的权限,你可以这样做,但应该非常小心,因为它可能会搞砸其他人。
现在幸运的是,当您有一个具有单个上游存储库(源)的典型 Git 部署时,它是宇宙中所有美好和真实的源泉,您可以尽情使用git pull --rebase
它,这将是非常安全的,在我看来给你的历史要理智得多(意思是线性的)。我和我的团队一直在使用它。
但是,如果您开始拥有多个遥控器并开始这样做git pull --rebase <arguments>
,您不再每次都针对同一个目标进行 rebase,或者在与您的主要上游运行之前git pull --rebase
开始将您的分支推送到备用存储库- 那么您可能会开始遇到麻烦。
任何时候您与另一个远程/存储库共享您的更改然后更改这些更改(对于更改的值等于更改 SHA、父级等,即使提交消息/内容没有更改),您可能会搞砸这个人谁有旧的变化。
只要您不超出 rebase sanity 的范围,git pull --rebase
对您将非常有好处。
那,错误,并没有回答关于 和 之间区别的git pull --rebase
问题git fetch && git rebase @{u}
。我会继续说我不知道有什么区别,如果有的话,那已经足够微妙了,以至于我在使用 Git 的这些年里都没有注意到它。如果您有多个存储库并且“来源”不是该分支的上游,系统可能会确定您的分支应该获取的正确存储库?
即使你在使用 git-rebase 时确实出错了,你当然可以使用git log -g
和/或git reset --hard ORIG_HEAD
. 只是不要强制推送(几乎所有 Git 服务器默认不允许),你会很高兴。
随着时间的推移,我的理解得到了扩展。git pull --rebase
调用git rebase
来做变基工作,所以从这个意义上说,它们之间没有区别。但是, git-pull 实际上调用git rebase --onto @{u} $(git merge-base HEAD @{u}@{1})
好的,该语法(“@{u}@{1}”)可能有点不透明,并且是启动的简化,但关键是它在运行 fetch 命令之前找出了上游的合并基础。你问这有什么不同?
好吧,在正常情况下没有。但是,如果您要更改上游指向的位置,或者上游本身已重新设置基础,则相当多。如果上游被重写,然后你做了一个git rebase @{u}
,你可能会非常不开心,并且可能会根据旧提交被重写的程度而得到双重提交或冲突。
然而,git pull --rebase
只有你自己的提交和你自己的提交才会被应用在@{u}之上。
好的,这也是一个简化。如果上游从 100 次之前的提交开始进行 rebase(但实际上历史中有 101 次以上的提交)并且您在执行 agit fetch
之前做了 agit pull --rebase
那么 Git 将无法准确确定正确的历史合并基础是什么你的本地提交是。
结果是,git fetch
被认为是有害的(当您有本地提交并且上游被重写时)。然而,真正的经验法则是“在历史被共享、发布或推送后,永远不要试图改变它”,这就是我开始的地方。
git fetch
被认为是有害的(所以使用git pull --rebase
);并且在共享、发布或推送后切勿尝试更改历史记录(因为除其他外,它会导致git fetch
有害)。
除了从其远程跟踪分支更新您的本地分支之外,还会更新-pull
您的工作区文件。
所以它可能git pull --rebase
比git fetch; git rebase
.