Git rebase 丢失了历史,那为什么要 rebase 呢?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5250817/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-19 05:10:12  来源:igfitidea点击:

Git rebase loses history, then why rebase?

gitversion-controlgit-rebasegit-merge

提问by ngephart

I've been looking into rebasing with Git over the past couple days. Most of the arguments for rebasing say that it cleans up the history and makes it more linear. If you do plain merges (for example), you get a history that shows when the history diverged and when it was brought back together. As far as I can tell, rebasing removes all that history. Question is this: why wouldn't you want the repo history to reflect all the ways the code developed, including where and how it diverged?

在过去的几天里,我一直在研究使用 Git 进行变基。大多数关于 rebase 的论点都说它清理了历史并使其更加线性。如果您进行简单的合并(例如),您会得到一个历史记录,显示历史何时发生分歧以及何时重新组合在一起。据我所知,变基会删除所有这些历史记录。问题是:为什么不希望 repo 历史反映代码开发的所有方式,包括它在哪里以及如何分歧?

采纳答案by poke

As far as I can tell, rebasing removes all that history.

据我所知,变基会删除所有这些历史记录。

That's not correct. Rebasing, as the name suggests, changes the baseof commits. Usually no commit is lost in that process (except that you don't get a merge commit). While your argument about keeping really everything of the development process inside the history the way it was done is correct, very often this leads to confusing histories.

那不正确。顾名思义,变基会更改提交的基础。通常在该过程中不会丢失任何提交(除非您没有获得合并提交)。虽然您关于将开发过程的所有内容真正保留在历史中的论点是正确的,但这通常会导致历史混乱。

Especially when working with others that each work on their own branches while requiringcertain changes from others to continue (for example A asks B to implement something so that A can use that feature in his own development), this leads to many merges. For example like this:

特别是当与其他人一起工作时,每个人都在自己的分支上工作,同时需要其他人的某些更改才能继续(例如,A 要求 B 实现一些东西,以便 A 可以在他自己的开发中使用该功能),这会导致许多合并。例如像这样:

     #--#--#--#--*-----*-----------------*---#---\         Branch B
    /           /     /                 /         \
---#-----#-----#-----#-----#-----#-----#-----#-----*       Branch A

