2015-08-19 102 views
7

假设我有一个文件a.txt。有一天,我删除了它,承诺并推送了它。Git还原已删除的文件并保留文件历史记录

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

我可以恢复文件并保留文件历史记录吗?就好像文件还没有被删除过?请注意,我不能在提交被推送时更改历史记录。

谢谢!

+0

您的意思是说您无法对上游进行强制推送? – shengy

+2

Git不会跟踪文件历史记录;它只跟踪整个根目录的历史记录。因此,在请求查看历史记录时,重建文件历史记录是一个问题,而不是在恢复文件时。 – Nayuki

+0

@shengy不,我不能 – fushar

回答

0

您可以通过使用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
+0

他已经删除了文件并推送到上游,此时'git reset'不适用于他。 – shengy

1

-C选项运行git怪指定三次:

git blame -C -C -C 

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

the documentation for git blame来自:

-C|<num>|

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

<num>是可选的,但它是下界上GIT中必须检测 文件之间作为移动/复制为它与母提交这些线相关联的字母数字 字符数。 默认值为40.如果给出的选项不止一个-C,则最后的-C的参数 <num>将生效。

+0

你确定这有效吗?我试过类似'git init'' echo“test”> a.txt'''git add a.txt''git commit -m“Commit 1”''echo“foobar”>> a.txt''git add a.txt'git commit -m'Commit 2'''git rm a.txt''git commit -m“Commit 3”''git revert HEAD''git blame -C -C -C a.txt' and这两行显示恢复提交... – fushar

+0

@fushar我敢肯定,你需要多个单词让git注册你移动了一些东西,文档中说最少有40个字符,我在我的回答中编辑了引用 – Ajedi32

+0

我只是想表明你的解决方案在最简单的例子中不起作用,实际上它并不适用于我的真实项目(我删除的文件内容远远大于40)。 - 'git blame -C1 -C1 -C1 a.txt'不幸也不适用于'a.txt'的例子。 – fushar

2

CAN做到这一点!方法如下:

  1. 从您想要撤消的删除之前的提交开始一个新的分支。
  2. 将违规更改与git merge <sha> -s ours合并。
  3. 如果除了删除要保持提交了变化:
    1. git diff <sha>^..<sha> | git apply重新应用更改到你的工作副本。
    2. 放弃删除(许多技术可用; git checkout -p可能适合您)。
  4. 将此分支合并回主分支(例如主)。

这产生了两个分支的历史;其中一个文件被删除,其中一个它从未被删除。因此,git能够跟踪文件历史,而不诉诸于诸如-C -C -C这样的英雄。 (事实上​​,即使使用-C -C -C,该文件也不会被“恢复”,因为git会看到的是,一个新文件被创建为作为先前存在文件的副本。使用此技术,您将重新引入相同的文件)。

+0

作品像一种享受,我现在学到了东西,谢谢@Matthew!我的情况相当复杂,我需要阅读一下'git checkout -p',但即使在部分违规提交中进行了混合更改,此方法也完全按照我需要的方式工作。 – bossi

相关问题