git rebase提交不可重复

时间:2019-07-03 20:59:05

标签: git rebase

当我有两个指向同一提交的分支,然后将它们都重新建立到同一新的基本提交时,为什么重新建立了分支的分支发散了?

我希望它们会以相同的方式重放,并最终指向相同的新提交。

touch a; touch b; touch c
git add a
git commit -m 'a'
git add b
git commit -m 'b'
git checkout -b branch-01 HEAD^
git add c
git commit -m 'c'
git checkout -b branch-02
git rebase master branch-01
git rebase master branch-02
git log --all --graph --decorate --pretty=oneline --abbrev-commit

2 个答案:

答案 0 :(得分:3)

要说明发生了什么,请尝试以下实验:

$ git checkout -b exp1 master
<modify some file; git add; all the usual stuff here>
$ git commit -m commit-on-exp1

此时,您有一个名为exp1的实验分支,其中一个提交不在master上:

...--A--B   <-- master
         \
          C1   <-- exp1

现在,我们将创建一个指向提交exp2的{​​{1}}分支,并将提交B复制到分支C1上的新提交C2: / p>

exp2

结果是:

$ git checkout -b exp2 master
$ git cherry-pick exp1

现在让我们重复 C2 <-- exp2 / ...--A--B <-- master \ C1 <-- exp1 ,创建它,使其指向提交exp3,然后再次复制B

exp1

您是否期望$ git checkout -b exp3 master $ git cherry-pick exp1 指向提交exp3?如果是这样,为什么?为什么C2指向exp2而不是像C2那样指向C1

这里的问题是提交exp1C1(现在C2上的C3一点一点相同。的确,他们具有相同的快照,相同的 author ,相同的 log消息,甚至是相同的父级(所有三个人都有{{1 }}作为他们的单亲家长)。但是,这三个提交人的提交时间和时间戳都不同,因此它们是不同的提交。 (使用exp3来显示日期和时间标记。Cherry-pick(因此也要重新设置基准)会复制包括日期和时间的原始作者信息,但是由于它是新提交,因此使用当前日期。以及提交者时间戳的时间。)


通常,当您使用B时,您将获得Git复制提交,就好像是通过樱桃拾取。复制结束时,Git然后移动分支名称,使其指向最后复制的提交:

git show --pretty=fuller

成为:

git rebase

这里...--A--B <-- mainline \ C--D--E <-- sidebranch C'-D'-E' <-- sidebranch / ...--A--B <-- mainline \ C--D--E 的副本,已更改为使用C'作为其父对象(并且可能与C的源快照不同),{{1} }是B的副本,而CD'的副本。只有一个名称指向D;该名称现在已移动,因此没有名称指向E'

但是如果您最初有两个 名称指向E,那么这两个名称中的一个仍指向E

E

如果您要求Git再次复制E,它会这样做-但是新副本不是E,因为它们具有新的日期和时间戳记。这样您就可以看到自己的照片了。

因此,如果您要在复制某些提交链时移动两个或更多名称,可以使用 C'-D'-E' <-- sidebranch / ...--A--B <-- mainline \ C--D--E <-- other-side-branch 移动名字,但是您将必须进行其他操作(例如运行C-D-E)以移动其余名称,以使它们指向在一次变基期间生成的提交副本。

(我一直想拥有一个C'-D'-E'更好的版本,该版本可以自动执行此操作,但是通常这显然是一个难题。)

答案 1 :(得分:0)

为什么分支分散了

在用于计算git commit的哈希的元数据中,不仅存在AuthorAuthorDate;还有一个Committer和一个CommitterDate。可以通过运行例如

来查看
git show --pretty=fuller branch-01 branch-02

每个rebase(或cherry-pick)命令都会根据当前时间在新提交中更新提交者日期。由于问题中的两个重新基准是在不同的时间执行的,因此它们的CommitterDate不同,因此它们的元数据也不同,因此它们的提交哈希也不同。

如何一起移动分支/标记

torek correctly notes

  

如果您要在复制某些提交链时移动两个或更多名称,可以使用git rebase移动名字,但是可以做一些事情否则,例如运行git branch -f,以移动其余的名称,以便它们指向在一次重设基准期间创建的提交副本。

关于作者与提交者

来自Difference between author and committer in Git?

  

作者是最初编写代码的人。另一方面,假定提交者是代表原始作者提交代码的人。这在Git中很重要,因为Git允许您重写历史记录或代表他人应用补丁。 FREE online Pro Git book这样解释:

     
    

您可能想知道 author committer 之间有什么区别。 作者是最初编写补丁的人,而 committer 是上次应用补丁的人。因此,如果您向项目发送补丁程序,并且其中一个核心成员应用了该补丁程序,那么你们俩都将获得荣誉-您作为作者,而核心成员作为提交者。