merge --squash 和 rebase 有什么区别?

发布于 2024-08-24 09:19:42 字数 40 浏览 12 评论 0原文

我试图理解壁球和变基之间的区别。据我了解,在进行变基时会执行挤压。

I'm trying to understand the difference between a squash and a rebase. As I understand it, one performs a squash when doing a rebase.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

表情可笑 2024-08-31 09:19:42

合并提交:保留分支中的所有提交,并将它们与基础分支上的提交交错在此处输入图像描述

合并挤压:保留更改但忽略历史记录中的各个提交
输入图像描述这里

变基:这会将整个功能分支移至 master 分支的顶端,有效地将所有新提交合并到 master

在此处输入图像描述

有关 此处


前两张图来自 关于 GitHub 文档上的拉取请求合并

Merge commits: retains all of the commits in your branch and interleaves them with commits on the base branchenter image description here

Merge Squash: retains the changes but omits the individual commits from history
enter image description here

Rebase: This moves the entire feature branch to begin on the tip of the master branch, effectively incorporating all of the new commits in master

enter image description here

More on here


The first two diagrams come from About pull request merges on the GitHub Docs

娇俏 2024-08-31 09:19:42

git merge --squash 和 git rebase --interactive 都可以产生“压缩”提交。但它们有不同的目的。

将生成一个压缩目标分支上的提交,不标记任何合并关系。
(注意:它不会立即生成提交:您需要一个额外的 git commit -m "squashbranch")

如果您想完全丢弃源分支,从 (schema取自SO问题):

git checkout stable

          X               stable
         /
a---b---c---d---e---f---g tmp

到:

git merge --squash tmp
git commit -m "squash tmp"


# In the following graph, G is d--e--f--g squashed together

          X-------------G stable
         /
a---b---c---d---e---f---g tmp

然后删除tmp< /代码> 分支。


注意: git merge 有一个 --commit 选项,但不能与 --squash 一起使用。 永远不可能同时使用--commit--squash
自 Git 2.22.1(2019 年第 3 季度)起,这种不兼容性变得明确:

请参阅 commit 1d14d0c(2019 年 5 月 24 日)作者:Vishal Verma (reloadbrain)
(由 Junio C Hamano -- gitster -- 合并于 提交 33f2790,2019 年 7 月 25 日)

合并:拒绝--commit--squash

以前,当提供 --squash 时,'option_commit' 是静默的
掉了。这对于试图覆盖的用户来说可能会感到惊讶
显式使用 --commit 的挤压行为。

git/git builtin/merge.c#cmd_merge() 现在包括:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));

在新的基础上重放您的部分或全部提交,允许您压缩(或者最近“修复”,请参阅此 SO问题),直接转到:

git checkout tmp
git rebase -i stable

   stable
      X----------------G tmp
     /
a---b

如果您选择压缩 tmp 的所有提交(但是,与merge --squash相反,您可以选择重播某些内容,并压缩其他内容)。

因此,区别在于:

  • squash 不会触及您的源分支(此处为 tmp),并在您想要的位置创建单个提交。
  • rebase 允许您在同一源分支上继续(仍然是 tmp):
    • 新基地
    • 更清晰的历史

Both git merge --squash and git rebase --interactive can produce a "squashed" commit. But they serve different purposes.

will produce a squashed commit on the destination branch, without marking any merge relationship.
(Note: it does not produce a commit right away: you need an additional git commit -m "squash branch")

This is useful if you want to throw away the source branch completely, going from (schema taken from SO question):

git checkout stable

          X               stable
         /
a---b---c---d---e---f---g tmp

to:

git merge --squash tmp
git commit -m "squash tmp"


# In the following graph, G is d--e--f--g squashed together

          X-------------G stable
         /
a---b---c---d---e---f---g tmp

and then deleting tmp branch.


Note: git merge has a --commit option, but it cannot be used with --squash. It was never possible to use --commit and --squash together.
Since Git 2.22.1 (Q3 2019), this incompatibility is made explicit:

See commit 1d14d0c (24 May 2019) by Vishal Verma (reloadbrain).
(Merged by Junio C Hamano -- gitster -- in commit 33f2790, 25 Jul 2019)

merge: refuse --commit with --squash

Previously, when --squash was supplied, 'option_commit' was silently
dropped. This could have been surprising to a user who tried to override
the no-commit behavior of squash using --commit explicitly.

git/git builtin/merge.c#cmd_merge() now includes:

if (option_commit > 0)
    die(_("You cannot combine --squash with --commit."));

replays some or all of your commits on a new base, allowing you to squash (or more recently "fix up", see this SO question), going directly to:

git checkout tmp
git rebase -i stable

   stable
      X----------------G tmp
     /
a---b

If you choose to squash all commits of tmp (but, contrary to merge --squash, you can choose to replay some, and squashing others).

So the differences are:

  • squash does not touch your source branch (tmp here) and creates a single commit where you want.
  • rebase allows you to go on on the same source branch (still tmp) with:
    • a new base
    • a cleaner history
