撤消提交并修复git push

时间:2014-02-21 14:12:28

标签: git github git-rebase

我有一个带有主分支的回购和一个名为febupdate的分支。一周前(或左右)我向febupdate分支提交了一些新文件并将更新推送到github。从那时起,又有三个提交被推送到该分支。

然后有人回来说,几周前提交的所有文件都需要拔出(因为它们是其他数据的副本)。我不知道该怎么做,所以我要求提供一些建议并被告知git rebase HEAD~3。所以我这样做了,我删除了错误的提交,我本地副本中的所有内容现在都应该如此。但我们无法弄清楚如何让github上的回购反映出来。最后我们做了git push --force

现在,只要有人对该分支进行git pull,就会要求他们提供合并内容的原因。用户也会收到所有重复文件。我们唯一能做的就是吹掉整个文件夹,然后做一个新的git clone

以下是我的问题

  1. 我们将febupdate分支合并为master后会继续这种行为吗?任何从主人那里做git pull的人都会得到一个关于合并数据的对话,并最终得到我试图杀死的额外文件吗?我们是否需要告诉所有人吹走他们的本地副本并做一个新的git clone
  2. 我从前一次提交中删除文件的正确方法是什么?我应该指出它就像60个文件,所以它不像我刚刚在两个文件上做了一个git rm。我想我本可以尝试制作一个文件列表并完成一些循环到git rm所有这些。
  3. 任何解散febupdate分支的方法吗?

4 个答案:

答案 0 :(得分:2)

首先,其他人不需要新的git clone。如果他们知道这个“rebase”,他们可以使用

git fetch  
git reset --hard origin/febupdate

关于你的第一个问题:

答案是否定的,为什么你的febupdate分支搞砸是因为“rebase”。 rebase导致git无法快速转发更改。对于master分支,我们只在将febupdate合并到它时添加新的提交。在这种情况下,其他人可以毫无问题地使用pull。 (git可以快进)

所以我猜你知道问题2和3的答案。如果你只添加新的提交,其他人可以毫无问题地提取。要做到这一点,一个技巧是:

  1. 备份当前HEAD(您可以使用tmp分支)。
  2. 使用任何方式去正确的状态,你的“git rebase HEAD~3”是单向的。
  3. 将此正确状态的所有文件复制到tmp目录(git目录之外)。
  4. 通过从备份分支恢复返回当前的HEAD。
  5. 用tmp dir文件替换你的整个git目录。
  6. 现在git status将显示您删除了所需的文件,提交更改,推送

答案 1 :(得分:1)

一旦每个人都有历史记录更新,合并问题应该停止。或者他们可以在分支上执行git reset --hard <sha before the reset>并执行拉动(这将导致他们丢失他们拥有分支的任何提交)。他们应该通过创建一个新的分支来备份这些更改,他们可以使用这个分支来挑选他们的提交。

本文应该对正在发生的事情有所了解。为什么在推送提交上执行git rebase是一件非常糟糕的事情。

http://git-scm.com/book/en/Git-Branching-Rebasing#The-Perils-of-Rebasing

下次要撤消已推送的更改时,应使用git revert <sha of commit>。这将创建一个新提交,它是问题提交的反转。如果您只想撤消某些更改,请执行git checkout <sha of commit with good files> -- <files to fix>并进行提交。

如果您推送了更改,则需要进行新的提交以修复更改,而不是尝试通过删除提交来修改历史记录。

答案 2 :(得分:0)

这是因为他们仍然拥有您在旧版哈希下的回购中恢复的对象。 Git必须将新提取的数据与图中的哈希值合并,它可能会要求您提交提交消息,因为它正在尝试快进合并。如果你能通过rm'ing可能更清洁的文件解决问题。

答案 3 :(得分:0)

按顺序:

  1. 他们不必重新克隆(虽然这样可行)但是他们必须做一些额外的工作。

    当您执行rebase时,您复制了旧提交。假设提交B是您“删除”的那个:

    A - B - C - D    [old "febupdate", is what you pushed originally]
      \
        C'- D'       <-- HEAD=febupdate
    

    任何抓住第一个“推送”副本的人都有三个原始提交,B CD。然后当他们去获取更新时,他们会收到新的提交C'D'。假设他们自己添加了提交E。所以他们现在(在引入更新之前):

    A - B - C - D       <-- origin/febupdate
                  \
                    E   <-- HEAD=febupdate
    

    一旦他们引入您的更新,他们就会得到:

    A - B - C - D - E   <-- HEAD=febupdate
      \
        C'- D'          <-- origin/febupdate
    

    就git而言,当它看到这个新状态时,它认为他们写了提交BCD和{ {1}}和写了提交EC'。 Git让他们有机会将他们的四次提交(D'B)与你的两次合并。

    即使他们没有进行新的提交E,git仍然可以让他们有机会将“他们的”三次提交(EB)与您的两次合并。实际上,这将“恢复”提交D

    如果他们没有自己的提交(编辑当然没有未保存的工作!),他们只需强制执行B即可轻松恢复匹配febupdate

    origin/febupdate

    如果他们拥有他们自己的提交(例如$ git checkout febupdate; git fetch; git reset --hard origin/febupdate ),他们需要将这些(而不是任何待删除的)提交到新提示提交{ {1}},他们可以使用ED'。后者在 1 上工作有点棘手,但是一下子就完成了所有事情。前者(git cherry-pick)更容易思考:他们只需将git rebase --onto重命名为cherry-pick,创建新的本地分支febupdate以跟踪oops,然后{ {1}}每个提交(真正他们的提交)从febupdate到新origin/febupdate

  2. “正确”的方式是谁愿意做什么样的工作,以及你和他们是否愿意允许错误提交git cherry-pick保留在提交历史中。如果每个人都愿意完成上述所有工作,并且确实不希望oops保留,那就是这样做的方法。

    如果febupdate可以保留,并且您想让人们轻松,则可以使用B。作业B的作用是添加一个新的提交,其效果只是“撤消旧提交中的操作”。假设在提交B中您添加了一个文件git revert并从git revert中移除了一条好的行。命令B将进行提交,删除badfile并将好行放回goodfile。无论在git revert <sha-1-of-B>中发生什么,都要恢复“取消”并添加新的提交:

    badfile

    每个人都希望添加新的提交,因此这“适用于”每个人已经拥有的工作流程。

  3. 排序,但是如果某些人已经抓住了提交goodfileB,那么无论你现在做什么都会让某些人有额外的工作(超出他们已有的额外工作-工作)。在这种情况下,我可能只是继续让人们进行恢复(如上文第(1)部分所述)。


  4. 1 git 1.9 / 2.0中即将推出的功能应该(至少在理论上)使它不那么棘手。另外,作为一种特殊情况,A - B - C - D - R <-- HEAD=febupdate 在当前git中做正确的事情,但前提是你还没有运行C'。 (这有点难以描述。)