我有一个历史悠久的初级开发分支(A)。 A中的所有版本提交都被标记为此类。我签出了A的根提交,并分支到测试(B)中。
因此,我有一个主要分支A,分支B的头部指向A的根提交。我的目标是通过合并从A到B的每个带标记的提交来创建所有版本的历史记录。
从A到B的第一次合并按预期进行,没有冲突。
$git checkout B
$git merge [release-commit-ID] --squash
$git commit -m "release#"
第一个提交工作得很好,但是所有其他提交都将所有合并提交视为完全冲突。我看到B的根与A的根相同,但是从A中的第一个发布提交到B中的第一个压缩合并提交之后,没有共享历史被识别。是什么引起冲突以及如何获取共享历史被认可?
答案 0 :(得分:1)
是什么导致冲突?如何识别共享历史记录?
没有共享的历史记录(或者说不够)。没有什么可识别的,这就是为什么存在冲突。
关键是--squash
标志:
$ git checkout B $ git merge [release-commit-ID] --squash
第一步是将您的HEAD
附加到分支名称B
上,检查出B
所标识的提交名称:
...--*--C--D--E <-- B (HEAD)
\
F--G--H <-- somebranch
这里的名称B
标识提交E
(每个字母代表真实的哈希ID)。提交*
(我将其命名为B
,但您使用了该名称作为分支)是两个开发流分开的地方,这意味着当我们向后工作时(如Git所做的那样)这是他们聚在一起的关键。现在,您运行git merge --squash <hash>
,其中<hash>
标识提交F
或G
或H
,因此Git将提交*
的内容与提交E
的内容以了解您所做的更改:
git diff --find-renames <hash-of-*> <hash-of-E> # what we changed
并重复G
:
git diff --find-renames <hash-of-*> <hash-of-G> # what they changed
Git现在将这两组更改合并,将合并的更改应用于*
的内容,并进行新的提交。
如果您不使用--squash
,则Git会记录有两个父母的新提交:
...--*--C--D--E--I <-- B (HEAD)
\ /
F-------G--H <-- somebranch
,两行之间的最新公共起点是提交G
。但是,如果您使用使用--squash
,则Git仅使用一个父级记录新提交:
...--*--C--D--E--I <-- B (HEAD)
\
F--G--H <-- somebranch
,现在通用起点不变。 G
中的所有工作都在提交I
中,但是提交I
不能记住 为什么。提交git merge
以后的H
必须从提交*
重新开始。
Git不会阻止您在分支somebranch
上进行开发,但是通常,在git merge --squash
之后,您应该将合并 from 的分支视为“已死” ”,然后完全停止使用它。将G
与git merge --squash
合并后,我们应该完全停止使用F
和G
。这意味着我们还必须完全停止使用H
。如果H
有用,我们应该将其复制到新的不同提交中:
$ git checkout -b newbranch B
给予我们
...--*--C--D--E--I <-- B, newbranch (HEAD)
\ /
F-------G--H <-- somebranch
其次:
$ git cherry-pick somebranch # or <hash of H>
要将H
复制到非常相似但不完全相同的地方,请提交H'
:
H' <-- newbranch (HEAD)
/
...--*--C--D--E--I <-- B
\ /
F-------G--H <-- somebranch
我们现在可以丢弃somebranch
:
$ git branch -D somebranch
,如果愿意,可以将newbranch
重命名为somebranch
。
(请注意,我们可以使用git rebase --onto
和git checkout somebranch; git rebase --onto B <hash of G>
使用git cherry-pick
一步完成此带有名称移动的操作。尽管如此,请注意{{1 }}无法复制合并提交,并且正在使用我们要杀死的提交的任何人-在F-G-H
链上-必须这样做,然后再将其复制保存东西。因此,在使用--squash
之前,请确保您了解所有含义。)