Git:推送合并后,将其与意外丢弃的文件还原

时间:2018-10-25 10:57:57

标签: git version-control

没有经验的用户进行更改release,然后合并到dev。哦,不,合并冲突!合并状态显示他们自己的冲突文件,以及其他团队成员的所有其他修补程序。作为偏执狂和谨慎的用户,他们说:

  

这些不是我的文件,我是否不小心更改了它们?啊哈,我应该discard他们!

现在,合并提交仅包含其更改,而丢弃分支中的所有其他更改(可能需要大量工作)。他们将dev推向上游,直到另一个团队成员发现某件事不对劲,该错误才被发现。

大多数指南建议:

  1. 如果尚未推送分支:git reset
  2. 还原合并:git revert -m 1 <commitId>。但是,这只会还原数据(也就是仅不幸用户的更改),不会撤消历史记录。将来进行merge的任何尝试都将忽略丢失的更改,因为历史记录表明它们已经集成。
  3. 重写历史记录,rebasereset后跟git push origin -f。这意味着团队的其他成员必须与强制的dev分支同步。如果团队很大,或者没有迅速发现错误,或者存在复杂的CI工具-这将是非常痛苦的练习。

Imho在git的设计中给我带来了严重的疏忽。很少有工具可以识别这种情况或从这种情况中恢复过来。 git diff不会显示已放弃的更改,而git revert不会撤消那些已放弃的更改。有没有更好的方法来预防和解决此问题?

1 个答案:

答案 0 :(得分:1)

如Linus(https://mirrors.edge.kernel.org/pub/software/scm/git/docs/howto/revert-a-faulty-merge.txt)所述:

  

还原常规提交只会有效撤消该提交       做到了,而且相当简单。但是还可以还原合并提交       撤消提交已更改的 data ,但绝对可以       合并对历史的影响不大。

     

因此合并将仍然存在,并且仍将被视为加入       这两个分支在一起,将来的合并将看到该合并为       最后一个共享状态-以及还原了合并带来的还原       完全不会影响。

     

因此,“还原”撤消数据更改,但这不是       “撤消”在某种意义上说不会撤消提交对       存储库历史记录。

好的,这可以解释为什么revert不是有效的策略,但是我们能做什么?让我们考虑以下内容:

p---Q---r---s---M---t---u---   dev
     \         /
      A---B---C-------D---E    feature
  • ABC是功能/发行分支
  • M是不好的合并,是放弃了AB的更改,但保留了C
  • DE稍后将在feature上工作
  • 其余是与主线分支dev无关的更改

只要M存在于dev上,就假定ABC的历史已被整合,即使AB的缺失也没有。要在不更改dev的历史记录的情况下恢复它们,我们需要在备用历史记录(即新的提交ID)中重新创建增量。

如果提交的次数很少,则可以将每个单独的cherrypick分别dev拖到rebase --no-ff上,将数据复制到新的提交ID中。但是,这不能很好地适应大型或复杂的分支历史。

下一个选择是使用feature重新创建一个新的git checkout E git rebase --no-ff Q 分支,可以从中合并丢失的更改。

      A'--B'--C'-------D'--E'    feature-fixed
     /                      \
p---Q---r---s---M---t---u---M2   dev
     \         /
      A---B---C--------D---E     feature

这将创建以下内容:

p---Q---r---S-------M---t---u-----M3      dev
     \       \     /              /
      A---B---\---C----D---E     /        feature
               \   \            /
                ----M2----------          fix

原始合并M可能仅由于合并冲突而成为问题。这种方法的一个问题是,不仅您必须正确解决ABC中的原始冲突,而且现在您还需要解决DE和TU中新的冲突源。在紧急情况下,弄清楚发生了什么可能很麻烦。

首选解决方案:

squash

使用您可能熟悉的工具,一种更简单的策略是使用dev提交(M2)正确地重新创建合并。这将创建一个新的提交ID(新历史记录),因此AB的增量可以成功地集成回主线。此方法还可以消除可能的合并冲突源,使您可以首先更正错误,然后处理上游更改。

方法:

在错误合并(M)降落之前从git checkout -b fix S 分支。

git merge --squash C

您现在拥有一个干净的状态,可以从中执行更正的合并。 squash标志会将这些更改压缩为一个提交,但更重要的是它将生成一个新的提交ID

git checkout dev
git merge fix

就像在这一点上一样,您将需要解决冲突,但是M2现在表示M原来应该包含的所有数据。现在,您可以像往常一样将其合并到开发者中了

feature

同样,可能会发生合并冲突,但是在这一点(M3)之后,您已经恢复了丢失的数据。现在,您可以按正常方式继续进行操作,例如,可以将DE从dev合并到dev或任何其他常规操作中。这也意味着其他团队成员无需重置其本地pull分支,因为该分支将在下次执行TYPE Array IS TABLE OF VARCHAR2(50); TYPE ArrayArray IS TABLE OF Array; 时恢复。