[英]Accidentally merged master into develop and pushed
I work in a git repo where we maintain a master and a develop branch. 我在一个git仓库工作,我们维护一个主人和一个开发分支。 Changes are made in develop and merged into master before releases.
在开发之前进行更改并在发布之前合并到master中。 Today I accidentally merged master into develop and pushed the result to develop.
今天我不小心把大师合并到了开发中并推动了结果的发展。 A
git log
in develop now shows the merge develop into master
commits. 现在开发的
git log
显示merge develop into master
提交。 I need to fix this somehow. 我需要以某种方式解决这个问题。 I found the most recent good commit using
git reflog
. 我使用
git reflog
找到了最近的好提交。 What is the correct approach to revert to it? 恢复它的正确方法是什么?
Since I have already pushed, I would like to avoid rewriting history. 由于我已经推,我想避免重写历史。 However, I'm not sure that I can use
git revert
. 但是,我不确定我是否可以使用
git revert
。 I'm not convinced that the "revert a faulty merge" howto and other SO questions apply since the commits that I want to revert are merges themselves ( https://www.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt ). 我不相信“恢复错误的合并”howto和其他SO问题适用,因为我想要恢复的提交是自己合并的( https://www.kernel.org/pub/software/scm/git/docs /howto/revert-a-faulty-merge.txt )。
You can use git revert
to revert the merge. 您可以使用
git revert
还原合并。 Just be aware that when you do that, you make a future "re-merge" more difficult. 请注意,当您这样做时,您将使未来“重新合并”变得更加困难。 Read that message you linked closely—it says a lot about how to make the future "re-merge" work—but be aware that it's talking about merging
develop
into master
, and you said you did the opposite, merged master
into develop
: 阅读你密切关注的那条消息 - 它说了很多关于如何使未来“重新合并”的工作 - 但要注意它正在谈论将
develop
合并到master
,你说你做了相反的,合并的master
进入develop
:
A -- B -- C -- D -- E <-- master
\ \
F - G - H - M <-- develop
In this case (having merged master
into develop
instead of the other way around) you can choose a number of different options, all with advantages and drawbacks... 在这种情况下(将
master
合并为develop
而不是相反)你可以选择许多不同的选项,所有选项都有优点和缺点......
(0) Do nothing. (0)什么都不做。 If merging in
C
and D
doesn't break the develop
branch, just leave it that way. 如果在
C
和D
中合并不会破坏develop
分支,那么就这样离开。 Later, someone will git checkout master
and git merge --no-ff develop
and get this (let's say one more commit I
got added to develop
first): 后来,有人会
git checkout master
和git merge --no-ff develop
并得到这个(假设I
再加入一个提交以进行develop
):
A -- B -- C -- D -- E -- M2 <-- master
\ \ /
F - G - H - M - I <-- develop
Here merge
finds what's been done in develop
since it split off from master
, which was at B
. 这里
merge
找到了develop
已经完成的工作,因为它从master
处分离出来,这是在B
。 So it puts in F
, G
, and H
, skips any parts of M
that came off master
(probably all of it), and finally puts in I
and makes merge-commit M2
(because of commit E
; but if E
were not there, it would be because I used --no-ff
too). 所以它把在
F
, G
,而H
,跳过的任何部分M
是来到了master
(可能是所有的话),最后提出在I
,使合并提交M2
(因为提交的E
;但如果E
不存在,那是因为我使用了--no-ff
)。
(1) Just "rewrite history": erase commit M
from branch develop
. (1)只是“重写历史”:从分支
develop
擦除提交M
Alert everyone else who uses the branch that this is about to happen: that commit M
is going away and they should take whatever measures they must, to handle this. 警告使用该分支即将发生的所有其他人:提交
M
即将离开,他们应该采取他们必须采取的任何措施来处理这个问题。
(2) Stop using the old name develop
, make a new branch name develop1
or whatever: (2)停止使用旧名称
develop
,创建一个新的分支名称develop1
或者其他:
A -- B -- C -- D -- E <-- master
| \
| M <-- develop
\ /
F - G - H <-- develop1
This is the same as option (1) except that the commit M
is still there, along with the branch label on it, and you have a new/different branch label pointing to commit H
. 这与选项(1)相同,除了提交
M
仍然存在,连同其上的分支标签,并且您有一个指向提交H
的新/不同分支标签。 You still need to alert everyone, but it might make their jobs easier. 您仍需要提醒所有人,但这可能会使他们的工作更轻松。 You can delete
develop
later, when everyone is good with that. 您可以稍后删除
develop
,当每个人都很好。
(3) Revert the merge. (3)恢复合并。 As in the linked article, let's use
W
to represent the new revert commit: 与链接文章一样,让我们使用
W
来表示新的还原提交:
A -- B -- C -- D -- E <-- master
\ \
F - G - H - M - W <-- develop
What's in W
? 什么在
W
? Whatever it takes to "erase the effect" of the merge. 无论如何“消除合并的效果”。 In this case, that means, changes that un-do whatever was done in
C
and D
. 在这种情况下,这意味着,在
C
和D
执行的任何操作均无法执行。 So far so good, develop
has just the changes from F
, G
, and H
, again. 到目前为止,
develop
只有F
, G
和H
的变化。 The problem occurs later , if/when someone does: 如果/有人这样做,问题会在以后发生:
git checkout master
git merge develop
The second command goes rooting around to find where master
and develop
were split, ie, commit B
, so it picks up all the changes since then. 第二个命令根深蒂固地查找
master
和develop
被拆分的位置,即提交B
,因此它会从那时起获取所有更改。 Which at this point include those in W
, which will un -do C
and D
, not at all what you wanted. 在这一点上,包括
W
那些,它们将取消 C
和D
,而不是你想要的。 It can be fixed-up afterward, but whoever does the merge has to know about this "delete C
and D
" time-bomb waiting for them. 它可以在之后修复,但是合并的人必须知道这个“删除
C
和D
”定时炸弹等待它们。
Note that this is the same merge as in the "do nothing" option (0). 请注意,这与“不执行任何操作”选项(0)中的合并相同。 The issue here is the contents of
W
. 这里的问题是
W
的内容 。 In case (0), you want the contents of commit I
, but here you don't want the contents of W
. 在case(0)中,你想要 commit
I
的内容,但是在这里你不需要 W
的内容。
This is arguably the worst option of all, given what's shown above, but I'll list it anyway: 考虑到上面显示的内容,这可以说是最糟糕的选择,但无论如何我都会列出它:
(4) make an all-new branch with copies of the commits you want to keep, and name it develop
. (4)创建一个包含您要保留的提交副本的全新分支,并将其命名为
develop
。 (Or name it something else, but then we're back to the develop1
-like situation above, and you should probably just use that one.) Whether you keep the old-develop
branch, or just abandon it (by not labeling it), is up to you, but I will draw it in: (或者将其命名为其他内容,但之后我们又回到了
develop1
的情况,你应该只使用那个。)无论你是保留old-develop
分支,还是放弃它(通过不标记它) ,由你决定,但我会把它画进去:
F' - G' - H' <-- develop
/
A -- B -- C -- D -- E <-- master
\ \
F - G - H - M <-- old-develop
This is described in the link you included. 这包含在您包含的链接中。 It's only really useful in more complex cases.
它只适用于更复杂的情况。
You can fix this by resetting your local branch back to the last good commit, then pushing that: 您可以通过将本地分支重置为上一次良好提交来解决此问题,然后推送:
git checkout develop
git reset --hard lastgoodcommit
git push origin develop
Note that your upstream repository may disallow non-fast-forward merges by default. 请注意,默认情况下,您的上游存储库可能会禁止非快进合并。 If so, you will need to modify that option on your upstream, do the above push, and then restore the original setting.
如果是这样,您将需要在上游修改该选项,执行上述操作,然后恢复原始设置。
I use GIT Extensions. 我使用GIT Extensions。 There is a feature to right click a revision in the UI and revert back to it.
有一个功能可以右键单击UI中的修订并还原为它。
Yes, you can revert a merge, but you need to specify which parent is the mainline. 是的,您可以还原合并,但您需要指定哪个父级是主线。 Since you merged develop into master, this should do the trick:
既然你将开发合并为master,那么这应该可以解决问题:
git revert --mainline 1 HEAD
To make sure you have exactly what you want, you should do a diff with $lastgoodcommit, however, $lastgoodcommit should be HEAD^. 为了确保你有你想要的东西,你应该用$ lastgoodcommit做差异,但是,$ lastgoodcommit应该是HEAD ^。 This is of course, if you haven't made commits on top of the merge, if you have, then you need to replace HEAD with the merge commit.
这当然是,如果你没有在合并之上进行提交,如果你有,那么你需要用合并提交替换HEAD。
Finally, you can also do the revert manually, by checking out the code on top of the current commit: 最后,您还可以通过检查当前提交之上的代码来手动还原:
git checkout $lastgoodcommit -- .
The '-- .' ' - 。' is there to differentiate from a normal checkout, where HEAD is switched to the specified commit, in the command here, all the files in the working directory, and the staging area, are going to be exactly the same as they were in $lastgoodcommit.
有没有区别于正常结账,其中HEAD切换到指定的提交,在此处的命令中,工作目录中的所有文件和暂存区域将与$ lastgoodcommit中的完全相同。 If you do a diff with $lastgoodcommit, you should see, again, no changes.
如果你用$ lastgoodcommit做差异,你应该再次看到没有变化。 Essentially it's a revert.
基本上它是一个恢复。
You could also try ' git checkout --patch
' to selectively revert chunks of code. 您还可以尝试'
git checkout --patch
'来有选择地还原代码块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.