撤消已推送的合并

时间:2012-04-16 14:45:40

标签: git merge reset revert

好吧,我搞得一团糟。显然,在家里的机器上,开发分支没有更新。我做了一个提交并推了推。结果是实际的origin / develop分支已合并到我的本地开发分支 - 由于某种原因被认为是不同的分支!

首先,我真的不明白这是怎么发生的,其次,我可以撤消这个吗?

为了说明这一点,网络现在看起来像这样:

 local-develop ---------------------------------- C*--- M -
origin/develop --- C --- C --- C --- C --- C --------- / 

我真正想要的是C *将被提交到origin / develop而不是合并分支。

正如我所说,这已经被推了。有没有办法删除更改并以我想要的方式提交它?

例如我做:

git reset --hard HEAD~1

我不确定这是否会撤消合并,我有两个不同的开发,然后合并删除等...?

2 个答案:

答案 0 :(得分:26)

合并不会在推送时发生,它们发生在git merge上(好吧,pull但这真的只是获取+合并,因此合并时会发生合并)。

你似乎更有可能做到这样的事情:

<get copy from origin/develop>
<wait around for remote's origin/develop to acquire new commits>
git checkout develop      # get onto (local) develop branch
<edit>
git commit -m message     # create some new commit(s)
git push origin develop   # attempt to push -- but this fails!
git pull

这是创建合并提交的最后一步(上面M),因为pull表示fetch(获取现在位于{{1}的所有新提交}}),然后origin/develop(带你的本地merge并将你的提交与那些刚刚提取的新提交合并。)

如果您没有develop这个新的结果,那么远程仓库 你的本地提交,您已标记为git pushC*的人。在这种情况下,你的身体状况良好! (您可以再次运行M进行检查,以确保您的本地回购git fetch与遥控器中的origin/develop匹配,然后执行git log origin/develop以查看其中的内容。)

可能有助于记住,这里有两个完全独立的git回购:你的,你的东西;以及你在这里打电话origin的人。 (让我们调用该机器X。)如果您要登录X,它有自己独立的提交历史记录和分支名称等等。在那里,您可以将目录更改为repo,运行git log -1 develop,并查看该分支顶端的内容。

现在,如果您从X注销并重新使用自己的计算机,则可以运行git log -1 origin/develop。如果这与您在X上看到的内容相同,则get fetch无需更新,因为git fetch的作用实际上(但更有效),登录到X并查看develop中的X内容。 origin/develop fetchorigin/develop所带来的X所带来的任何内容都会带来并添加到X。现在,您与merge同步。 pull没有你的东西,但你有他们的东西。

如果你再采取额外的步骤develop(包括X暗示的那个),git将会(如果必须的话)进行合并提交......但所有这些都是在你的回购中,在分支的顶端(在这种情况下仍为X)。除非并且直到你将此合并提交推送到X(或者X上的某人提取你的提交但是暂时忽略它:-)),rebase赢了&# 39;没有。

无论如何,只要遥控器(develop这里)没有你的合并提交,你就是金色的。由于他们没有它,其他人也没有。您可以C* origin/develop M分支将您的提交(origin/develop)置于X之上。这将摆脱合并提交(pull),然后你可以将一个简单的快进推送到X

如果X 你的合并提交 - 即,如果你在git reset之后推动并获得了合并 - 那么你就会被卡住(对某些人而言)因为可能其他人有权访问git rebase并且现在正在使用您的合并提交。可以回滚X上的回购,类似于您在自己的回购邮件中使用devel--------------------------- C*--- M --- C4 --- C5 --- C6 --- C7 ---- / 执行此操作的方式,等等,但是&#39} ; s通常是一个坏主意。

<小时/> 现在,假设你实际上已经推送到另一个仓库(在机器X上),但是你绝对确定没有其他人看到你的更改,而且你&#39;肯定会重置它们,而不是将它们还原(将数量恢复为&#34; fesing up&#34;并留下螺旋记录,这让其他人可以轻松地从中恢复,但也让他们看到你的错误: - ))。 1

这就是诀窍:你首先需要让机器X的回购说#34;分支cd的提示是C7&#34;,其中C7在你的来自前面的非常自己的图表,只是重新编号,以便我可以区别地命名每个提交:

--bare

那么,你怎么能这样做?好吧,一种方法是在git update-ref 2 50db850登录回购(即使它是localhost$ ssh X X$ cd /path/to/repo.git X$ git update-ref refs/heads/develop 50db850 ),然后使用{{ 1}}那里。让我们说C7的SHA1实际上是X(如&#34; git log&#34;所示)。然后你可以这样做:

git push -f

但是,如果您无法登录origin/develop,或者甚至根本不想登录,则可以使用push -f执行相同操作。 3 (这还有其他优点:特别是,一旦localhost$ git branch resetter 50db850 localhost$ git log resetter # make sure it looks right ... localhost$ git push -f origin resetter:develop Total 0 (delta 0), reused 0 (delta 0) To ssh://[redacted] + 21011c9...50db850 resetter -> develop (forced update) localhost$ git branch -d resetter # we don't need it anymore 成功完成,你的git repo就会知道push -f已被重绕。)只需创建一个指向正确提交的本地分支:< SUP> 4

M

完成此操作后,机器X将恢复到您想要的状态,您就可以继续进行,就好像您从未推动过您不喜欢的合并一样。

请注意,当您执行lost+found时,如果其他人在git fsck --lost-found之上进行了新的提交,那些将变得不可见(从技术上讲,他们是&#39;仍然在那里,伴随着你的合并提交,但它们在git log意义上git ls-remote失去了#34;并且在几个月之后它们真的会永远消失)。 5

再次和非常重要:这种共享回购&#34;回滚&#34;对于共享仓库的其他用户来说是一个巨大的痛苦,所以在你做之前要确定它没问题。


1 这种微不足道的合并甚至不需要还原。将合并留在那里没有根本的错误。但是,如果你正在处理一个更严重的错误合并,除了你的&#34; oops&#34;的记录之外,恢复合并还有另一个缺点:它会重做&#34;重做& #34;后来的变化有点困难,因为后来的&#34;目的合并&#34;会看到之前的合并并认为:好的,我不需要重新合并那些更改。然后你必须&#34;恢复还原&#34;代替。

我认为这里正确的外卖课程是:在推前查看(git push -f)以确保您要推送的内容是您打算推送的内容。< / p>

2 或者,更简单,更简单:{{1}}。这使用获取协议代码来查看远程具有的内容。但它隐藏了我要去的主题,那就是:遥控器就像你的一样!//

3 即将发布的git版本2发布了新的&#34;安全功能&#34;这将与{{1}}一起使用。但是他们还没有出来,所以这对你没有帮助。我会在以后重新编辑它,以便注意它们。在那之前,真的在这里小心点:此时你正试图将其他东西推向共享存储库。

4 您甚至可以通过原始SHA-1 ID执行此操作。分支名称更容易连续多次正确输入。

5 保留和到期是通过git&#34; reflogs&#34;。共享服务器可能没有记录所有ref更新;如果没有,只有已经有新提交的私有回购将保留它们。对于不再可从分支提示到达的提交,最短的默认到期是30天,即大约一个月。但请注意,这是一个无趣的,疯狂的争夺,让每个人都可以通过他们的存储库搜索&#34;丢失&#34;在强行推动&#34;失去工作后承诺&#34;关闭共享存储库。

答案 1 :(得分:1)