我什么时候应该使用git ull--rebase?

我知道有些人默认使用git pull --rebase,而另一些人坚持从不使用它。我相信我理解合并和rebasing之间的区别,但我试图把它放在git pull的上下文中。只是不想看到很多合并提交消息,还是有其他问题?

684089 次浏览

我认为这归结为个人喜好。

您想在推送更改之前隐藏您的愚蠢错误吗?如果是这样,git pull --rebase是完美的。它允许您稍后将提交压缩为几个(或一个)提交。如果您的(未推送的)历史中有合并,稍后进行git rebase合并就不那么容易了。

我个人不介意发布我所有愚蠢的错误,所以我倾向于合并而不是重新定位。

我认为你在同一分支上与其他人协作时应该使用git pull --rebase。你处于工作→提交→工作→提交周期,当你决定推送你的工作时,你的推送会被拒绝,因为同一分支上有并行工作。在这一点上,我总是做了一个pull --rebase。我不使用Squash(扁平化提交),但我会重新调整基础以避免额外的合并提交。

随着你的Git知识的增加,你会发现自己比我使用过的任何其他版本控制系统都更关注历史。如果你有大量的小合并提交,很容易失去对历史中发生的大局的关注。

这实际上是我唯一一次执行rebasing(*),我的其余工作流程是基于合并的。但是只要你最频繁的提交者这样做,历史最终看起来会好得多。

(*)在教授Git课程时,有一个学生因此逮捕了我,因为我也主张在某些情况下重新建立功能分支的基础。他已经阅读了这个答案;)这种重新建立基础也是可能的,但它总是必须根据预先安排/同意的系统,因此不应该“总是”应用。那时我通常也不做pull --rebase,这就是问题所在;)

你应该使用git pull --rebase

  • 您的更改不值得单独的分支

确实--为什么不呢?它更清晰,并且不会在提交上强加逻辑分组


好的,我想它需要一些澄清。在Git中,正如你可能知道的,我们鼓励你分支和合并。你将更改拉入的本地分支和远程分支实际上是不同的分支,git pull是关于合并它们。这是合理的,因为你不经常推送,通常会积累许多更改,然后才能构成一个完整的功能。

然而,有时候,不管出于什么原因,你认为如果这两个分支——远程和本地——是一个分支会更好。就像在SVN中一样。这就是git pull --rebase发挥作用的地方。你不再合并——你实际上是在远程分支之上提交。这就是它的实际意义。

是否危险的问题在于是否将本地和远程分支视为不可分割的东西。有时这是合理的(当你的更改很小,或者如果你处于一个强大的开发的开始,小提交带来了重要的更改)。有时不是(当你通常会创建另一个分支,但你太懒了)。但这是另一个问题。

我认为没有理由没有使用pull --rebase——我专门向Git添加了代码,以允许我的git pull命令始终针对上游提交进行重新定位。

在回顾历史时,知道在该功能上工作的人什么时候停止同步从来都不是有趣的。当他/她正在做的时候,这可能对他/她有用,但这就是reflog的作用。它只是为其他人添加噪音。

我想提供一个不同的视角来理解git pull --rebase实际上意味着什么,因为它似乎有时会丢失。

如果你曾经使用过Subversion(或CVS),你可能已经习惯了svn update的行为。如果你有更改要提交,并且由于上游进行了更改而提交失败,你svn update。Subversion通过合并上游的更改来进行,可能会导致冲突。

Subversion刚刚做的,本质上是git pull --rebase。重新制定本地更改以相对于新版本的行为是其中的“rebase”部分。如果你在失败的提交尝试之前做了svn diff,并将结果diff与svn diff的输出进行比较,两者之间的区别在于rebase操作所做的。

在这种情况下,Git和Subversion之间的主要区别在于,在Subversion中,“你的”更改仅作为未提交的更改存在于你的工作副本中,而在Git中,你在本地有实际的提交。换句话说,在Git中,你已经分叉了历史;你的历史和上游历史已经分歧,但你有一个共同的祖先。

