Git rebase方法以避免重复提交

时间:2017-09-25 05:31:03

标签: git github version-control

当我尝试将rebase从master转到我的开发分支时,我遇到了一个奇怪的问题。主人和开发部门都在进行一些工作。

为了从主人那里得到改变,我在下面做

git checkout dev
git rebase master

这很好用。但是 -

  1. 当我这样做时,dev分支提交正在重复 git checkout dev git add . git commit -m 'some change' git push git rebase master 提交some change在dev分支的git项目历史中重复。它还会创建循环。
  2. 如果我在推动dev分支更改之前执行git rebase master那么它运行良好,我可以在项目中看到线性历史记录。
  3. 我不确定为什么会这样。这在我看来是奇怪的行为。如果有人能解释,请帮忙。

    项目历史 提交b48659d正在重复(我做37c07a4的原始提交),当第一次推送然后在dev分支中进行rebase。

    *   fbadb86 (HEAD -> dev) Merge branch 'dev' of *******
    |\  
    | * b48659d (origin/dev) sample added in dev branch --> did rebase after push and got this commit again
    * | 37c07a4 sample added in dev branch --> commit + push
    * | 46c1f40 (origin/master, origin/HEAD, master) master file added in master branch --> commit + push
    |/  
    * 5baae80 first commit
    

    这种情况发生在推送之后的所有提交中。这导致了重新定位中的大量问题,因为提交正在重复,并且即使我自己的代码更改来自先前的提交,也会产生很多冲突。

1 个答案:

答案 0 :(得分:1)

所有提交始终是只读的。它们也是永久性的,有一些例外(与任何人是否可以找到它们有关)。这意味着git rebase 副本提交。这是它的工作!

让我们来看看您的git log --graph --oneline ...输出,但让我们开始更简单一点:

  * b48659d (dev) ...
* | 46c1f40 (origin/master, origin/HEAD, master) ...
|/
* 5baae80 first commit

请注意缩短的哈希ID,例如5baae80b48659d。这些是真正的名字"每个提交,缩短为只有7个字符,因为它通常就足够了。 1 每个提交记录提交的ID,Git使用这些父提交哈希值从更近期的分支提示提交开始,逐步跟踪每个提交历史记录。分支dev的提示提交现在为37c07a4...

5baae80--46c1f40   <-- master, origin/master
       \
        b48659d   <-- dev

这些提交都不能改变!

您现在git pushorigingit push命令调用第二个Git,在作为origin的机器上调用,然后移交你没有的提交,每个人都同意他们的ID。然后你的Git要求他们的Git将dev设置为与origin/dev相同的值devb48659d...如果他们同意此请求, Git记得他们现在他们的 dev - 你的origin/dev - 指向b48659d,就像我们在这里画的那样,所以现在我们有了这个:

5baae80--46c1f40   <-- master, origin/master
       \
        b48659d   <-- dev, origin/dev

此时,您运行git rebase,这就是事情开始出错的地方。

1 Git现在动态选择缩短的长度,而不是总是使用7,但默认情况下以7开头。您可以随时使用更多:全名当前为40个字符。

Rebase复制提交,然后移动分支标签

git rebase命令无法更改任何现有提交,因为Git中的 nothing 可以做到这一点。 Git的目的是让这个变得不可能。所以它甚至没有尝试。相反,它 copy 提交。

复制提交时,Git需要两条信息:

  • 应该复制什么提交?
  • 副本应放在哪里?

Git获取第一个 - 通过列表提交进行复制的提交列表,从HEAD开始并向后工作,在您选择的某个时刻停止。 (这个列表是向后的,所以它必须反转它。)Git得到第二个 - 目标&#34;复制后&#34;从您提供的论点开始,例如master

在这种情况下,HEAD名称为dev(因为您在启动rebase之前运行git checkout dev),因此要复制的提交以名称{{1点:

dev

因此,我们将复制一系列在5baae80--46c1f40 <-- master, origin/master \ b48659d <-- dev (HEAD), origin/dev 停止的提交。

复制它们的地方来自你的论点b48659d。名称master标识提交master,因此副本将追溯46c1f40

棘手的部分是Git如何计算提交而不是进行复制的内容。它是从46c1f40开始并向后工作的。你可以想象Git会暂时将这些提交中的每个提交着色。这会将Git带到b48659d,它具有 no 父提交(它是存储库中的第一个提交,因此它不能拥有父提交)。这会停止步行,因此这两个提交被涂成绿色。然后Git从您通过名称 - 5baae80指定的提交开始 - 并暂时将提交绘制为红色。 46c1f40的父级是46c1f40,因此Git将这一个描绘成红色(不要复制),并尝试继续绘制其父级以绘制红色。没有父母,所以我们完成了临时绘画,留下了一个绿色提交,5baae80

这是要复制的提交列表。 (它倒退了,但无论如何它只有一个条目,所以逆转它什么都不做。)

现在Git开始复制过程。每个要复制的提交都会被复制,就像b48659d一样(如果您使用git cherry-pick,它会被樱桃选择复制)。这使 new 提交。

现有git rebase -i的新提交是b48659d。让我们把它画进去:

37c07a4

现在已经复制了整个提交列表, 37c07a4 / 5baae80--46c1f40 <-- master, origin/master \ b48659d <-- dev, origin/dev 做了最后一件事。它将名称git rebase从原始提交字符串中删除,并将其粘贴到新副本上。结果是:

dev

您可以在问题中引用的 37c07a4 <-- dev (HEAD) / 5baae80--46c1f40 <-- master, origin/master \ b48659d <-- origin/dev 输出中看到这一点。

最后一次提交来自哪里?

剩下的一个问题是,这是从哪里来的:

git log --graph

该提交存在是因为您运行了* fbadb86 (HEAD -> dev) Merge branch 'dev' of *******

您可能通过运行git merge来运行git merge。默认情况下,git pull为您运行git pull,然后为您运行git fetch。 (我建议Git中的初学者根本不要使用git merge:它做了什么,以及它做的方式,过于混乱。将其分成git pull,然后迟早会被分成一秒钟Git命令,有时为git fetch,有时为git rebase。)

一般来说,git merge的作用是尝试将两个独立的&#34;开发线组合在一起&#34;。给出这样的图表:

git merge

Git或多或少地认为,在您撰写 37c07a4 <-- dev (HEAD) / 5baae80--46c1f40 \ b48659d <-- origin/dev 时,其他人写了b48659dorigin/dev)。为了组合它们,Git找到了他们的&#34;合并基地&#34;,这是这两条线再次连接的地方。按照眼睛的线条清楚地表明:那是37c07a4。所以Git创建了一个新的合并提交,这是一个与两个父级的提交。让我们在:

中画出来
5baae80

这就是您现在所看到的 37c07a4--fbadb86 <-- dev (HEAD) / / 5baae80--46c1f40 / \ __-------- b48659d <-- origin/dev 输出中的内容(git log --graph --oneline ...master箭头也添加了 - 我把它们排除了因为它们太难了画这种方式)。

这里的根本错误是在其他人已经拥有的提交上运行origin/master。在这种情况下,git rebase处的其他Git已经提交了origin。您无法更改该提交,因此在制作新副本时,您将停止使用 b48659d,但他们仍然拥有他们的。最终你必须加入他们的#34;回到&#34;你的副本&#34;,通过合并,给出这个相当混乱的画面。

(此规则有一个例外:如果您可以说服其他人b48659d放弃,并切换他们的b48659d以使用您的新规则相反,你仍然可以改变。但是,你是否可以,以及如何,是另一个问题。)