代码之家  ›  专栏  ›  技术社区  ›  lellefood

还原远程分支上的提交

git
  •  6
  • lellefood  · 技术社区  · 8 年前

    我在当地的一家分公司工作,增加了许多承诺。
    然后我把它推到 remote staging 分支。

    现在我必须撤消上一次提交 远程分段 这是我的本地分支机构合并到 远程分段

    我从其他答案中了解到的是,我必须使用revert而不是reset以一种干净的方式完成它,不是吗?

    所以我要做的是:

    1. 例如,创建一个新的本地分支 cleaning master 作为父级(在后台)
    2. 拉遥控器 staging 进入清洁阶段
    3. 使用 git revert {last good commit hash in staging}
    4. 现在 打扫 应该处于良好的承诺和相同的状态 远程分段 在我用力推之前,不是吗?
    5. 现在我该推了 打扫 进入之内 远程分段 恢复远程分支。用什么旗子?

    我说的对吗?因为 git status 在第4点告诉我 分段

    2 回复  |  直到 8 年前
        1
  •  14
  •   battlmonstr    8 年前

    别让事情复杂化。

    首先你需要做一个 git log 找出要还原的提交ID。例如,它是提交 abc123 . 如果您知道这是最后一个,您可以使用一个特殊的标识符“head”。

    然后,首先在本地的“分段”分支中还原它:

    git checkout staging
    git revert abc123
    

    注意:对于日志中的最后一次提交,您将写入 git revert HEAD .

    然后你更新你的远程“登台”功能:

    git push
    

    说明:在Git中,如果您有一个远程存储库,那么您将处理两个不同的存储库(本地和远程)。在你这样做之后 git checkout staging ,您实际上创建了一个表示远程分支的不同本地名称。 git revert 实际上不会删除提交,但它会在上面创建一个新的提交,这会撤消所有更改(如果添加了一个文件-新的提交将删除它,如果删除了一行-新的提交将把它添加回去等等),即,它是日志的一个添加,这就是为什么推送是干净的。

    如果你真的想让它消失,这样就没有人可以责怪你,你可以冒风险:

    git checkout staging
    git reset --hard HEAD^
    git push -f
    

    (重置行重新定位本地的“分段”分支,以便它指向一个在顶级提交之前的提交)

    一般来说,强制推送是一种不好的做法,但是保持无用的提交和恢复也是不好的,因此另一种解决方案是实际创建一个新的分支“staging2”,并在该分支中进行测试:

    git checkout staging
    git checkout -b staging2
    git reset --hard HEAD^
    git push
    
        2
  •  1
  •   torek    8 年前

    DR

    记住这一点 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非常确定(并且正确)您 已经合并了所有的工作 并且正确的结果已经到位(也就是说,你只是稍后将其取消)。要将其全部还原,可以还原还原。

    还原将生成一个新的提交,就像每个提交一样,只会向当前分支添加一个新的提交。您总是在自己的存储库中这样做。剩下的工作就是把新的承诺 其他 Git存储库,将其作为其中一个的新提示添加到另一个Git的集合中 他们的 分支。

    长(涉及很多细节)

    首先,让我们后退一点,因为这个短语 远程分支 意味着什么都没有,或者更确切地说,对太多不同的人来说,意味着太多不同的事情。无论哪种情况,都会导致沟通失败。

    Git确实有 分支 但即使是“分支”这个词也是含糊不清的(参见 What exactly do we mean by "branch"? )我觉得最好具体点:我们有 分支机构名称 喜欢 master staging 在你的建议中, cleaning . Git也有 远程跟踪名称 远程跟踪分支名称 喜欢 origin/staging 但令人困惑的是,Git存储了这些名称 本地 即,在您自己的存储库中(仅限)。你的Git使用 你的 起点/分段 记住你的Git看到了什么 他们的 吉特,当你的吉特最后一次和他们的吉特说话时,问他们一些事情 他们的 分段 .

    因此,问题的根源在于您的Git存储库是 你的 但是还有第二个Git存储库 你的,你最终想做点什么 其他 Git存储库。这里的限制是你的Git只允许你在 你的 存储库,之后您将最终运行 git push . 这个 Git推送 步骤将把一些提交或提交从Git存储库转移到它们的Git存储库。这时,你可以问 他们的 要设置的Git 他们的 名称 他们的 分段 他们要么说 是的,我已经设置好了 (您的Git现在将更新 起点/分段 记住这一点),或者 不,我拒绝设置,原因如下:uuuuuuuuuuu(在此处插入原因) .

    因此,你要做的是 你的 存储库设置了适当的步骤,以便 他们的 吉特,英寸 他们的 存储库,将接受提交 Git推送 并将更新 分段 . 在我们进行这些步骤时,请记住这一点。有多种方法可以做到这一点,但下面是我将使用的方法。

    1. git fetch . 这个命令运行起来总是安全的。如果你有多个遥控器,你可以给它一个特定遥控器的名字,但是大多数人只有一个遥控器 origin 如果你只有一个,就不需要命名了。

      (遥控器的名称) 起源 _主要是一种简单的拼写方法,您的计算机应该使用它来访问其他Git存储库。)

      这个 Git获取 可能什么都不做,或者可能更新一些远程跟踪( origin/* )姓名。什么 Git获取 是调用了另一个git,从中得到一个所有分支的列表,其中commit散列与它们一起使用,然后将它们拥有的所有未使用的commit都带过来。 起点/分段 现在记住他们 分段 . 现在您可以为此添加新的提交。

    2. 现在你的 起点/分段 与其他Git同步 分段 ,根据需要创建或更新本地分支名称。这里最好用的名字是 分段 ,但您可以使用 打扫 如果你愿意的话。因为这一步是 创建或更新 ,分步骤:

      • 如果是“创建”,可以使用 git checkout -b staging origin/staging 创建新的 分段 其上游为 起点/分段 .

        你可以把这个缩短到 git checkout staging 因为你没有自己的 分段 将搜索所有 来源/* 名称(以及任何其他远程跟踪名称,如果您有多个远程名称),以查找匹配的名称。然后,它就好像您使用了更长的命令一样。(只有一个遥控器,唯一可以匹配的名称是 起点/分段 . 如果你两个都有 起源 xyzzy 作为遥控器,你可以同时拥有两个 起点/分段 xyzzy/staging ;那么您需要更长的命令。)

      • 或者,如果它是“更新”,您将已经有一个 分段 已经有了 起点/分段 设置为它的上游,因为您以前已经这样做过。在这种情况下,只需运行:

        git checkout staging
        git merge --ff-only origin/staging
        

        使您的登台与重新同步 起点/分段 . 如果快进合并失败,那么您有一些提交,它们没有,您将需要更复杂的内容,但我们在此假定这是成功的。

        你也可以缩写一下这些命令,但我会把它们放在这里。注意,第一个命令是 相同的 作为上面第一个案例的简短版本,您可以通过输出判断发生了哪一个 Git签出阶段 . (我会留下其他问题或练习的细节。)

      我们可以在您自己的存储库中绘制您现在拥有的内容的图片,它看起来像这样:

      ...--o--o--o---M   <-- staging (HEAD), origin/staging
               \    /
                o--o   <-- feature/whatever
      

      每轮 o 表示提交。 M 表示合并提交,其结果您不喜欢,但在其他Git中也存在于 起源 在下面 他们的 名称 分段 这就是为什么你自己的Git有这个名字 起点/分段 指向提交

    3. 现在您要创建一个提交 撤消 糟糕的承诺。这可能会用到 Git还原 但记住,还原意味着 解开 退出 不是 切换到旧版本 . 你告诉Git哪一个承诺要撤销,Git通过找出你做了什么和做了相反的事情来撤销它。

      例如,如果您说要还原的提交说“删除文件自述文件”,则更改将包括“将文件自述文件还原为删除时的格式”。如果说要还原的提交说“将此行添加到documentation/doc.txt”,则更改将包括“从docum中删除该行”。Entation/Doc.txt”。如果在第三个文件中,您说要恢复的承诺说“将hello改为再见”,那么恢复所做的更改就是在同一行的第三个文件中将“再见”改为“hello”(如果该行被移动,使用某种魔力可以找到该行)。

      这意味着 Git还原 可以撤消任何提交,即使它不是最新的提交。但要做到这一点,必须 将该提交与它的直接父级进行比较 . 如果试图还原的提交是 合并 承诺,它已经 多个父级 您需要指定应该使用哪个父Git。

      要使用的正确父对象并不总是显而易见的。然而,对于大多数合并,它只是“父编号1”。这是因为Git特别强调 第一 合并的父级:提交 HEAD 当你跑步时 git merge . 所以这就是合并带来的,还没有出现的一切。

      Git还原 成功后,将进行一次新的提交,以撤消合并的效果:

                       W   <-- staging (HEAD)
                      /
      ...--o--o--o---M   <-- origin/staging
               \    /
                o--o   <-- feature/whatever
      

      在这里, W 表示此新提交:它是 倒转过来。你现在要做的就是跑 git push origin staging 发送你自己的新承诺 W 其他Git:

    4. Git推送源站分段 :这会调用另一个git并提供它commit W 这是我们的每一个承诺,他们没有;他们有 所有的东西都在前面(左边),但不是 W

      只要没有特殊的限制,他们就会接受这个新的承诺和更改。 他们的 分段 指向新提交 W . 您的Git将记住更改:

                       W   <-- staging (HEAD), origin/staging
                      /
      ...--o--o--o---M
               \    /
                o--o   <-- feature/whatever
      

      (不用一直画画 W 在另一行,但我使用复制粘贴来保持形状不变。)

    正如你所看到的,你现在已经完成了。你和他们都同意 分段 两者都应该指向提交 W 有撤销承诺的效果 . 现在可以安全地删除您自己的 分段 姓名,如果您喜欢:

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

    产生:

    ...--o--o--o---M--W   <-- origin/staging
             \    /
              o--o   <-- feature/whatever