GRAY°灰色天空 2024-08-31 09:19:42

让我们从以下示例开始:

在此处输入图像描述

现在我们有 3 个选项将功能分支的更改合并到主分支

  1. 合并提交
    将保留功能分支的所有提交历史记录并将它们移动到主分支
    将添加额外的虚拟提交。

  2. 变基和合并
    会将功能分支的所有提交历史记录附加到主分支的前面
    不会添加额外的虚拟提交。

  3. 挤压并合并
    将所有功能分支提交分组为一个提交,然后将其附加到主分支的前面
    将添加额外的虚拟提交。

您可以在下面找到主分支将如何照顾它们中的每一个。

输入图像描述此处

在所有情况下:
我们可以安全地删除功能分支

Let's start by the following example:

enter image description here

Now we have 3 options to merge changes of feature branch into master branch:

  1. Merge commits
    Will keep all commits history of the feature branch and move them into the master branch
    Will add extra dummy commit.

  2. Rebase and merge
    Will append all commits history of the feature branch in the front of the master branch
    Will NOT add extra dummy commit.

  3. Squash and merge
    Will group all feature branch commits into one commit then append it in the front of the master branch
    Will add extra dummy commit.

You can find below how the master branch will look after each one of them.

enter image description here

In all cases:
We can safely DELETE the feature branch.

完美的未来在梦里 2024-08-31 09:19:42

合并挤压将树(一系列提交)合并为单个提交。也就是说,它将 n 次提交中所做的所有更改压缩为单个提交。

Rebasing就是重新定基,即为树选择一个新的基础(父提交)。也许这个多变的术语更清楚:他们称之为移植,因为它只是:为一棵树选择一个新的基础(父提交,根)。

在进行交互式变基时,您可以选择压缩、选择、编辑或跳过要变基的提交。

希望这是清楚的!

Merge squash merges a tree (a sequence of commits) into a single commit. That is, it squashes all changes made in n commits into a single commit.

Rebasing is re-basing, that is, choosing a new base (parent commit) for a tree. Maybe the mercurial term for this is more clear: they call it transplant because it's just that: picking a new ground (parent commit, root) for a tree.

When doing an interactive rebase, you're given the option to either squash, pick, edit or skip the commits you are going to rebase.

Hope that was clear!

时光礼记 2024-08-31 09:19:42

我学会理解 squashmerge 等之间的价值和区别的方法是为自己编写这个简短的教程。


如果你遵循这个,它将解释你想了解的关于挤压、合并、快进和变基的所有内容。


功能分支

假设您在原点有 Main 分支,具有提交历史记录,A。

在此处输入图像描述

您从 Main 中提取内容,并创建一个新的分支,FeatureA,这样您就有提交历史记录:

  • A、F1、F2、F3(FeatureA 分支上的三个提交)

在此处输入图像描述

您想要将您的更改推送到 Origin 并合并到 Main 中。由于 Origin 上的 Main 没有改变,您也可以快进。

快进合并 将

FeatureA 分支的所有提交历史记录应用到 Main 提交历史记录之上。

输入图片此处描述

与 Squash 合并

当您的分支有多个提交时,可用的选项就是压缩。与 Main 合并时,压缩会将 FeatureA 分支的历史记录合并为单个提交。

输入图片此处描述

如果 Main 上有其他更改,则无法快进。

如果您对 FeatureA 分支进行了更改,同时其他人已推送进入 Main,这样提交的起源历史现在是:A、B、C

在此处输入图像描述

您希望将更改推送到 Main 分支Origin,您有几个不同的选项:

  • 合并(无快进)
  • Rebase、
  • Stash 和 Pull。

合并(也称为不快进合并)

如果您要获取 Origin 的 Main 分支的本地副本并将其合并到本地 FeatureA 分支中,您将创建一个提交对于该合并,M。FeatureA 上的本地历史记录将是:A、F1、F2、F3、M,其中 M 是合并提交。

输入图片这里的描述

然后你可以合并到Main(如果你愿意的话可以压缩)。请注意,如果您不压缩,您将在 Main 提交历史记录中引入合并提交:

  • A、B、C、F1、F2、M。

您可以通过压缩< /em> 合并到 Main 时的分支,如上面 Squash 部分所述,结果为:ABCF,如下所示:

在此处输入图像描述

Rebase

Rebase 是避免引入将提交合并到历史记录中。它本质上会接受您的更改,并使其就像您已开始使用最新的 Main,而不是使用过时的 Main 版本。例如,在变基后,您的功能分支将从 A、B、C(而不是最初的 A)分支出来。结果:

  • A、B、C、F1、F2、F3

在此处输入图像描述

  • A、B、C、F(带壁球)

在此处输入图像描述

注意,没有合并 Git 实现此目的

的方式是系统地(逐次提交)将更改从源的 Main 应用于您的分支。最终结果就好像您过去没有基于提交 A 启动您的 FeatureA 分支,但就好像您在最新的 Main 之上开始了所有更改。