In this example we have a branch that works separately for the time but constantly pulls in changes from the original branch (# are original commits, * are merges).

在这个例子中,我们有一个分支,它暂时单独工作,但不断地从原始分支中提取更改(# 是原始提交,* 是合并)。

Now if we do a rebase on Branch B before merging in back in, we could get the following:

现在,如果我们在重新合并之前对分支 B 进行变基,我们可以获得以下结果:

                             #--#--#--#--#---\         Branch B
                            /                 \
---#---#---#---#---#---#---#---#---------------*       Branch A

This represents the same actual changes, but B was rebased to some older commit on A, so all merges on B that were done before are no longer needed (because those changes are already there in that older commit). And all commits that are missing now, are the merges, which usually do not contain any information about the development process. (Note that in this example you could also rebase that last commit on A later on, to get a straight line, effectively removing any hints to the second branch)

这表示相同的实际更改,但 B 已重新基于 A 上的某个较旧提交,因此不再需要之前在 B 上完成的所有合并(因为这些更改已存在于该较旧提交中)。现在缺少的所有提交都是合并,通常不包含有关开发过程的任何信息。(请注意,在此示例中,您还可以稍后将最后一次提交重新设置为 A,以获得一条直线,从而有效地删除对第二个分支的任何提示)

回答by Nerian

Imagine you are working on a Secret Project of World Domination. There are three masterminds on this conspiracy:

想象一下,您正在从事一项统治世界的秘密计划。这个阴谋有三个策划者:

  • The Genius
  • The General
  • The Computer Hacker
  • 天才
  • 一般
  • 电脑黑客

And they all agree to come to their secret base in 1 week each one with 1 detailed plan.

他们都同意在 1 周内带着 1 个详细计划来到他们的秘密基地。

The computer hacker, being a pragmatic programmer, suggested that they use Git to store all the files of the plans. Each one will fork the initial project repo and they will merge all in one week.

电脑黑客是一个务实的程序员,建议他们使用 Git 来存储计划的所有文件。每个人都会分叉最初的项目回购,他们将在一周内合并。

They all agree and in the following days the story goes like this:

他们都同意,在接下来的日子里,故事是这样的:

The Genius

天才

He made a total of 70 commits, 10 each day.

他总共进行了 70 次提交,每天 10 次。

The General

一般

He spy the repo of their comrades and made an strategy to beat them. He made 3 commits, all the last day.

他窥探了他们同志的回购,并制定了击败他们的策略。在最后一天,他做了 3 次提交。

The Computer Hacker

电脑黑客

This pragmatic programmer used branches. He made 4 different plans, each one on a branch. Each branch was rebased to be just one commit.

这位务实的程序员使用了分支。他制定了 4 个不同的计划,每个计划都在一个分支上。每个分支都被重新定位为一个提交。

Seven days passed and the group meet again to merge all the plans into one master piece. All of them were eager to start so all of them tried to merge all the stuff on his own.

7天过去了,小组再次开会,将所有计划合并为一个杰作。他们都急于开始,所以他们都试图自己合并所有的东西。

Here goes the story:

故事是这样的:

The Genius

天才

He merged all the changes from the General's repo and then the Computer Hacker's one. And then, being a logic lover, he gave a look at the log. He expected to see a logical evolution of an idea, where the things were constructed upon the previous ideas-commits.

他合并了 General 的 repo 中的所有更改,然后合并了 Computer Hacker 的 repo。然后,作为一个逻辑爱好者,他看了看日志。他期望看到一个想法的逻辑演变,其中事物是基于先前的想法构建的。

But what the logs shown, was a myriad of commits of different ideas all mixed in the time line. One reader could not really understand the evolution, the reasoning of the commits just by reading the commits time line.

但是日志显示的是,在时间线上混合了无数不同想法的提交。一位读者无法通过阅读提交时间线来真正理解提交的演变和推理。

So he ended with a mess, that even a genius could't understand.

所以他的结局是一团糟,连天才都无法理解。

The General

一般

The General thought: Divide and conquer!

将军思想:分而治之!

And so he merged the repo of the Genius on his repo. He looked at the log and saw a bunch of commits from the Genius idea, which followed an understable progression, until the last day. The last day the ideas of the General and the Genius were mixed.

因此,他将 Genius 的回购合并到了他的回购中。他查看了日志,看到了一系列来自 Genius 想法的提交,这些提交遵循不稳定的进展,直到最后一天。最后一天将军和天才的想法混合在一起。

He was spying the The computer Hacker and knew about the Rebase solution. So he did a rebase of the his own idea and try the merge again.

他正在监视 The computer Hacker 并且知道 Rebase 解决方案。因此,他对自己的想法进行了重新设置,然后再次尝试合并。

Now the log showed a logical progression every day.

现在日志显示每天的逻辑进展。

The Computer Hacker

电脑黑客

This pragmatic programmer created a integration branch for the Genius idea, another one for the General idea and another one for his own ideas. He did a rebase to each branch. And then he merged all in master.

这位务实的程序员为 Genius 想法创建了一个集成分支,另一个为 General 想法创建了一个集成分支,另一个为他自己的想法创建了一个集成分支。他对每个分支都做了rebase。然后他将所有内容合并到 master 中。

And all of his team mates saw that his log was great. It was simple. It was understable at first sight.

而且他的所有队友都看到他的日志很棒。这很简单。乍一看,这很不稳定。

If an idea introduced a problem, it was clear in which commit was introduced, for there was just one.

如果一个想法引入了一个问题,很明显是在哪个提交中引入的,因为只有一个。

They ended conquering all the world and they vanished the use of Subversion.

他们最终征服了整个世界,并且不再使用 Subversion。

And all were happy.

而且大家都很开心。

回答by VonC

You do a rebase mainly to rework your local commits (the one you haven't pushed yet) on top of a remote branch (you just fetch), in order to solve any conflict locally(i.e. before you push them back to the upstream repo).
See "git workflow and rebase vs merge questions" and, quite detailed: "git rebase vs git merge" .

您执行 rebase 主要是为了在远程分支(您只是获取)之上重新处理您的本地提交(您尚未推送的提交),以便在本地解决任何冲突(即在您将它们推回上游存储库之前) )。
请参阅“ git 工作流程和 rebase 与合并问题”以及非常详细的:“ git rebase 与 git merge”。

But rebase isn't limited to that scenario, and combined with "--interactive", it allows for some local re-ordering and cleaning of your history. See also "Trimming GIT Checkins/Squashing GIT History".

但是 rebase 不限于这种情况,并且结合“--interactive”,它允许对您的历史进行一些本地重新排序和清理。另请参阅“修剪 GIT 签入/压缩 GIT 历史记录”。

why wouldn't you want the repo history to reflect all the ways the code developed, including where and how it diverged

你为什么不希望 repo 历史反映代码开发的所有方式,包括它在哪里以及如何分歧

  • In a centralized VCS, it is important to never lose the history, and it should indeed reflect "all the ways the code developed".
  • In a distributed VCS, where you can do all kind of local experiments before publishingsome of your branches to upstream, it makes less sense to keep everythingwithin the history: not everyone needs to clone and see all of your branches, tests, alternatives, and so on.
  • 在中心化的 VCS 中,重要的是永远不会丢失历史,它确实应该反映“代码开发的所有方式”。
  • 在分布式 VCS 中,您可以在将某些分支发布到上游之前进行各种本地实验,将所有内容保留在历史记录中意义不大:并非每个人都需要克隆并查看您的所有分支、测试、替代方案、等等。

回答by mda

If you make a mistake on a public repository and no one has forked/merged/pulled from it yet, you can save face and confusion:

如果您在公共存储库上犯了一个错误并且还没有人从它分叉/合并/拉出,您可以避免面子和困惑:

git reset --hard [SHAnumber]

git rebase -f master

git push -f origin HEAD:master

To empty the trash:

要清空垃圾箱:

git gc