为什么分支 B 在第一次合并提交后从 A 到 B 的所有合并提交都有冲突?
Why does branch B have conflicts in all merge commits from A to B after the first merge commit?
我有一个历史悠久的主要开发分支 (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 的第一个压缩合并提交之后,没有识别到共享历史。是什么导致了冲突以及如何获得共享历史被认可?
What is causing the conflicts and how do I get shared history to be recognized?
没有共享历史记录(或者说,还不够)。没有什么可以识别的,所以才会有冲突。
关键是--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 比较内容commit *
到 commit 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用两个记录新的提交parents:
...--*--C--D--E--I <-- B (HEAD)
\ /
F-------G--H <-- somebranch
现在两条线之间最近的共同起点是提交 G
。但是如果你 do 使用 --squash
,Git 只用 one parent 记录新的提交:
...--*--C--D--E--I <-- B (HEAD)
\
F--G--H <-- somebranch
现在共同起点不变。通过 G
的所有工作都在提交 I
中,但提交 I
不 记得 为什么那个工作在那里。来自提交 H
的未来 git merge
必须在提交 *
.
重新开始
Git不会阻止你在分支somebranch
上开发,但一般来说,在git merge --squash
之后,你应该考虑你合并的分支 成为 "dead" 并完全停止使用它。一旦我们将 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>
一步完成此 copy-with-name-moving 事情。无论如何,请注意 git cherry-pick
无法复制合并提交,并且 任何人 使用我们想要杀死的提交 - 这里是 F-G-H
链 - 必须做这个 killing-off-with-copying-the-ones-to-save 事情。所以在使用 --squash
之前,请确保您了解所有含义。)
我有一个历史悠久的主要开发分支 (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 的第一个压缩合并提交之后,没有识别到共享历史。是什么导致了冲突以及如何获得共享历史被认可?
What is causing the conflicts and how do I get shared history to be recognized?
没有共享历史记录(或者说,还不够)。没有什么可以识别的,所以才会有冲突。
关键是--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 比较内容commit *
到 commit 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用两个记录新的提交parents:
...--*--C--D--E--I <-- B (HEAD)
\ /
F-------G--H <-- somebranch
现在两条线之间最近的共同起点是提交 G
。但是如果你 do 使用 --squash
,Git 只用 one parent 记录新的提交:
...--*--C--D--E--I <-- B (HEAD)
\
F--G--H <-- somebranch
现在共同起点不变。通过 G
的所有工作都在提交 I
中,但提交 I
不 记得 为什么那个工作在那里。来自提交 H
的未来 git merge
必须在提交 *
.
Git不会阻止你在分支somebranch
上开发,但一般来说,在git merge --squash
之后,你应该考虑你合并的分支 成为 "dead" 并完全停止使用它。一旦我们将 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>
一步完成此 copy-with-name-moving 事情。无论如何,请注意 git cherry-pick
无法复制合并提交,并且 任何人 使用我们想要杀死的提交 - 这里是 F-G-H
链 - 必须做这个 killing-off-with-copying-the-ones-to-save 事情。所以在使用 --squash
之前,请确保您了解所有含义。)