如何还原更改所有文件的特定提交,在还原期间导致大量冲突?

时间:2018-04-26 10:24:40

标签: git

在一个协作存储库中,有人做了一个提交,以某种方式使它看起来像是重新添加了存储库中的所有文件。

使用--date-order打印时,以下是历史记录的一部分:

* 28cbf861 - (65 minutes ago) update logs and metadata (HEAD -> master, origin/master, origin/HEAD)
* e589776e - (18 hours ago) P2LTR15 update
...
* d4c61147 - (5 days ago) Delete P2STR03_SRC00150_Q0448_0000_0-7.log
* fa837509 - (5 days ago) Delete P2STR03_SRC00150_Q0427_0000_0-7.log
*   9a5e2300 - (5 days ago) git pull at 20180421 10am.
|\
* | 6567df4b - (5 days ago) add md5 3min
* | 6f7c80f7 - (5 days ago) Added md5sum files for all 3min SRCs
 /
* b97e834f - (6 days ago) Delete P2STR13_SRC00605_Q0325_0000_0-9.log
* 5cd9989b - (6 days ago) Delete P2STR13_SRC00605_Q0129_0000_0-9.log
* 769ae25d - (6 days ago) Delete P2STR13_SRC00605_Q0209_0000_0-9.log
...

错误提交是6f7c80f7,我想将其删除,但请保留6567df4bgit pull提交(9a5e2300)是一个简单的合并提交。

当我打印没有--date-order的历史记录时,突然会在最底部显示提交6f7c80f7,即好像它是第一次提交。

* 28cbf861 - (70 minutes ago) update logs and metadata
* e589776e - (18 hours ago) P2LTR15 update
...
* fa837509 - (5 days ago) Delete P2STR03_SRC00150_Q0427_0000_0-7.log
*   9a5e2300 - (5 days ago) git pull at 20180421 10am.
|\
| * b97e834f - (6 days ago) Delete P2STR13_SRC00605_Q0325_0000_0-9.log
...
| * 697a103c - (7 months ago) initial commit
* 6567df4b - (5 days ago) add md5 3min
* 6f7c80f7 - (5 days ago) Added md5sum files for all 3min SRCs

我尝试过git revert 6f7c80f7,但它显示了很多我不知道如何解决的冲突,也就是说,当我执行git status时:

On branch master
Your branch is up to date with 'origin/master'.

You are currently reverting commit 6f7c80f7.
  (fix conflicts and run "git revert --continue")
  (use "git revert --abort" to cancel the revert operation)

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

    deleted:    P2LTR15/.gitkeep
    deleted:    P2LTR15/MOS_P2LTR15_MO.csv
    ... (this is basically a list of almost all the files in the repository)