在我看来,在让你的本地分支简单地反映上游分支并在其上进行持续开发的正常情况下,正确的做法总是--rebase,因为这实际上是语义上的。你和其他人正在破坏分支的预期线性历史。其他人碰巧在你尝试推送之前稍微推送的事实是无关紧要的,对于每次这样的时间事故导致历史上的合并似乎适得其反。

如果出于某种原因,你真的觉得某个东西需要成为一个分支,在我看来,这是一个不同的问题。但是,除非你有一个特定的、积极的愿望来以合并的形式表示你的更改,否则在我看来,默认行为应该是git pull --rebase

请考虑其他需要观察和理解您的项目历史的人。您是希望历史上到处都是数百个合并,还是只希望选择少数几个合并,这些合并代表了有意发散的开发工作的真正合并?

也许最好的解释方法是举一个例子:

  1. Alice创建主题分支A,并对其进行处理
  2. Bob创建不相关的主题分支B,并处理它
  3. Alice做git checkout master && git pull。Master已经是最新的。
  4. Bob做git checkout master && git pull。Master已经是最新的。
  5. 爱丽丝git merge topic-branch-A
  6. 鲍勃git merge topic-branch-B
  7. Bob在Alice之前做了git push origin master
  8. Alice执行git push origin master,但被拒绝,因为它不是快进合并。
  9. 爱丽丝查看原始/主日志,发现提交与她的无关。
  10. 爱丽丝git pull --rebase origin master
  11. Alice的合并提交被解除,Bob的提交被拉取,Alice的提交在Bob的提交之后应用。
  12. Alice做了git push origin master,每个人都很高兴他们将来查看日志时不必读取无用的合并提交。

请注意,要合并到的特定分支与示例无关。此示例中的Master可以很容易地成为发布分支或开发分支。关键点是Alice和Bob同时将他们的本地分支合并到共享的远程分支。

git pull --rebase可能会隐藏合作者git push --force的历史重写。如果您知道自己忘记在其他人之前推送提交,我建议使用git pull --rebase只有

如果你没有提交任何东西,但是你的工作空间不干净,只是git stash之前到git pull。这样你就不会默默地重写你的历史记录(这可能会默默地丢弃你的一些工作)。

只要记住:

  • 拉取+合并请求参数
  • 获取成功后重新上架,重新上架

所以,选择你想要处理你的分支的方式。

你最好知道合并和rebase之间的区别:)

一个实践案例是当您使用比特桶PR时。让我们用下面的例子来理解它:

有PR开放。

然后您决定通过BitBucket GUI使用最新的Master分支重新定位PR远程分支。此操作将更改PR的提交ID。

由于您已经使用GUI重新设置了远程分支的基础。首先,您必须将PC上的本地分支与远程分支同步。

在这种情况下,git pull --rebase像魔术一样工作。

git pull --rebase之后,您的本地分支和远程分支具有相同的历史记录和相同的提交ID。

然后现在,如果您向PR分支添加新的提交/更改。

您可以在不使用武力或任何东西的情况下将新提交推送到远程分支/BitBucket PR。

这个场景描述了一种因为原点的代码发生了变化,你无法推送提交的情况。科迪的解释很容易理解。我画了一个图来描述这种场景,希望对我有帮助。如果我错了,请纠正我。

在此处输入图片描述

如何使用Git Pull

  • git pull:使用远程提交更新本地工作分支,并更新所有远程跟踪分支。

  • git pull --rebase:使用来自远程的提交更新本地工作分支,但重写历史记录,以便在来自远程的所有新提交之后发生任何本地提交,避免合并提交。

  • git pull --force:此选项允许您在使用由于冲突而无法获取的选项时强制获取特定远程跟踪分支。要强制Git覆盖当前分支以匹配远程跟踪分支,请阅读下面关于使用git重置的信息。

  • git pull --all:获取所有遥控器-如果您正在使用分叉或在具有多个遥控器的另一个用例中工作,这很方便。