在所有后续提交中删除合并和取消合并此功能的功能
Delete a feature merged and unmerged this feature in all following commits
我是 git 的新手,无法在互联网上找到这个问题的答案,但可能有人问过。
所以假设我的默认分支是 develop
。我从 develop 创建了一个名为 feature/test
的分支,在这个分支上做了一些提交,然后将它合并到 develop
.
---1---2---3---4---M---5---6---7--- (develop)
\ /
A---B (feature/new)
合并后 M
,我继续我的开发项目,进行了几次提交。
但现在我想从分支之后的所有提交中取消合并功能分支,就像分支 develop
从未合并过 feature/new
.
这就是我喜欢的东西:
---1---2---3---4---5'---6'---7'--- (develop)
\
A---B (feature/new)
如您所见,M
之后的所有提交都被修改以撤消删除合并带来的修改。
是否可以这样做,我应该使用哪个命令?
谢谢
有多种方法可以做到。
要获得您在图片中描述的历史,您需要重写历史。你应该知道,如果这个 repo 与其他人共享,并且如果你想要重写的历史已经共享(推送到远程),那么正确地做它需要一些协调 - 因为重写共享历史会导致错误情况,如果解析不正确,将导致您的工作无法完成。
就是说,为了避免重写历史,您可以使用 git revert
(或等价物)。还原合并 也 有成本,并且无论您是否与其他人共享历史记录,这些成本都适用。
因此,一般来说,最好避免合并以后可能必须“取消合并”的分支。但无法改变过去,您将不得不充分利用现有的选择。
要决定是否应该重写历史记录,我会参考 git rebase
文档 (https://git-scm.com/docs/git-rebase) in the section "Recovering From Upstream Rebase". You might also look at the git revert
docs regarding merges (https://git-scm.com/docs/git-revert)。然后根据您的决定,您可以执行以下操作之一:
改写历史
因此:完成您所要求的最简单方法是
git rebase --onto develop~4 develop~3 develop
这会获取您想保留的提交,为它们计算补丁,并将这些补丁应用到新的父级;一些细节:
表达式 develop~4
和 develop~3
特定于您的示例。
develop~4
指的是您从 develop
指向的提交开始,通过四次“第一父”指针找到的提交。这导致 4
。通过将其作为 --onto
参数,您告诉 rebase
它计算的补丁应该从这里开始应用。
同样develop~3
通向M
,所以这是“上游”。这意味着 M
和 M
可访问的任何提交(通过父指针)都不会用于创建补丁。 (如果你没有使用 --onto
upsteram 也会在应用补丁的地方发挥作用;但在这里我们确实使用了 --onto
所以这无关紧要。)
应用补丁时,可能会发生冲突。那是因为 5
、6
或 7
中的某些内容可能会编辑已被 M
编辑过的行(或“足够接近”由 M
,导致 git 不确定是否存在问题)。任何可靠的方法来执行您所要求的操作都会产生相同的冲突,因此您只需要弄清楚如果合并从未发生过,更改“应该”是什么样子。
如果 develop
存在于远程中,并且如果 M
已经被推送到该远程,那么默认情况下 git 将拒绝推送此更改的结果(因为它从分支历史中删除 M
)。您可以使用 push
命令的 --force-with-lease
选项覆盖它。 (有些人说使用 -f
选项,但是虽然这样更容易输入,但也不太安全。 -f
不会检查你不知道的新提交是否已被推送到develop
;--force-with-lease
会。)
不重写历史
如果您不能(或不想)协调历史记录重写,那么您必须接受您推送的任何历史记录都是不可变的。在这种情况下,您可以恢复合并。
git revert -m 1 develop~3
-m
选项告诉 git 你要“恢复到”哪个合并的父项;所以通过说 -m 1
,你有效地撤消了分支的更改。
就像 history-rewrite 方法一样,这可能会发生冲突,需要手动解决冲突。最终结果将是
1 -- 2 -- 3 -- 4 -- M -- 5 -- 6 -- 7 -- !AB <--(develop)
\ /
A --- B <--(feature/new)
其中 !AB
反转 A
和 B
的更改(已合并到 M
)。
因为 A
和 B
还在 develop
的历史中,如果你以后想要 re-merge 它们并不简单。您要么必须还原 !AB
,要么使用 rebase -f
在 mreging 之前重写 feature/new
的历史记录。
我是 git 的新手,无法在互联网上找到这个问题的答案,但可能有人问过。
所以假设我的默认分支是 develop
。我从 develop 创建了一个名为 feature/test
的分支,在这个分支上做了一些提交,然后将它合并到 develop
.
---1---2---3---4---M---5---6---7--- (develop)
\ /
A---B (feature/new)
合并后 M
,我继续我的开发项目,进行了几次提交。
但现在我想从分支之后的所有提交中取消合并功能分支,就像分支 develop
从未合并过 feature/new
.
这就是我喜欢的东西:
---1---2---3---4---5'---6'---7'--- (develop)
\
A---B (feature/new)
如您所见,M
之后的所有提交都被修改以撤消删除合并带来的修改。
是否可以这样做,我应该使用哪个命令?
谢谢
有多种方法可以做到。
要获得您在图片中描述的历史,您需要重写历史。你应该知道,如果这个 repo 与其他人共享,并且如果你想要重写的历史已经共享(推送到远程),那么正确地做它需要一些协调 - 因为重写共享历史会导致错误情况,如果解析不正确,将导致您的工作无法完成。
就是说,为了避免重写历史,您可以使用 git revert
(或等价物)。还原合并 也 有成本,并且无论您是否与其他人共享历史记录,这些成本都适用。
因此,一般来说,最好避免合并以后可能必须“取消合并”的分支。但无法改变过去,您将不得不充分利用现有的选择。
要决定是否应该重写历史记录,我会参考 git rebase
文档 (https://git-scm.com/docs/git-rebase) in the section "Recovering From Upstream Rebase". You might also look at the git revert
docs regarding merges (https://git-scm.com/docs/git-revert)。然后根据您的决定,您可以执行以下操作之一:
改写历史
因此:完成您所要求的最简单方法是
git rebase --onto develop~4 develop~3 develop
这会获取您想保留的提交,为它们计算补丁,并将这些补丁应用到新的父级;一些细节:
表达式 develop~4
和 develop~3
特定于您的示例。
develop~4
指的是您从 develop
指向的提交开始,通过四次“第一父”指针找到的提交。这导致 4
。通过将其作为 --onto
参数,您告诉 rebase
它计算的补丁应该从这里开始应用。
同样develop~3
通向M
,所以这是“上游”。这意味着 M
和 M
可访问的任何提交(通过父指针)都不会用于创建补丁。 (如果你没有使用 --onto
upsteram 也会在应用补丁的地方发挥作用;但在这里我们确实使用了 --onto
所以这无关紧要。)
应用补丁时,可能会发生冲突。那是因为 5
、6
或 7
中的某些内容可能会编辑已被 M
编辑过的行(或“足够接近”由 M
,导致 git 不确定是否存在问题)。任何可靠的方法来执行您所要求的操作都会产生相同的冲突,因此您只需要弄清楚如果合并从未发生过,更改“应该”是什么样子。
如果 develop
存在于远程中,并且如果 M
已经被推送到该远程,那么默认情况下 git 将拒绝推送此更改的结果(因为它从分支历史中删除 M
)。您可以使用 push
命令的 --force-with-lease
选项覆盖它。 (有些人说使用 -f
选项,但是虽然这样更容易输入,但也不太安全。 -f
不会检查你不知道的新提交是否已被推送到develop
;--force-with-lease
会。)
不重写历史
如果您不能(或不想)协调历史记录重写,那么您必须接受您推送的任何历史记录都是不可变的。在这种情况下,您可以恢复合并。
git revert -m 1 develop~3
-m
选项告诉 git 你要“恢复到”哪个合并的父项;所以通过说 -m 1
,你有效地撤消了分支的更改。
就像 history-rewrite 方法一样,这可能会发生冲突,需要手动解决冲突。最终结果将是
1 -- 2 -- 3 -- 4 -- M -- 5 -- 6 -- 7 -- !AB <--(develop)
\ /
A --- B <--(feature/new)
其中 !AB
反转 A
和 B
的更改(已合并到 M
)。
因为 A
和 B
还在 develop
的历史中,如果你以后想要 re-merge 它们并不简单。您要么必须还原 !AB
,要么使用 rebase -f
在 mreging 之前重写 feature/new
的历史记录。