Unmerged paths:
  (use "git reset HEAD <file>..." to unstage)
  (use "git add/rm <file>..." as appropriate to mark resolution)

    deleted by them: P2LTR15/P2LTR15.yaml
    deleted by them: P2LTR15/audioFrameInformation/P2LTR15_SRC00712_HRC021.afi
    ... (this is another list of files, I don't know why it is there, possibly those were actually changed)

还有其他方法可以重写Git历史记录,以至于这个错误的提交从未发生过吗?

我看过this guide但它也只是告诉我做一个恢复。我应该在那之前尝试返回提交,然后cherry-pick commits然后强制重写存储库吗?我认为这也不是一个好选择。

1 个答案:

答案 0 :(得分:2)

您说git log输出引用只是历史记录的一部分,但您也说提交6f7c80f7会添加所有文件,在引用的文本中,6f7c80f7从不显示它所连接的任何父提交。

这表明6f7c80f7 root commit:一个初始提交,实际上会添加它显示的每个文件,因为&#34; previous&#34; commit不存在,因此根据定义,每个文件必须是该提交中的新文件。

图表 可以有多个根目录。它在Git提交图中有点不寻常,因为我们通常首先检查一些现有提交,然后进行更改,然后运行git commit以保存新的完整快照来进行新提交。但还有其他方法:

  • 我们可以使用git fetch获取不相关的存储库,然后git merge使用--allow-unrelated-histories。如果Git版本足够大,git merge 总是允许不相关的历史记录,并且没有--allow-unrelated-histories标志:它只是合并这些而没有警告。 (你可能会在这里看到很多add/add conflict错误,但是必须做很多手工解决!)

    这会将他们的 - 其他存储库的根提交添加到我们自己的提交图中,该提交图已经有了root提交,所以现在我们有两个root提交。

    < / LI>
  • 我们可以使用git checkout --orphan设置我们自己的存储库状态,以便我们进行的下一次提交将是根提交。

    (如果我们进行根提交,我们将遇到与&#34;获取无关存储库&#34;案例相同的合并问题。)

  • 我们可以,偶然或故意地使用Git内部,使用git commit-tree之类的管道命令或只是戳.git内的文件来创建新的根提交。

在任何情况下,一旦我们拥有这个状态,其中存在多个根并且合并提交合并额外的根,然后在合并之上构建了更多提交,我们就会陷入困境。合并提交 - 在您的情况下,9a5e2300 - 有一个哈希ID,依赖于 两个提交链的存在:返回原始链的那个root commit,以及返回新root提交的那个。在您的情况下,9a5e2300作为父项的任何提交的哈希ID,这只是一个提交fa837509 - 取决于9a5e2300的存在,因为它实际上包含了该哈希ID成为自己的ID。 fa837509子项的哈希ID(此处图中只有一次提交)则取决于fa837509的存在性;如果图表的其余部分是线性的,那么每个孩子依次依赖父ID,一直到最后。

因此,如果您以某种方式摆脱额外的根提交,您的合并提交将需要具有不同的哈希ID,这意味着每个后续提交需要具有不同的哈希ID。此外,如果您 完成了6f7c80f7,那么您必须为其当前子6567df4b创建的副本将 另一个root提交!你也必须摆脱那个,这意味着合并提交9a5e2300没有合并的东西,所以你可能也想放弃它 - 除了你想要的以某种方式保留其源快照。然后你需要将所有剩余的(可能是线性的)链从fa837509一直到提示,并将每个那些提交复制到不依赖于存在的新提交中9a5e2300的{​​{1}},但确实使用了具有来自合并提交的更新源快照的任何提交。

因此,这会导致您必须使用的过程以避免两次root提交:

  • 将合并9a5e2300中的快照复制到新的非合并提交。这会获得一个新的哈希ID(因为它是一个新的唯一提交)。在某处保存该ID。

  • fa837509中的快照复制到新提交中,该提交同样获取新的哈希ID。新提交的父级将是您刚刚保存的ID。将此ID保存在某处。

  • fa837509子项中的快照复制到新提交中,使用上一个副本作为新父项。

  • 重复每次提交,直至到达提示。

一旦你拥有了这个不依赖于想要删除的提交的线性提交链,你就可以停止使用 所提交的原始提交链依赖于你想要摆脱的提交。如果和其他人执行此操作,并删除Git 找到旧链的名称,则表明旧链似乎从未存在过。随着名称的消失,最终旧的提交确实被删除了。 (当所有的安全检查计时器都到期时会发生这种情况。这些安全检查存在,如果你犯了错误就可以恢复旧的提交,但很快就能抓住它 - 通常是30天 - 这样Git可以制作不是然后连接到提交图,但在14天之内。正常的Git命令在最差的几毫秒内将它们连接起来,所以14天几乎是几千年。)

以上显示可能执行您的建议(尽管您可能希望构建一个与我所描述的略有不同的替换历史记录)。它是否是一个好主意完全是另一个问题。重写历史记录的主要缺点,无论你使用git rebasegit filter-branchThe BFG Repo Cleaner,还是你自己想出的东西 - 重写的存储库是实际上是一个 new 存储库。或者至少,新链是新的:旧的东西,从重写点之前,是相同的。您必须拥有旧存储库副本的所有人才能从内容切换到内容。如果即使一个单人保留旧提交,并使用Gi​​t将旧版本与新版本融合(Git很乐意这样做),所有旧版提交都会立即返回。现在你把旧的和新的都拼凑成一个大的快乐(?)存储库,你的问题变得更糟了!

将您的提交(部分或全部)重写为新历史没有任何根本性的错误,您只需要(a)知道如何做到这一点,并且(b)了解这一点&#34;每个人都必须切换&#34 34;后果。如果没有其他人拥有你要替换的提交,那么这种重写是完全安全的 - 那里没有其他人其他Git存储库将旧的承诺重新发挥作用。如果的每个人都有旧提交了解其工作方式并计划合作,那么这种历史重写主要是安全:只有在有人犯错时才会出错(然后,取决于你自己的谨慎和/或偏执的程度,也许只有他们!)。当你拥有天真的用户时,他们只是让Git默认Borg-like action整合了它所遇到的每一项技术,这种重写会造成混乱。

相关问题