【问题标题】:What's the difference between `git fetch` then `git rebase`, and `git pull --rebase`?`git fetch` 然后 `git rebase` 和 `git pull --rebase` 有什么区别?
【发布时间】:2011-09-11 05:02:12
【问题描述】:

在阅读git pull 页面时,它给出了关于git pull --rebase 的严厉警告:

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

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

另外,我看到有人这么说

git fetch
git rebase

和

一样
git pull --rebase

而其他人则说他们略有不同。

真相是什么?

【问题讨论】:

  • 一本关于 git 的好书,你应该把它放在枕头下progit.org
  • git pull 页面上的警告听起来很容易出错。但是书中的描述听起来像是你必须努力搞砸变基。
  • 我最终经常做的是使用git fetch 来更新我对远程仓库的看法,然后查看下拉的历史记录并决定我想做什么。 (通常我会用git rebase 跟进。)

标签: git git-rebase


【解决方案1】:

Git 的规则是,在共享、发布或推送后,您永远不应尝试更改历史记录。当然,如果你真的想要并且拥有足够的权限,你可以这样做,但应该非常小心,因为它可能会搞砸其他人。

现在幸运的是,当您拥有一个具有单个上游存储库(源)的典型 Git 部署时,这是宇宙中所有美好和真实的源泉,您可以尽情使用 git pull --rebase,这将是完美的安全,在我看来给你一个更理智(意思是线性)的历史。我和我的团队一直在使用它。

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

任何时候您与另一个远程/存储库共享您的更改,然后更改这些更改(对于更改的值等于更改 SHA、父级等,即使提交消息/内容没有更改),您可能会搞砸把有旧变化的人扶起来。

只要您不超出 rebase 理智的范围,git pull --rebase 将非常适合您。

那个,呃,没有回答关于git pull --rebase 和git fetch && git rebase @{u} 之间区别的问题。我会继续说我不知道​​有什么区别,如果有的话,那已经足够微妙了,以至于我在使用 Git 的这些年里都没有注意到它。如果您有多个存储库并且“来源”不是该分支的上游,系统可能会计算出您的分支应该获取的正确存储库?

即使你在使用 git-rebase 时确实出错了,你当然可以使用 git log -g 和/或 git reset --hard ORIG_HEAD 轻松地将自己恢复到原来的 rebase 前环境。只是不要强制推送(几乎所有 Git 服务器默认不允许),你会很高兴的。

已编辑

随着时间的推移,我的理解有所扩展。 git pull --rebase 调用 git 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 次提交开始进行变基(但实际上历史上有 101 次以上的提交)并且你做了一个git fetch 之前做了一个git pull --rebase 然后Git 将无法准确确定正确的历史合并库是什么来确定您的本地提交是什么。

其结果是,git fetch 被认为是有害的(当您有本地提交并且上游被重写时)。然而,真正的经验法则是“在历史被共享、发布或推送后,永远不要试图改变它”,这就是我开始的地方。

TL;DR:

git fetch 被认为是有害的(所以使用git pull --rebase);并且在共享、发布或推送后切勿尝试更改历史记录(因为除其他外,这会导致 git fetch 有害)。

【讨论】:

  • TL;DR(也许问题的答案埋在那里,但我永远不会知道:)
  • @RickO'Shea:添加了一个 TL;DR 只为 你。
  • TLDR 错误:git fetch 不可能有害!它除了从远程获取新对象之外什么都不做。它不会以任何方式更改本地结帐或本地分支的状态。
  • @mvp:您是正确的, fetch 不会更改本地分支,但这并不能阻止它有害(在我在 TL;DR 上方段落中概述的特定情况下)。如果您认为我对这些情况“现在”错了(我最近没有检查过 git 的这一部分),请对技术细节提出异议,而不是概括总结。
  • @SethRobertson 也许@mvp 的意思是您的 TL;DR 应该是您对完整问题“git fetch 然后git rebase 和git pull --rebase 有什么区别? "不仅是您最后一段的摘要,因为就目前而言,任何浏览您的答案以寻找 TL;DR 的人都会阅读“git fetch 被认为是有害的?我认为git fetch 只是获取并且不会改变什么?那如何回答git pull --rebase/git rebase的问题?"
【解决方案2】:

事实是它们是不同的。这是一个非常有用的网页,它解释得很漂亮:

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

所以 git pull --rebase 比 git fetch; git rebase 有一些显着的魔力,大多数时候你不会注意到,但如果上游维护者顽皮地忽略了所有这些严厉的警告并决定重写公共分支的历史,它可以通过咨询您的本地 reflog 并以更智能的方式执行本地 rebase 来真正提供帮助。

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

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

  • 如果它是私有分支,请随心所欲地变基
  • 如果它是一个公共分支,除非您真的必须这样做,否则请不要变基,如果您这样做,请确保您了解影响,并确保任何可能受到影响的人都正确了解什么你已经完成了,所以他们不会感到意外,也不会浪费大量时间弄清楚发生了什么。

就这么简单。是的,我会积极鼓励人们在他们的私人分支机构定期git rebase -i。在推送到公共/上游某个地方之前抛光历史是a good thing,因为没有人愿意涉足一个充满诸如“哎呀,修复我在 3 次提交前犯的错误”之类的提交的项目历史。 (OTOH,不要完全沉迷于重新定位以寻求完美的历史。我们是人类。我们会犯错误。处理它。)

关于git pull --rebase 魔法的最后一个观察结果。如果上游公共分支以合理的方式重新设置了基础(例如压缩/修复提交,或删除不应该放在那里的提交),那么魔法对你有利。但是,如果上游 rebase 意外 dropped 提交,那么魔法会默默地阻止您将它们放回原处。在这种情况下,如果你想恢复那些被丢弃的提交,你应该改用git fetch; git rebase。

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

    • 这根本不能回答问题。此外,尽管没有耐心阅读它,但您似乎对我的正确答案投了反对票。
    猜你喜欢
    • 2011-03-22
    • 2017-06-30
    • 2015-03-21
    • 2020-08-24
    • 2018-03-05
    • 2016-10-27
    • 1970-01-01
    • 2014-10-15
    相关资源
    最近更新 更多