所以这听起来像问题是
1)合并应该没有发生
2)合并在那意味着M
不超过D
应用所有
dev
变化的方式编辑
3)最终你将要合并dev
(包括A
通过C
)为master
4)强制推送不允许使用master
我们剩下的选项不是很好。
要解决(1)和(2),你只需要恢复M
。由于(4)您不能重写master
的历史记录,所以将master
返回到与D
匹配的状态的所有方法都等同于git revert
。这解决了(1)并且使得(2)没有意义。
但现在(3)是一个问题。大多数解决方案涉及力量推动到dev
;尽管您无法强制推送master
,但您还没有指出是否允许重写dev
历史记录。 (如果不是的话,无论如何,我会为此构建一个解决方案......)
如果重写dev
历史是好的,那么问题就是如何详细描述你想要的历史在替换分支中(记住原始历史将仍然出现,无论您是否需要,在提交之前您还原M
)。
我能想到的最简单的选项(但一有新的分支上的至少历史的保真度)看起来像
git checkout D
git branch -f dev
git merge --squash C
git commit -m "Replacement dev branch"
git push -f
请注意,如果您没有需要手动编辑的结果“squash merge”,你可以在merge
命令之后但在commit
命令之前执行;但同样,我的理解是,完成编辑以前是问题的一部分...
因此,这会创建一个新的提交上植根于D
,引入相对D
为C
合并同样的变化,但没有真正合并的“第二父母”关系 - 这意味着git将“忘记”这些更改与您已合并到master
中的更改相同。
\/
C
| |
B F
| |
A D
\ /\
\/ \
M CBA [Dev]
|
W [Master]
在此图中,在W
比赛D
和CBA
比赛什么M
会一直,如果它没有被错误地编辑TREE
(内容)。您可能已在dev
的原始分支点取代CBA
而不是在D
(由checkout
命令控制)。鉴于历史将会以任何方式“断”,唯一的区别在于是否应该现在或以后解决现有的冲突。
如果您对dev
的“新历史”应该是什么样子有更具体的要求,请告诉我们,我可以建议一个可能更接近满足它们的程序。
在任何情况下,因为这在改写历史dev
,当没有人对dev
unpushed变化是最好的做法(否则他们将不得不被复位至新dev
分支)。即便如此,每个人都必须强制更新本地的dev
分支。请参阅git rebase
文档中的“从上游缓冲区恢复”,因为这基本上是必须发生的。
这使我想到了另一种可能性:如果你不能(或不愿)改写历史dev
要么,则需要额外的步骤来确保dev
总是在一个“正常”的方式移动(如就像远程看到的那样)。
git checkout D
git branch -f dev
git merge --squash C
git commit -m "Replacement dev branch"
git rebase master
git push
注意,虽然我们移动dev
分支,后来我们rebase
回的origin/dev
后裔;所以不需要强制推送。如果这看起来令人不安,可以为压扁合并创建一个临时分支,然后在rebase
之后做一个简单的ff合并以提前dev
,但结果是一样的。
\/
C
| |
B F
| |
A D
\ /\
\/ \
M CBA
|
W [Master]
/
/
CBA' [Dev]
注意CBA
不可达,并最终将垃圾收集;我在这里展示没有特别的原因。新的dev
在CBA'
- 重写CBA
。
同样,如果你对历史应该如何看W
和CBA'
之间让我们知道,我们可以尝试制定出一个程序的具体要求 - 但是,请记住,历史原貌仍然可见M
之前反正。
这将撤销'M'中的更改,但它不会帮助我将'A,B,C'中的更改放入'master'中,因为历史记录表明它们已被合并。 –
再次执行#commit-id是你最后一次提交的id对应的A,B,C分支commit-id的。 –