我意外地提交并将我的代码更改推送到了错误的分支。
以下是我为撤消不良修改所做的工作
但是我收到了错误
! [远程拒绝] 3cd4e57dcbb2a5bae350086c11d64c2f01ad4546 - >发展(受保护的分支挂钩拒绝)
如何在遥控器上撤消?我猜git reset --hard只是本地而不是远程。
答案 0 :(得分:4)
远程分支似乎受到保护。 为了推动力量, 您可以暂时取消保护分支,再次推送和保护。 您可以在GitHub上的存储库页面的设置/分支选项卡上执行此操作。 请注意,这(并且通常强制推送)不是对公共存储库的推荐操作。
可替换地, 您可以通过还原来撤消提交, 在坏的之后会生成一个新的提交, 然后简单地推。
答案 1 :(得分:2)
我发表了一条评论,但这个评论太长了,所以我也会把它作为一个答案。我不清楚你在本地和任何其他(可推送的)存储库中做了什么,此时。
首先,请记住,每次以分布式方式使用Git时 - 在您自己的计算机上,以及使用"远程"像origin
一样 - 涉及两个(或更多)单独的Git存储库。你在本地做的事情确实是纯粹本地的:你在你的存储库中执行它们,现在你拥有它们,但没有其他存储库有这些提交。
要将提交从您的存储库发送到另一个存储库,您可以推送它们:
git push origin refspec
或与运营其他存储库的人交谈 - 让他们说你的朋友Bob - 并说服他运行git fetch
你的< / em> repository。
如果遥控器是像GitHub这样的大型服务器,那么你实际上没有朋友Bob运行它,服务器人员通常会设置一些东西以便你有某种界面(例如网络浏览器)方法),您可以通过它来进行更改。例如GitHub允许你假装是Bob&#34;并在GitHub服务器上按照名称保护和取消保护分支。
接下来,请记住,Git中的分支名称只被视为提交图中提交的可移动指针。提交图更加永久和可靠:一旦提交存在,它就以精确的形式存在&#34;永远&#34;。但是,可以添加,删除和移动分支名称。所以它是提交,它们具有&#34;真实的名称&#34;那些大丑陋的哈希ID,如3cd4e57dcbb2a5bae350086c11d64c2f01ad4546
- 这是主要的问题 - 但你几乎总是通过分支名称之类的东西访问。
(分支机构名称也保护提交,并且可以访问它们,但目前这不是您需要担心的事情。)
如果您绘制(至少部分)提交图,这些事情总是更有意义。您可能有一个分支名称,如develop
,&#34;指向&#34; (具有ID)像3cd4e57dcbb2a5bae350086c11d64c2f01ad4546
这样的提交。然而,该特定提交本身指向另一个较早的提交(包含ID)。每个提交都指向其父提交,这意味着我们可以使用箭头绘制提交的链接。我实际上没有箭头所以我在这里使用近似值:
... <- o <- o <- o <-- develop
这里,每次提交只是指向其父级的轮次o
。分支名称develop
指向分支的最近或 tip 提交。该提交指向其父级,它指向另一个父级,依此类推。
所有中间箭头往往只是一种分心(再加上它们向前倾斜)所以我更喜欢把它们画成:
...--o--o--o <-- develop
如果我们develop
&#34;分支&#34;从另一个分支如master
开始,该图清楚地说明了它是如何工作的:
...--o--o--o--o <-- master
\
o--o--o <-- develop
git reset
移动分支标签使用git reset
时,可以移动分支标签。这对图形本身没有影响,仅在标签指向的上。我们假设您在分支develop
上,并使用git reset
来删除&#34;来自develop
的最后一次提交。图片现在改为:
...--o--o--o--o <-- master
\
o--o--o
^
|
develop
看看图表是如何完全不变的,只有标签移动了? develop
的旧提示 - 提交本身,就是 - 仍然存在。只是它不再有一个指向它的分支名称。要命名该特定提交,您现在必须使用其哈希ID,您可能已经或可能没有在任何地方保存。
(嗯,它在这个图中没有这样的名字 。但我们是否在所有中绘制了分支名称?如果没有,是否有一些其他< / em>指向它的人类可读的名称?再次,让我们暂时不担心。)
在git reset
之前,如果您要求您的Git向您显示您致电develop
的提交,它会向您显示旧提示:最右侧o
提交。在git reset
之后,如果您要求您的Git向您显示您调用develop
的提交,则会在同一行显示中间o
提交。所以你的 Git现在认为develop
意味着提交和所有早期的提交。
git push
要求其他 Git更改其名称点正如您在问题中所建议的,执行git reset
只会更改您 Git关于哪个提交develop
名称的想法。名称develop
指向其他提交的任何其他存储库(例如上一个提示 - 仍然)其名称指向旧提示。
使用git push
,您可以询问任何其他可以连接的Git,以更改他们对任何分支名称应指向的位置的想法。其他Git有权说&#34; no&#34;,并且有两个&#34;级别&#34;您可以在执行git push
时使用:一种礼貌的请求,&#34;请执行此操作&#34;,并且更有力&#34;执行此操作!&#34;你得到--force
。另一个Git仍然可以说&#34; no&#34;一个或两个这样的操作。
你在问题中说你:
提交并将我的代码更改推送到错误的分支。
我不清楚你是否犯了错误的分支,然后按名称推送了这个分支,或者你是否致力于正确的分支,然后推错了名字或者什么。它还不清楚你的推送是否首先成功,因为你给出的唯一示例输出有一个错误:
git push -f origin 3cd4e57dcbb2a5bae350086c11d64c2f01ad4546:develop ! [remote rejected] 3cd4e57dcbb2a5bae350086c11d64c2f01ad4546 -> develop (protected branch hook declined)
这是一种强制推动,他们仍然说'不是'#34;。这里的错误消息使用短语&#34; protected branch&#34;,这是一个GitHub功能,但它也是一个GitLab功能,可以来自几乎任何地方。所以我不确定这指的是哪个保护功能。我可以肯定的是,他们说&#34;没有&#34;,而不是为什么他们说&#34;不&#34;。而且,特别是,我无法判断是否有任何之前的推送成功。
让我们仔细看看在任何一种情况下不良提交会发生什么。让我们从这张图开始:
...--o--o--o--o <-- master
\
o--o <-- develop
如果你在分支develop
上并且对工作树和git add
以及git commit
进行了一些更改,Git会使用新快照进行新的提交。让我们说这不是一个好的改变,让我们称之为B
为Bad:
...--o--o--o--o <-- master
\
o--o--B <-- develop
如果没有将其推送到任何地方,那么根据定义,没有其他人有错误的提交。这使您可以轻松地git reset
离开它:
...--o--o--o--o <-- master
\
o--o--B
^
|
\--------- develop
现在我们可以简单地忘记B
,假装它从未存在过,把它推到一边并开始忽略它:
...--o--o--o--o <-- master
\
o--o <-- develop
\
B [abandoned]
这样放弃的提交最终会过期并且确实会被删除(通常,30天之后的某个时间已经过去 - 被放弃的提交不再受分支名称的保护,但通常仍然受到的保护reflog 条目,这些reflog条目最终会在一段可配置的时间后到期,默认为30天。)
但是,您还有另一种方法可以摆脱B
。只需反过来做同样的改变。如果您向文件blah.html
添加了一行,请删除该行。如果您更改了main.py
中的字词,请将其更改回来。无论你做了什么,都做相反的事情。然后,进行新的提交。我们将其称为U
进行撤消:
...--o--o--o--o <-- master
\
o--o--B--U <-- develop
与提交U
相关联的代码 - 工作树 - 将在B
之前匹配提交代码,因为B
做错了,然后U
撤消它。
将提交U
称为还原, 1 并且Git中有一个命令可以执行此操作而无需您执行任何额外的工作:{{1 }}。你给revert命令指定一个错误提交的名称 - 例如它的哈希ID,或者当git revert
是分支develop
上的提示提交时,只提供名称B
- 并且Git指出在错误提交中发生了什么变化,并进行反向提交。
1 好吧,Git称之为&#34;还原&#34;。其他人称之为&#34;退出&#34;:在Mercurial,&#34;退出&#34;提交是develop
。
执行hg backout
到删除错误提交,执行reset
到添加新提交之间的区别撤消坏的,正是这样:恢复添加内容。它将错误的提交留在原地并简单地添加一个新的提交来支持错误提交的效果。
Git的所有内容都围绕着这个&#34;添加新东西&#34;的整个想法。在旧提交之上添加新提交。每个人和每件事都准备好应对这一点。 Git的一些是为了处理删除提交而构建的,但Git的所有都是为了处理添加它们而构建的。
如果没有在其他任何地方推送错误的提交,也不允许其他任何人从你那里获取它,那么显然没有其他人拥有它。这意味着很容易从您自己的存储库中删除提交,或者至少将其放弃。你的Git会处理这个问题。但是如果你已经推送了提交,或者让它被提取,那么其他人就拥有了它。如果你拿走它,你必须得到他们来把它带走。如果另一个人拥有它,他可能会把它交给其他人,到现在可能有数千份副本。
在这种情况下,对其他人来说,还原更容易。他们都准备好了新的提交,如果你添加一个新的恢复提交,他们会以通常的方式提取它:没有大惊小怪,没有麻烦,每个人都做他们都在做的事情。因此,为此目的,恢复通常会更好。当然,它留下了糟糕的提交 - 但也许这甚至是好的事情。它可以作为一个教训:&#34;不要尝试这个,它是错的&#34;。 : - )
如果受保护分支上的保护允许添加 new 提交,但不允许&#34;删除&#34; (这可能更好地称为&#34;放弃&#34;)旧提交,恢复和推送将起作用。
如果保护是别的,也许什么都不会起作用。
如果可以关闭保护(暂时或其他方式),则可能允许 强制推送放弃提交,并还原。
请记住,如果你强行推动,那么你正在与其他可能正在推动的人竞争。当你强制推送时,你会告诉其他一些Git 更改某些分支点的提交ID。当你这样做时,你可能假设它现在指向你的错误提交。但是如果其他人在你的错误提交revert
之后完成新推送,那么使用你的提交{{1} }?你的推力将放弃他们的新提交。确保没问题 - 如果没有,找到一些方法确保它不会发生。 2
2 这是B
的用武之地,但我不打算在此解决这个问题。