我在一个本地分支上工作,添加了许多提交
然后我把它推到remote staging
分支。
现在我必须撤消已经推送到remote staging
的最后一次提交,即我的本地分支合并到remote staging
我对其他答案的理解是,我必须使用还原而不是重置以干净的方式进行,不是吗?
所以我要做的是:
cleaning
的新本地分支,其中master
为父级(位于分段后面)staging
拉入清洁git revert {last good commit hash in staging}
cleaning
应该处于良好的提交状态并处于remote staging
的相同状态,然后才能推送,不是吗?cleaning
推入remote staging
以使远程分支恢复。有哪些旗帜?我说错了吗?因为git status
在第4点告诉我,我已与staging
答案 0 :(得分:10)
不要让它变得复杂。
首先,您需要执行git log
以找出要还原的提交ID。例如,它是提交abc123
。如果您知道它是最后一个,您可以使用特殊标识符" HEAD"。
然后你首先在本地" staging"本地恢复它。分支:
git checkout staging
git revert abc123
注意:对于日志中的最后一次提交,您需要编写git revert HEAD
。
然后你更新你的遥控器" staging":
git push
说明:在git中,如果你有一个遥控器,你正在处理2个不同的存储库(本地和远程)。执行git checkout staging
后,实际上创建了一个表示远程分支的不同本地名称。 git revert
实际上并没有删除你的提交,但是它会在顶部创建一个新提交,撤消所有更改(如果你添加了一个文件 - 如果删除了一行,新提交将删除它 - 新提交将其添加回来等),即它是对日志的补充,这就是为什么推送将是干净的。
如果你真的想让它消失,那么没有人可以责怪你,你可以冒风险:
git checkout staging
git reset --hard HEAD^
git push -f
(重置行重新定位本地" staging"分支,以便它指向最高提交之前的提交)
一般来说,强制推送是一种不好的做法,但保持无用的提交和恢复也不是很好,所以另一种解决方案是实际创建一个新的分支" staging2"而是在那个分支中进行测试:
git checkout staging
git checkout -b staging2
git reset --hard HEAD^
git push
答案 1 :(得分:1)
请注意,git revert
实际上意味着退出更改,不 还原,即恢复某些特定版本。可以实现恢复/恢复,但执行此操作的命令是git checkout
和git read-tree
(由于不同的原因,这两个命令都有点棘手)。请参阅How to revert Git repository to a previous commit?和Rollback to an old Git commit in a public repo(具体为jthill's answer)。
这里唯一真正棘手的部分是"还原合并"。这相当于在合并提交中使用git revert -m 1
,这很容易运行;但这意味着之后,你不能重新合并,因为Git非常肯定(并且正确)你已经合并了所有的工作并且正确的结果到位了(就是这样,你只是以后解除它)。要把它全部放回去,你可以恢复还原。
Reverting进行新的提交,就像每次提交一样,只需向当前分支添加新的提交。您一如既往地在自己的存储库中执行此操作。剩下的工作就是将新提交推送到某些其他 Git存储库,将其添加到其他Git的集合中,作为其中一个他们的分支机构。
首先,让我们稍微备份一下,因为短语远程分支意味着什么,或者更确切地说,对于太多不同的人来说意味着太多不同的东西 - 在任何一种情况下,它都会蜿蜒导致沟通失败。
Git确实有分支,但即使是"分支"含糊不清(见What exactly do we mean by "branch"?)。我发现最好具体一点:我们有{em>分支名称,如master
和staging
,并在您的建议中cleaning
。 Git还有远程跟踪名称或远程跟踪分支名称,如origin/staging
,但令人困惑的是,Git将这些名称存储在本地,即,在您自己的存储库中(仅限)。你的Git使用你的 origin/staging
来记住你的Git在他们的 Git上看到的内容,当你的Git最后一次与他们的Git交谈并向他们询问时他们的 staging
。
因此,问题的根源在于你的Git存储库是你的,但是还有第二个Git存储库不是你的,你最终希望在其他 Git存储库上执行某些操作。这里的约束是你的Git只允许你在你的存储库中执行这些操作,之后你最终会运行git push
。 git push
步骤会将一些提交或提交从您的Git存储库转移到他们的Git存储库。目前,您可以要求他们的 Git设置他们的名称 - 他们的 staging
- 他们会说是的,我设置了(你的Git现在会更新你的origin/staging
以便记住这一点),或者不,我拒绝设置它,原因如下:_____(在此插入原因)
因此,您要在 存储库中执行的操作是设置适当的步骤,以便他们的 Git,在他们的存储库中,将接受您git push
的提交并将更新其staging
。在我们完成这些步骤时请记住这一点。有多种方法可以做到这一点,但这里有我要使用的方法。
运行git fetch
。此命令始终可以安全运行。您可以为其指定一个特定遥控器的名称,如果您有多个,但大多数人只有一个,名为origin
,如果您只有一个,则无需为其命名。
(远程名称 - origin
- 主要是拼写您的计算机用于访问其他Git存储库的URL的简便方法。)
此git fetch
可能无效,或者可能会更新某些远程跟踪(origin/*
)名称。 git fetch
所做的是调用另一个Git,从中获取所有分支的列表以及哪些提交哈希值,然后将他们拥有的任何提交带到你不知道的状态。您的origin/staging
现在会记住他们的staging
。现在可以为此添加新提交。
现在您的origin/staging
与其他Git staging
同步,根据需要创建或更新本地分支名称。这里使用的最佳名称是staging
,但如果您愿意,可以使用cleaning
。由于此步骤是创建或更新,因此它具有子步骤:
如果它"创建",您可以使用git checkout -b staging origin/staging
创建一个上游为staging
的新origin/staging
。
您可以将其缩短为git checkout staging
,因为您没有自己的staging
- 会搜索您的所有origin/*
名称(以及任何其他远程名称)跟踪名称,如果你有多个遥控器),找到哪一个匹配。然后它就像你使用较长的命令一样。 (只有一个遥控器,唯一可以匹配的名称是origin/staging
。如果您同时拥有origin
和xyzzy
作为遥控器,则可以同时拥有origin/staging
和{{1那么你需要一个更长的命令。)
或者,如果它"更新",您已经有xyzzy/staging
已将staging
设置为其上游,因为您已完成这之前。在这种情况下,只需运行:
origin/staging
让您的登台与git checkout staging
git merge --ff-only origin/staging
重新同步。如果快进合并失败,你有一些他们不会做的提交,你需要更复杂的东西,但我们在这里假设这成功。
你也可以稍微缩短这些命令,但我会在这里拼写出来。请注意,第一个命令是与上面第一个案例的短版本相同,您可以通过origin/staging
的输出判断哪个命令发生了。 (我将留下其他问题或练习的详细信息。)
我们可以在您自己的存储库中绘制您现在拥有的图片,它看起来像这样:
git checkout staging
每轮...--o--o--o---M <-- staging (HEAD), origin/staging
\ /
o--o <-- feature/whatever
代表一次提交。 o
表示合并提交,其结果是您不喜欢的,但在其名称M
下的origin
处的其他Git中也存在这就是为什么你自己的Git的名字staging
指向提交origin/staging
。
您现在想要创建撤消错误提交的提交。这可能会使用M
,但请记住,还原意味着撤消或退出,而不是切换到旧版本。你告诉Git承诺撤消,Git通过弄清楚你做了什么来解除它,并做相反的事情。
例如,如果您说要还原的提交说明&#34;删除文件README&#34;,则更改将包括&#34;以删除时的形式恢复文件README。&# 34;如果您说要还原的提交说明&#34;将此行添加到Documentation / doc.txt&#34;,则更改将包括&#34;从Documentation / doc.txt&#34;中删除该行。如果你说恢复的提交说'#34;改变你好再见&#34;在某个第三个文件中,恢复将做的更改是改变&#34;再见&#34;到&#34;你好&#34;在第三个文件中,在同一行(如果它移动,有一些魔法找到该行)。
这意味着git revert
可以撤消任何提交,即使它不是最新的提交。但是,要这样做,它必须将该提交与其直接父进行比较。如果您尝试还原的提交是 merge 提交,则它具有多个父,您需要指定Git应该使用哪个。
使用的正确父级并不总是很明显。但是,对于大多数合并而言,它只是父母编号1&#34;。这是因为Git特别强调合并的第一个父级:它是您运行git revert
时的HEAD
提交。所以这就是合并所带来的一切,但尚未出现。
当git merge
成功时,它会进行一次新的提交,以撤消合并的效果:
git revert
此处, W <-- staging (HEAD)
/
...--o--o--o---M <-- origin/staging
\ /
o--o <-- feature/whatever
代表此新提交:它W
颠倒过来。您现在要做的只是运行M
将您自己的新提交git push origin staging
发送给其他Git:
W
:这会调用其他Git并提供它git push origin staging
- 这是我们所做的每次提交都不会被提及的。他们有W
和之前的所有内容(左侧),但不是M
。
只要没有特殊限制,他们就会接受这个新提交并将他们的 W
更改为指向新提交staging
。你的Git会记住这个变化:
W
(没有必要在单独的一行上绘制 W <-- staging (HEAD), origin/staging
/
...--o--o--o---M
\ /
o--o <-- feature/whatever
,但我在这里使用复制粘贴来保持形状相同。)
如您所见,您现在已经完成了。您和他们都同意您和他们的W
都应指向提交staging
,其具有撤消提交W
的效果。如果您愿意,现在可以安全地删除您自己的M
名称:
staging
产生:
git checkout <something-else>
git branch -d staging