恢复远程分支上的提交

时间:2018-05-22 17:39:36

标签: git

我在一个本地分支上工作,添加了许多提交 然后我把它推到remote staging分支。

现在我必须撤消已经推送到remote staging的最后一次提交,即我的本地分支合并到remote staging

我对其他答案的理解是,我必须使用还原而不是重置以干净的方式进行,不是吗?

所以我要做的是:

  1. 创建一个名为cleaning的新本地分支,其中master为父级(位于分段后面)
  2. 将远程staging拉入清洁
  3. 使用git revert {last good commit hash in staging}
  4. 现在cleaning应该处于良好的提交状态并处于remote staging的相同状态,然后才能推送,不是吗?
  5. 现在我应该将cleaning推入remote staging以使远程分支恢复。有哪些旗帜?
  6. 我说错了吗?因为git status在第4点告诉我,我已与staging

    保持同步

2 个答案:

答案 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)

TL; DR

请注意,git revert实际上意味着退出更改 还原,即恢复某些特定版本。可以实现恢复/恢复,但执行此操作的命令是git checkoutgit 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>分支名称,如masterstaging,并在您的建议中cleaning。 Git还有远程跟踪名称远程跟踪分支名称,如origin/staging,但令人困惑的是,Git将这些名称​​存储在本地,即,在您自己的存储库中(仅限)。你的Git使用你的 origin/staging来记住你的Git在他们的 Git上看到的内容,当你的Git最后一次与他们的Git交谈并向他们询问时他们的 staging

因此,问题的根源在于你的Git存储库是你的,但是还有第二个Git存储库不是你的,你最终希望在其他 Git存储库上执行某些操作。这里的约束是你的Git只允许你在你的存储库中执行这些操作,之后你最终会运行git pushgit push步骤会将一些提交或提交从您的Git存储库转移到他们的Git存储库。目前,您可以要求他们的 Git设置他们的名称 - 他们的 staging - 他们会说是的,我设置了(你的Git现在会更新你的origin/staging以便记住这一点),或者不,我拒绝设置它,原因如下:_____(在此插入原因)

因此,您要在 存储库中执行的操作是设置适当的步骤,以便他们的 Git,在他们的存储库中,将接受您git push的提交并将更新其staging。在我们完成这些步骤时请记住这一点。有多种方法可以做到这一点,但这里有我要使用的方法。

  1. 运行git fetch。此命令始终可以安全运行。您可以为其指定一个特定遥控器的名称,如果您有多个,但大多数人只有一个,名为origin,如果您只有一个,则无需为其命名。

    (远程名称 - origin - 主要是拼写您的计算机用于访问其他Git存储库的URL的简便方法。)

    git fetch可能无效,或者可能会更新某些远程跟踪(origin/*)名称。 git fetch所做的是调用另一个Git,从中获取所有分支的列表以及哪些提交哈希值,然后将他们拥有的任何提交带到你不知道的状态。您的origin/staging现在会记住他们的staging。现在可以为此添加新提交。

  2. 现在您的origin/staging与其他Git staging同步,根据需要创建或更新本地分支名称。这里使用的最佳名称是staging,但如果您愿意,可以使用cleaning。由于此步骤是创建或更新,因此它具有子步骤:

    • 如果它"创建",您可以使用git checkout -b staging origin/staging创建一个上游为staging的新origin/staging

      您可以将其缩短为git checkout staging,因为您没有自己的staging - 会搜索您的所有origin/*名称(以及任何其他远程名称)跟踪名称,如果你有多个遥控器),找到哪一个匹配。然后它就像你使用较长的命令一样。 (只有一个遥控器,唯一可以匹配的名称是origin/staging。如果您同时拥有originxyzzy作为遥控器,则可以同时拥有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

  3. 您现在想要创建撤消错误提交的提交。这可能会使用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:

  4. 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 ,但我在这里使用复制粘贴来保持形状相同。)

  5. 如您所见,您现在已经完成了。您和他们都同意您和他们的W都应指向提交staging,其具有撤消提交W的效果。如果您愿意,现在可以安全地删除您自己的M名称:

    staging

    产生:

    git checkout <something-else>
    git branch -d staging