当我有两个指向同一提交的分支,然后将它们都重新建立到同一新的基本提交时,为什么重新建立了分支的分支发散了?
我希望它们会以相同的方式重放,并最终指向相同的新提交。
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
答案 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
?
这里的问题是提交exp1
和C1
(现在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
的副本,而C
是D'
的副本。只有一个名称指向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的哈希的元数据中,不仅存在Author
和AuthorDate
;还有一个Committer
和一个CommitterDate
。可以通过运行例如
git show --pretty=fuller branch-01 branch-02
每个rebase
(或cherry-pick
)命令都会根据当前时间在新提交中更新提交者日期。由于问题中的两个重新基准是在不同的时间执行的,因此它们的CommitterDate
不同,因此它们的元数据也不同,因此它们的提交哈希也不同。
如果您要在复制某些提交链时移动两个或更多名称,可以使用
git rebase
移动名字,但是可以做一些事情否则,例如运行git branch -f
,以移动其余的名称,以便它们指向在一次重设基准期间创建的提交副本。
来自Difference between author and committer in Git?:
作者是最初编写代码的人。另一方面,假定提交者是代表原始作者提交代码的人。这在Git中很重要,因为Git允许您重写历史记录或代表他人应用补丁。 FREE online Pro Git book这样解释:
您可能想知道 author 和 committer 之间有什么区别。 作者是最初编写补丁的人,而 committer 是上次应用补丁的人。因此,如果您向项目发送补丁程序,并且其中一个核心成员应用了该补丁程序,那么你们俩都将获得荣誉-您作为作者,而核心成员作为提交者。