问题是,这样做的方式。对于必须应用于 FeatureA 分支的每个提交,git 都会检查合并冲突,并且您必须解决它们。如果自您的 FeatureA 分支以来,对 Origin 上的 Main 进行了多次更改,则您可以一遍又一遍地解决合并冲突

。拉比较容易?

存储和拉取

存储您的 FeatureA,从 Origin 获取/拉取 Main 的最新本地副本,然后创建一个新分支并应用您的存储。 (或者将新的 Main 分支合并到您的分支中,并应用您的存储。如果执行后者,请压缩以避免在提交历史记录中合并。)然后您可以推送到 Origin / 创建拉取请求。

The way I have learned to understand the value and difference between squash, merge, etc. is to put together this short tutorial for myself.


If you follow this it will explain everything you want to know about squash, merge as well as fast forward, and rebase.


Feature Branches

Say you have Main branch at the Origin, with a history of Commits, A.

enter image description here

You pull from Main, and create a new branch, FeatureA, such that you have commit history:

  • A, F1, F2, F3 (three commits on FeatureA branch)

enter image description here

You want to push you changes into Origin and merge into Main. Since Main on Origin hasn’t changed you are also able to Fast Forward.

Merge with Fast Forward

Apply all the commit history of FeatureA branch on top of Main’s commit history.

enter image description here

Merge with Squash

An option available whenever your branch has multiple commits is to squash. Squashing combines the history of FeatureA branch into a single commit when merging with Main.

enter image description here

Fast forward isn’t possible if there have been other changes on Main.

If you made changes to the FeatureA branch, meanwhile others had pushed into Main, such that the Origin history of Commits is now: A, B, C

enter image description here

You want to push you changes into Main branch on Origin, and you have a few different options:

  • Merge (without fast forward)
  • Rebase,
  • Stash and Pull.

Merge (aka. Merge without fast-forward)

If you were to fetch a local copy of Origin’s Main branch and merge it into your local FeatureA branch, you would create a commit for that merge, M. You local history on FeatureA would be: A, F1, F2, F3, M, where M is the merge commit.

enter image description here

You could then merge to Main (squashing if you wanted). Note that if you don’t squash, you will introduce a Merge commit into the Main commit history:

  • A, B, C, F1, F2, M.

You could avoid this by squashing your branch when merging to Main, as described above in the Squash section, resulting in: A B C F, like so:

enter image description here

Rebase

Rebase is another option to avoid introducing a merge commit into the history. It essentially takes your changes, and makes it as if you had begun on the latest Main, rather than on an outdated version of Main. For example, after rebasing your Feature branch would branch off from A, B, C, (instead of A, as it was originally). The result:

  • A, B, C, F1, F2, F3

enter image description here

  • A, B, C, F (with squash)

enter image description here

Note, there is no Merge commit, M

The way Git achieves this is to systematically--commit-by-commit--apply the changes from origin’s Main to your branch. The end result is as if you had not started your FeatureA branch in the past based off commit A, but as if you started all your changes on top of the latest Main.

The problem is, in the way this is done. For each commit that has to be applied into your FeatureA branch, git checks for merge conflicts, and you have to resolve them. If there has been more than one change to Main on Origin since your FeatureA branch, you can be resolving merge conflicts over and over again.

Perhaps a stash and pull is easier?

Stash and Pull

Stash your FeatureA, Fetch/Pull an up to date local copy of Main from Origin, and either create a new branch and apply your stash. (Or merge your new Main branch into your branch, and apply your stash. If doing the latter, squash to avoid a merge in the commit history.) Then you can push to Origin / create pull request.

坚持沉默 2024-08-31 09:19:42

合并和变基都保留提交历史记录,而压缩则不保留。保留提交历史记录会产生巨大的影响,我在以下场景中经历了惨痛的教训:

我们有 master、develop 和 feature 分支。功能是在开发过程中创建的,并在发布时合并到主版本中。 Hotfix 分支是从 master 创建并合并的(因此开发人员不知道这一点)。 Master 在发布后没有合并回开发,因此它们不同步,从 master 合并回开发显示更改,而从开发向前合并到 master 也显示更改(即使开发中没有任何更改)。

造成这种情况的原因是当 master 合并回开发时压缩了提交。进行定期合并以保留提交历史记录,解决了问题。从开发合并到主控现在没有显示出任何预期的变化。

Merge and rebase both retain commit history vs squash doesn't. Retaining commit history has a huge impact and I learned it the hard way in the following scenario:

We have master, develop and feature branches. Feature is created off of develop and merged to master upon release. Hotfix branch was created off of master and merged (so develop doesn't know about it). Master was not merged back to develop after release so they got out of sync where merge from master back into develop shows changes and forward merge from develop to master also shows changes (even when nothing in develop has changed).

The cause of this was squashing commits when master is merged back to develop. Doing a regular merge which keeps the commit history, fixed the problem. Merge from develop to master doesn't show any changes now as expected.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文