`git fetch`然后`git rebase`和`git pull --rebase`有什么区别?

时间:2011-06-08 20:32:14

标签: git git-rebase

在阅读git pull页面时,它会对git pull --rebase发出严厉警告:

  

这是一种潜在的危险操作模式。它重写了历史,当你已经发布了这段历史时,它并不是一个好兆头。除非您仔细阅读git-rebase(1),否则不要使用此选项。

git rebase页面中,它提供了大量描述,但没有此类警告。

另外,我见过有人说过

git fetch
git rebase

相同
git pull --rebase

而其他人则说他们略有差异

真相是什么?

3 个答案:

答案 0 :(得分:38)

事实是,他们不同。这是一个非常有用的网页,可以很好地解释它:

http://gitolite.com/git-pull--rebase.html

所以 git pull --rebasegit fetch; git rebase 上有一些重要的魔力,大部分时间你都不会注意到,但是在上游维护者顽皮地忽略了所有那些船尾的情况下警告并决定重写公共分支的历史,它可以通过咨询您当地的reflog并以更智能的方式进行本地变基,真正有所帮助。

那就是说,这仍然是一个改变,所以你仍然在重写历史!因此,所有标准的严厉警告仍然适用。但是,如果您正在处理私人(即未发布)分支,那就没关系。

关于严厉的警告,我会多说一点。它们是有效的,但就我个人而言,我发现大多数人对于rebase有点偏执,就像git rebase在他们年轻的时候悄悄进入他们的卧室并且吃了他们的妹妹或者其他的东西。它真的不应该那么可怕:

  • 如果它是一个私人分支,那就是你的心灵内容
  • 如果它是公共分支,除非你真的必须,否则不要改变,如果你这样做,请确保你了解其影响,并确保任何可能受影响的人都知道什么你已经完成了,所以他们没有得到令人讨厌的惊喜,并浪费了大量的时间来弄清楚发生了什么。

就这么简单。是的,我会尽可能地鼓励人们定期git rebase -i在他们的私人分支机构。在推到公共/上游的某个地方之前抛光历史是a good thing,因为没有人想要涉及一个项目的历史,这个历史充满了像'oops,修复我犯了3个提交之前的错误'。 (OTOH,不要完全沉迷于寻求完美历史的变革。我们是人。我们犯错误。处理它。)

关于git pull --rebase魔法的最后一个观察。如果上游公共分支机构已经以合理的方式进行了重新设置(例如,压缩/修复提交,或者放弃了不应该放在那里的提交),那么魔法对你有利。但是,如果上游rebase意外掉线提交,那么魔法会默默地阻止你将它们放回去。在这种情况下,如果您想要放回那些已删除的提交,则应使用git fetch; git rebase

答案 1 :(得分:31)

使用Git的规则是,在共享,发布或推送历史记录后,切勿尝试更改历史记录。当然,如果你真的想要并拥有足够的权限,你可以这样做,但是应该非常谨慎地完成,因为它会让其他人感到困惑。

幸运的是,如果您有一个典型的Git部署,其中包含一个上游存储库(origin),它是Universe中所有优秀和真实的源,您可以将git pull --rebase用于您的内容,它将会是完全安全的,在我看来,给你一个更加理智(意味着线性)的历史。我和我的团队一直在使用它。

但是,如果您开始使用多个遥控器并开始执行git pull --rebase <arguments>,那么您不再每次都针对相同的目标进行重新定位,或者在运行之前开始将分支推送到备用存储库 git pull --rebase与您的主要上游 - 然后您可以开始遇到麻烦。

任何时候你与另一个远程/存储库共享你的更改,然后更改这些更改(对于更改的值等于更改SHA,父级等,即使提交消息/内容没有更改),你可以搞乱那个有旧变化的人。

只要你不属于变形理智的范围,git pull --rebase就会对你有好处。

那个,错误的,没有回答关于git pull --rebasegit fetch && git rebase @{u}之间差异的问题。我会继续说我没有意识到任何差异,如果有的话,它是微妙的,我在使用Git的那些年里没有注意到它。可能是因为如果你有多个存储库并且“origin”不是这个分支的上游,系统会找出你的分支应该获取的正确存储库吗?

即使你确实使用git-rebase非常糟糕,你当然可以使用git log -g和/或git reset --hard ORIG_HEAD轻松恢复到原来的pre-rebase环境。只是不要强制推送(几乎所有Git服务器都默认禁止),你会很开心。

EDITED

随着时间的推移,我的理解已经扩大。 git pull --rebase调用git rebase来执行rebase工作,因此从这个意义上说它们之间没有区别。但是,git-pull实际上会调用git rebase --onto @{u} $(git merge-base HEAD @{u}@{1})

好的,那个语法(“@ {u} @ {1}”)可能有点不透明,并且是一个简化引导,但关键是它找出合并基础到上游 BEFORE 它运行了fetch命令。你问,这有什么区别?

嗯,在正常情况下没有。但是,如果您正在改变上游所指向的位置,或者上游本身是否已经重新定位,那么就会非常多。如果上游被重写,然后你做了一个git rebase @{u},你可能会非常不满意,并且可能会因为旧的提交被重写多少而得到双重提交或冲突。

然而,凭借git pull --rebase背后的魔力,只有你自己和你自己的提交将被应用于@ {u}之上。

好的,这个是一种简化。如果上游从100次提交开始做了一个rebase(但实际上有101次提交)你在做{{{}之前做了git fetch 1}}然后Git将无法准确确定适当的历史合并基础是什么来确定您的本地提交是什么。

结果是,git pull --rebase被认为是有害的(当你有本地提交和上游被重写时)。然而,真正的经验法则是“在共享,发布或推送之后永远不会尝试更改历史记录”,这是我开始的地方。

TL; DR:

git fetch被视为有害(因此请使用git fetch);并且在共享,发布或推送之后永远不会尝试更改历史记录(因为,除其他外,它会导致git pull --rebase有害)。

答案 2 :(得分:-5)

除了从远程跟踪分支更新本地分支外,-pull还会更新工作区文件。

因此git pull --rebase(或默认配置pull使用rebase)可能比git fetch; git rebase更典型。