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

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


当前回答

信息图形总是有用的:)

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

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

其他回答

信息图形总是有用的:)

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

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

我刚刚用自己的话为我的团队创建了一个FAQ,以回答这个问题。让我分享一下:

什么是合并?

提交,将不同分支的所有更改合并到当前。

什么是重基?

将当前分支的所有提交重新提交到不同的基本提交上。

合并和再基础之间的主要区别是什么?

merge只执行一次新提交。rebase通常执行多次(当前分支中的提交次数)。merge生成一个新生成的提交(所谓的合并提交)。rebase仅移动现有提交。

在哪些情况下我们应该使用合并?

如果要将分支分支的更改添加回基本分支,请使用merge。

通常,您可以通过单击Pull/Merge请求上的“合并”按钮来完成此操作,例如在GitHub上。

在哪些情况下我们应该使用重基?

每当您想将基本分支的更改添加回分支时,请使用rebase。

通常,只要主分支发生变化,就可以在功能分支中执行此操作。

为什么不使用合并将基本分支中的更改合并到要素分支中?

git历史记录将包含许多不必要的合并提交。如果在一个功能分支中需要多个合并,那么该功能分支甚至可能包含比实际提交更多的合并提交!这就产生了一个循环,它破坏了Git所设计的心理模型,这在Git历史的任何可视化中都会带来麻烦。想象有一条河(例如“尼罗河”)。水流向一个方向(Git历史上的时间方向)。有时,想象那条河有一条支流,假设这些支流中的大部分都汇回了这条河。这就是河流的自然流动的样子。这是有道理的。但想象一下,那条河有一条小支流。然后,由于某种原因,河流汇入分支,分支从那里继续。从技术上讲,这条河现在已经消失了,它现在在支流中。但是,不知怎的,这条支流神奇地汇回了河里。你问哪条河?我不知道。这条河现在应该在支流中,但不知何故它仍然存在,我可以将支流合并回河流中。所以,河在河中。有点说不过去。这正是将基本分支合并到要素分支时发生的情况,然后在要素分支完成后,再次将其合并回基本分支。心智模型被打破了。因此,你最终得到了一个没有太大帮助的分支可视化。

使用merge时的Git历史示例:

请注意,许多提交都是从Merge分支“main”开始的。。。。如果你重新创建数据库,它们甚至都不存在(在那里,你只会有拉请求合并提交)。还有许多视觉分支合并循环(主到要素到主)。

使用rebase时的Git历史示例:

Git历史更加清晰,合并提交更少,没有任何杂乱的可视化分支合并循环。

rebase有什么缺点/缺陷吗?

Yes:

因为重基会移动提交(从技术上讲是重新执行),所以所有移动的提交的提交日期将是重基的时间,而git历史记录看起来可能会丢失初始提交时间。因此,如果出于某种原因,所有工具都需要提交的确切日期,那么合并是更好的选择。但通常情况下,干净的git历史要比准确的提交日期有用得多。如果需要,authordate字段将继续保存原始提交日期。如果重基分支有多个更改同一行的提交,并且该行也在基分支中更改,则可能需要多次解决该行的合并冲突,这在合并时是不需要的。因此,平均而言,需要解决的合并冲突更多。

使用rebase时减少合并冲突的提示:

经常退款。我通常建议每天至少做一次。尽量将同一行中的更改压缩为一次提交。

简短版本

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

那你什么时候用这两种?

合并

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

回扣

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

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

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

Pro Git的书在重新设置基础页面上有一个很好的解释。

基本上,合并将进行两次提交并合并它们。

一个重基将转到这两者的共同祖先,并在彼此之上逐步应用更改。这使得历史更加“清晰”和线性。

但当您重新创建基准时,您将放弃以前的提交并创建新的提交。因此,您永远不应该重新设置公共存储库的基础。其他在存储库中工作的人会恨你。

仅出于这个原因,我几乎完全合并了。99%的时候,我的分支机构没有太大的差异,所以如果有冲突,只会发生在一两个地方。

Gitrebase用于使历史中的分支路径更清晰,存储库结构更线性。

它还用于将您创建的分支保持为私有,因为在重新创建基础并将更改推送到服务器之后,如果您删除了分支,则不会有您曾处理过的分支的证据。因此,您的分支现在是您的本地关注点。

在进行重新基化之后,我们还消除了一个额外的提交,这是我们用来查看是否进行正常合并的。

是的,在成功的rebase之后仍然需要进行合并,因为rebase命令只是将您的工作放在您在rebase过程中提到的分支之上,比如master,并将分支的第一次提交作为master分支的直接后代。这意味着我们现在可以进行快速合并,将更改从该分支带到主分支。