Git: 有没有办法将同一分支 (FF) 上的两个提交重新合并到一个新分支?
Git: Is there a way to re-merge two commits on the same branch (FF) to a new branch?
我正在做一个小组项目,在进行了一些更改并推送到原点后(调用此提交 A
),另一个人似乎强制推送了他们的更改,从而恢复了我的提交(调用此提交 B
).
在我推送之前,我们有这样的东西:
A (master)
| B (their-master)
| |
| /
Z (origin/master)
我推送后,我们得到
B (their-master)
|
A (origin/master, master)
| /
Z
他们拉取我的提交,还原它并推送
B (origin/master, their-master)
|
A (master)
|
Z
我不知不觉地拉了一下,结果是
B (origin/master, master, their-master)
|
A
|
Z
我想在 A
创建一个新分支(例如 "re-merge"),将 B
提取到新分支以手动解决合并冲突。然后将它合并回 master 中,这样我们就可以保留其他人的更改并绕过强制提交。
D (origin/master, master, re-merge)
C (re-merge) | \
| | C
B (origin/master, master) --> B |
| / | /
A A
| |
Z Z
有没有办法在不在 A
处创建分支并手动比较文件以找到我想要保留的内容的情况下执行此操作?这将迫使我放弃 master 分支,因为 B
中的强制更改现在似乎被认为是从 A
快速转发。除了其他从事不相关事情的人也在致力于掌握。
谢谢。
可能他们所做的是保存某些文件(可能是所有有问题的文件)的版本,然后在根据您的提交重新设置他们的工作后,复制他们保存的文件版本,从而恢复您自己的版本工作(没有使用实际的 git revert
,但仍然完全没有共享工作的想法 :-))。
你是对的,你不能只是合并,因为你的提交 A
已经包含在当前提交的祖先中。
虽然不合并也很容易恢复。你想要的是 git 查看你在提交 Z
和提交 A
:
之间做了什么
$ git diff <rev-id-for-Z> <rev-id-for-A>
或者,由于您的 HEAD
提交是 B
,因此 HEAD~1
(又名 B~1
B^
又名 HEAD^
等)是 A
,而 HEAD~2
是 Z
:
$ git diff HEAD~2 HEAD~1
然后进行差异化——好吧,也许是差异化的一部分;如果需要,我们会尝试 - 并将其应用于当前工作树并根据结果进行新提交:
$ git diff HEAD~2 HEAD~1 | git apply && git commit
有一个命令可以为您完成这一切:git cherry-pick
。您将 cherry-pick
指向一个特定的提交,并将该提交与它的前身进行比较,将生成的差异应用于您当前的工作树(如果可以的话),并使用一条提交消息提交结果,说明这是一个樱桃-选择另一个提交。
如果您想要不同的提交消息,您可以 git commit --amend
结果,或者使用 -n
或 --no-commit
选项,告诉 cherry-pick 不要进行提交(这也允许工作树已经有其他更改)。
如果 cherry-pick 不干净——例如,如果需要手动合并——你将不得不再次做一些清理工作。或者,您可以自己 运行 git diff ... | git apply
,在这种情况下,您可以限制差异化的文件集:
$ git diff HEAD~2 HEAD~1 -- path1 path2 | git apply
等等。
(请注意,顺便说一下,与 diff-and-apply 不同,cherry-pick
可以直接访问提交图。因此它可以自动执行合并类型的工作,使其比仅应用补丁更智能。 diff 文本为 apply
留下了足够的线索来使用它的 -3
选项来做同样的事情,但你必须指示 apply
这样做。最后,作为旁注,当你发现自己在做git diff
某个提交的父项与该提交的对比,这只是 git show
的差异部分,所以只要你正在做的任何事情都可以容忍 "leading text",你实际上可以只使用 git show
在目标提交上,而不是其父项与自身的显式差异。但我认为,这并不像 diff-pipe-to-apply 序列那样清楚,这就是我以这种方式说明的原因。)
我正在做一个小组项目,在进行了一些更改并推送到原点后(调用此提交 A
),另一个人似乎强制推送了他们的更改,从而恢复了我的提交(调用此提交 B
).
在我推送之前,我们有这样的东西:
A (master)
| B (their-master)
| |
| /
Z (origin/master)
我推送后,我们得到
B (their-master)
|
A (origin/master, master)
| /
Z
他们拉取我的提交,还原它并推送
B (origin/master, their-master)
|
A (master)
|
Z
我不知不觉地拉了一下,结果是
B (origin/master, master, their-master)
|
A
|
Z
我想在 A
创建一个新分支(例如 "re-merge"),将 B
提取到新分支以手动解决合并冲突。然后将它合并回 master 中,这样我们就可以保留其他人的更改并绕过强制提交。
D (origin/master, master, re-merge)
C (re-merge) | \
| | C
B (origin/master, master) --> B |
| / | /
A A
| |
Z Z
有没有办法在不在 A
处创建分支并手动比较文件以找到我想要保留的内容的情况下执行此操作?这将迫使我放弃 master 分支,因为 B
中的强制更改现在似乎被认为是从 A
快速转发。除了其他从事不相关事情的人也在致力于掌握。
谢谢。
可能他们所做的是保存某些文件(可能是所有有问题的文件)的版本,然后在根据您的提交重新设置他们的工作后,复制他们保存的文件版本,从而恢复您自己的版本工作(没有使用实际的 git revert
,但仍然完全没有共享工作的想法 :-))。
你是对的,你不能只是合并,因为你的提交 A
已经包含在当前提交的祖先中。
虽然不合并也很容易恢复。你想要的是 git 查看你在提交 Z
和提交 A
:
$ git diff <rev-id-for-Z> <rev-id-for-A>
或者,由于您的 HEAD
提交是 B
,因此 HEAD~1
(又名 B~1
B^
又名 HEAD^
等)是 A
,而 HEAD~2
是 Z
:
$ git diff HEAD~2 HEAD~1
然后进行差异化——好吧,也许是差异化的一部分;如果需要,我们会尝试 - 并将其应用于当前工作树并根据结果进行新提交:
$ git diff HEAD~2 HEAD~1 | git apply && git commit
有一个命令可以为您完成这一切:git cherry-pick
。您将 cherry-pick
指向一个特定的提交,并将该提交与它的前身进行比较,将生成的差异应用于您当前的工作树(如果可以的话),并使用一条提交消息提交结果,说明这是一个樱桃-选择另一个提交。
如果您想要不同的提交消息,您可以 git commit --amend
结果,或者使用 -n
或 --no-commit
选项,告诉 cherry-pick 不要进行提交(这也允许工作树已经有其他更改)。
如果 cherry-pick 不干净——例如,如果需要手动合并——你将不得不再次做一些清理工作。或者,您可以自己 运行 git diff ... | git apply
,在这种情况下,您可以限制差异化的文件集:
$ git diff HEAD~2 HEAD~1 -- path1 path2 | git apply
等等。
(请注意,顺便说一下,与 diff-and-apply 不同,cherry-pick
可以直接访问提交图。因此它可以自动执行合并类型的工作,使其比仅应用补丁更智能。 diff 文本为 apply
留下了足够的线索来使用它的 -3
选项来做同样的事情,但你必须指示 apply
这样做。最后,作为旁注,当你发现自己在做git diff
某个提交的父项与该提交的对比,这只是 git show
的差异部分,所以只要你正在做的任何事情都可以容忍 "leading text",你实际上可以只使用 git show
在目标提交上,而不是其父项与自身的显式差异。但我认为,这并不像 diff-pipe-to-apply 序列那样清楚,这就是我以这种方式说明的原因。)