建议何时使用Git rebase与Git merge?

成功重新创建数据库后,是否仍需要合并?


当前回答

为了补充TSamper提到的我自己的答案,

在合并之前,重新创建数据库通常是一个好主意,因为这样做的目的是在分支Y中集成将要合并的分支B的工作。但同样,在合并之前,您要解决分支中的任何冲突(即:“rebase”,如“从分支B的最近一点开始在分支中回放我的工作”)。如果操作正确,后续从分支到分支B的合并可以快速进行。合并直接影响目标分支B,这意味着合并最好是微不足道的,否则分支B可能很长时间才能恢复到稳定状态(是时候解决所有冲突了)


重新基础后合并的意义?

在我描述的情况下,我将B重新放在我的分支上,只是为了有机会从B的最近一点回放我的工作,但同时留在我的分支。在这种情况下,仍然需要合并才能将我的“回放”工作带到B上。

另一种场景(例如Git Ready中描述的)是通过重基(rebase)将您的工作直接带到B中(这会保留所有漂亮的提交,甚至会给您机会通过交互式重基重新排序)。在这种情况下(当您在B分支中时重新创建基础),您是正确的:不需要进一步合并:

当我们没有合并或重新基础时,默认情况下是Git树

我们通过重新定基获得:

第二个场景的全部内容是:我如何将新功能恢复到主功能。

通过描述第一个重基场景,我的目的是提醒大家,重基也可以作为实现这一目标的初步步骤(即“将新功能重新引入主功能”)。您可以使用rebase首先将master“带入”新特性分支:rebase将重放来自HEAD master的新特性提交,但仍在新特性分支中,有效地将分支起点从旧的master提交移动到HEAD master。这允许您解决分支中的任何冲突(即,隔离,同时如果冲突解决阶段花费太长时间,则允许主分支继续并行发展)。然后,您可以切换到主功能并合并新功能(如果您想保留在新功能分支中完成的提交,则可以将新功能重新放到主功能上)。

So:

“rebase与merge”可以被视为两种方法来导入一个工作,例如master。但“先重新创建基础,然后合并”可以是一个有效的工作流,它可以先孤立地解决冲突,然后再恢复工作。

其他回答

简短版本

合并在一个分支中接受所有更改,并在一次提交中将它们合并到另一个分支。Rebase说我希望我的分支点转移到一个新的起点

那你什么时候用这两种?

合并

假设您创建了一个分支来开发单个功能。当您想将这些更改带回master时,可能需要合并。

回扣

第二种情况是,如果您开始进行一些开发,然后另一个开发人员进行了不相关的更改。您可能希望从存储库中提取并重新创建基础,以将当前版本的更改作为基础。

挤压:在这两种情况下都会保留所有提交(例如:“add feature”,然后是“typ”,然后“oops typ again”…)。通过挤压,可以将提交合并为单个提交。挤压可以作为合并或重基操作(--squash标志)的一部分完成,在这种情况下,通常称为挤压合并或挤压重基。

拉取请求:流行的git服务器(Bitbucket、GitLab、GitHub等)允许配置如何在每个回购基础上合并拉取请求。按照惯例,UI可能会显示“合并”按钮,但该按钮可以使用任何标志(关键字:合并、重基、挤压、快进)执行任何操作。

信息图形总是有用的:)

合并:将一个分支重叠到另一个分支上

Assume the following history exists and the current branch is "master":

                     A---B---C topic
                    /
               D---E---F---G master

       Then "git merge topic" will replay the changes made on the topic branch since it
       diverged from master (i.e., E) until its current commit (C) on top of master, and
       record the result in a new commit along with the names of the two parent commits
       and a log message from the user describing the changes.

                     A---B---C topic
                    /         \
               D---E---F---G---H master

Rebase:将一个分支的更改移动到另一个分支末端

Assume the following history exists and the current branch is "topic":

                     A---B---C topic
                    /
               D---E---F---G master

       From this point, the result of either of the following commands:

           git rebase master
           git rebase master topic

       would be:

                             A'--B'--C' topic
                            /
               D---E---F---G master

       NOTE: The latter form is just a short-hand of git checkout topic followed by git
       rebase master. When rebase exits topic will remain the checked-out branch.

因此,我们基本上可以得出结论,合并是一个安全的选项,它可以保存存储库的整个历史,而重基化通过将特性分支移动到main的顶端来创建线性历史。

Credit:帮助页面gitmerge--help和gitrebase--help

为了补充TSamper提到的我自己的答案,

在合并之前,重新创建数据库通常是一个好主意,因为这样做的目的是在分支Y中集成将要合并的分支B的工作。但同样,在合并之前,您要解决分支中的任何冲突(即:“rebase”,如“从分支B的最近一点开始在分支中回放我的工作”)。如果操作正确,后续从分支到分支B的合并可以快速进行。合并直接影响目标分支B,这意味着合并最好是微不足道的,否则分支B可能很长时间才能恢复到稳定状态(是时候解决所有冲突了)


重新基础后合并的意义?

在我描述的情况下,我将B重新放在我的分支上,只是为了有机会从B的最近一点回放我的工作,但同时留在我的分支。在这种情况下,仍然需要合并才能将我的“回放”工作带到B上。

另一种场景(例如Git Ready中描述的)是通过重基(rebase)将您的工作直接带到B中(这会保留所有漂亮的提交,甚至会给您机会通过交互式重基重新排序)。在这种情况下(当您在B分支中时重新创建基础),您是正确的:不需要进一步合并:

当我们没有合并或重新基础时,默认情况下是Git树

我们通过重新定基获得:

第二个场景的全部内容是:我如何将新功能恢复到主功能。

通过描述第一个重基场景,我的目的是提醒大家,重基也可以作为实现这一目标的初步步骤(即“将新功能重新引入主功能”)。您可以使用rebase首先将master“带入”新特性分支:rebase将重放来自HEAD master的新特性提交,但仍在新特性分支中,有效地将分支起点从旧的master提交移动到HEAD master。这允许您解决分支中的任何冲突(即,隔离,同时如果冲突解决阶段花费太长时间,则允许主分支继续并行发展)。然后,您可以切换到主功能并合并新功能(如果您想保留在新功能分支中完成的提交,则可以将新功能重新放到主功能上)。

So:

“rebase与merge”可以被视为两种方法来导入一个工作,例如master。但“先重新创建基础,然后合并”可以是一个有效的工作流,它可以先孤立地解决冲突,然后再恢复工作。

TL;博士

如果您有任何疑问,请使用merge。

简短回答

重新基准和合并之间的唯一区别是:

生成的历史树结构(通常只有在查看提交图时才明显)不同(一个有分支,另一个没有分支)。合并通常会创建一个额外的提交(例如树中的节点)。合并和重新基础将以不同的方式处理冲突。Rebase将一次提交一个冲突,而merge将一次显示所有冲突。

因此,简单的答案是根据您希望的历史外观选择重新基准或合并。

长答案

在选择要使用的操作时,需要考虑以下几个因素。

您从中获得更改的分支是否与团队之外的其他开发人员共享(例如,开源、公共)?

如果是,请不要重新设置基准。Rebase会破坏分支,除非他们使用git pull-Rebase,否则这些开发人员将拥有损坏/不一致的存储库。这是一个很快让其他开发人员感到不安的好方法。

您的开发团队有多熟练?

回扣是一种破坏性操作。这意味着,如果不正确应用它,您可能会丢失已提交的工作和/或破坏其他开发人员存储库的一致性。

我曾在团队中工作过,这些团队中的开发人员都来自一个公司能够负担得起专门的员工来处理分支和合并的时代。这些开发人员对Git了解不多,也不想了解太多。在这些团队中,我不会因为任何原因而冒险建议重新定基。

分支本身是否表示有用的信息

一些团队使用每个功能的分支模型,其中每个分支表示一个功能(或错误修复或子功能等)。在这个模型中,分支帮助识别相关提交的集合。例如,可以通过恢复该分支的合并来快速恢复功能(公平地说,这是一个罕见的操作)。或者通过比较两个分支来区分一个特性(更常见)。Rebase会破坏分支,这并不简单。

我也曾在使用每个开发人员分支模型的团队中工作过(我们都去过)。在这种情况下,分支本身不传递任何附加信息(提交已经包含作者)。换基不会有什么害处。

是否出于任何原因要还原合并?

与恢复合并相比,恢复(如撤消)重基相当困难和/或不可能(如果重基发生冲突)。如果您认为有机会恢复,请使用merge。

你是团队成员吗?如果是的话,你愿意在这一分支机构采取“要么全有要么全无”的方法吗?

需要使用相应的git pull--Rebase来拉动Rebase操作。如果你是自己工作,你可能会记得在适当的时候应该使用哪一个。如果你在一个团队中工作,这将很难协调。这就是为什么大多数rebase工作流建议对所有合并使用rebase(以及git pull--rebase对所有合并)。

常见的神话

合并销毁历史记录(压缩提交)

假设您有以下合并:

    B -- C
   /      \
  A--------D

有些人会说合并“破坏”了提交历史,因为如果只查看主分支(A-D)的日志,就会错过B和C中包含的重要提交消息。

如果这是真的,我们就不会有这样的问题了。基本上,除非您明确要求不要看到B和C(使用--firstparent),否则您将看到它们。这很容易自己尝试。

Rebase允许更安全/更简单的合并

这两种方法的合并方式不同,但并不清楚其中一种总是优于另一种,这可能取决于开发人员的工作流程。例如,如果开发人员倾向于定期提交(例如,当他们从工作过渡到家庭时,他们可能一天提交两次),那么给定分支可能会有很多提交。其中许多提交看起来可能与最终产品不太相似(我倾向于对每个特性进行一次或两次重构)。如果其他人正在处理一个相关的代码领域,他们试图重新调整我的更改,这可能是一个相当乏味的操作。

热巴更酷/更性感/更专业

如果您想将rm别名为rm-rf以“节省时间”,那么可能需要重新设置基准。

我的两美分

我一直认为有一天我会遇到这样一个场景,Git rebase是解决这个问题的绝佳工具。就像我认为我会遇到这样一个场景,Git reflog是一个很好的工具,可以解决我的问题。我已经在Git工作了五年多了。这还没有发生。

混乱的历史对我来说从来都不是一个问题。我从来没有像读一本令人兴奋的小说那样阅读我的承诺历史。大多数时候,我需要一段历史,无论如何,我都会使用Git责备或Git平分。在这种情况下,合并提交实际上对我很有用,因为如果合并引入了问题,那对我来说就是有意义的信息。

更新(2017年4月)

我觉得有义务提及我个人对使用rebase的态度有所软化,尽管我的一般建议仍然有效。我最近与Angular 2 Material项目进行了很多互动。他们使用rebase来保持非常干净的提交历史。这使我能够非常容易地看到是什么提交修复了给定的缺陷,以及该提交是否包含在发布中。它是正确使用rebase的一个很好的例子。

我什么时候使用git rebase?几乎不会,因为它改写了历史。gitmerge几乎总是首选,因为它尊重项目中实际发生的事情。