【问题标题】:Git revert deleted file and preserve file historyGit 恢复已删除的文件并保留文件历史记录
【发布时间】:2021-07-28 07:34:12
【问题描述】:

假设我有一个文件a.txt。有一天,我删除了它,提交并推送。

第二天,我想恢复上一次提交,带回a.txt。我尝试使用git revert,但是当我使用git blame 时,所有行都显示还原提交哈希。原来的责备历史丢失了。

我可以恢复文件并保留文件历史记录,即,就好像该文件之前没有被删除一样?请注意,由于提交已被推送,因此我不能更改历史记录。

谢谢!

【问题讨论】:

  • 你的意思是你不能做一个--force推送到上游?
  • Git 不跟踪文件历史;它只跟踪整个根目录的历史。因此,在请求查看历史记录时重建文件历史记录是一个问题,而不是在恢复文件时。
  • @shengy 不,我不能

标签: git git-revert git-blame


【解决方案1】:

可以做到这一点!方法如下:

  1. 从要撤消的删除之前的提交开始一个新分支。
  2. 将有问题的更改与git merge <sha> -s ours 合并。
  3. 如果提交除了您要保留的删除之外还有更改:
    1. 使用git diff <sha>^..<sha> | git apply 将更改重新应用到您的工作副本。
    2. 放弃删除(有许多技术可用;git checkout -p 可能对您很有效)。
  4. 将此分支合并回主分支(例如 master)。

这会产生一个有两个分支的历史;一种是文件被删除,另一种是从未删除。因此,git 能够跟踪文件历史记录,而无需求助于 -C -C -C 之类的英雄事迹。 (事实上​​,即使使用-C -C -C,文件也不会“恢复”,因为 git 看到的是一个新文件是作为以前存在的文件的副本创建的。使用这种技术,您正在将相同的文件重新引入存储库。)

【讨论】:

  • 工作就像一种享受,我现在学到了一些东西,谢谢@Matthew!我的案例相当复杂,我需要对git checkout -p 进行一些解读,但即使是在部分有问题的提交中混合了更改,这种方法最终也能完全按照我的需要工作。
【解决方案2】:

使用指定的-C 选项运行 git blame 三次:

git blame -C -C -C

这会导致git blame 查找从以前提交的文件中复制的内容。

来自the documentation for git blame

-C|<num>|

除了-M,检测从其他文件移动或复制的行 在同一次提交中被修改。这在您重新组织时很有用 您的程序并跨文件移动代码。当这个选项是 给出两次,该命令另外查找来自其他的副本 创建文件的提交中的文件。当给出这个选项时 三次,该命令另外查找其他副本 任何提交中的文件。

<num> 是可选的,但它是数量的下限 Git 必须检测为在之间移动/复制的字母数字字符 文件,以便将这些行与父提交相关联。和 默认值为 40。如果给出了多个 -C 选项,则 最后一个-C<num>参数将生效。

【讨论】:

  • 你确定这有效吗?我试过类似git initecho "test" > a.txt"git add a.txtgit commit -m "Commit 1"echo "foobar" >> a.txtgit add a.txtgit commit -m "Commit 2"git commit -m "Commit 2"git rm a.txtgit commit -m "Commit 3"git revert HEADgit blame -C -C -C a.txt和>
  • @fushar 我很确定你需要不止一个词来让 git 注册你移动了一些东西。文档说最少 40 个字符。我已将答案中的引文编辑得更完整。
  • 我只是想在最简单的例子中表明您的解决方案不起作用。实际上它也不适用于我的真实项目(我删除的文件内容当然比 40 大得多)。对于您的编辑 -- git blame -C1 -C1 -C1 a.txt 不幸的是也不适用于 a.txt 示例。
  • @fushar 嗯,你是对的。我似乎无法让它工作。文档似乎在说它应该工作,所以也许这是一个错误。要么这样,要么我完全误解了它应该如何工作。
【解决方案3】:

您可以使用git reset 而不是git revert 来做到这一点。 git reset 删除新提交并签出以前的提交。如果您已经推送到上游,则不建议这样做。

NAME
       git-reset - Reset current HEAD to the specified state

SYNOPSIS
       git reset [-q] [<tree-ish>] [--] <paths>...
       git reset (--patch | -p) [<tree-ish>] [--] [<paths>...]
       git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>]

DESCRIPTION
       In the first and second form, copy entries from <tree-ish> to the index. In the third form, set the
       current branch head (HEAD) to <commit>, optionally modifying index and working tree to match. The
       <tree-ish>/<commit> defaults to HEAD in all forms.

既然你已经推送了:

  • 如果您当天没有活跃的协作者拉动,请使用git reset 并强制推动git push -f

【讨论】:

  • 他已经删除文件并推送到上游,git reset此时对他不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-22
  • 2015-12-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多