在Git中恢复移动文件的历史记录

时间:2013-09-04 11:41:48

标签: git version-control

如果文件的名称和内容已更改,是否可以在提交后标记移动?

e.g。

  1. file1.txt已更改为file2.txt且内容已更改。
  2. git commit
  3. Git认为file1.txt已被删除,file2.txt是一个无关的新文件。
  4. 有没有办法在提交发生后将其标记为重命名?

3 个答案:

答案 0 :(得分:4)

不,不是,因为Git没有重命名跟踪 ...但它确实重命名 detection (基于文件内容和名称的相似程度)。

这意味着

  • git log --follow file2.txt将通过重命名跟踪文件历史记录(注意:遗憾的是,这并不总是正常工作,因为--follow有点破解),
  • git blame -C -C file2.txt将遵循文件重命名,内容复制以及跨文件和内部文件移动的逐行文件历史记录
  • git show -C会显示文件重命名(您可以将Git配置为在显示差异时始终重命名,甚至可以选择复制检测)。

HTH

答案 1 :(得分:1)

正如您所发现的那样,git不会检测到真正实质性更改和同时移动重命名的组合。

要理解的是,每次查看历史记录时,git都会通过将提交的内容与其父提交进行比较来检测提交中的更改。这看起来似乎很简单,但事实证明它很简单。

所以你需要插入一个新的提交,git log等可以检测的重命名,然后是你从那时起累积的其余历史记录,这意味着你的分支的新历史记录,即rebase or cherry-pick。

所以:

# make a new history with a rename that can be detected by comparing commits
# check out the glitched commit's ancestor by its sha, 
# this work won't take enough time to bother inventing a transient name for it
git checkout commit-before-rename+bigchange      
git mv file1.txt file2.txt
git commit
git checkout commit-with-rename+bigchange -- file2.txt
git commit

# Now add the rest of the changes, also detectable by comparing commits,
# by re-applying them on top of this new history:
git cherry-pick commit-before-rename+bigchange..branch-it\'s-on

# and force the old branch name to refer to this new history you just made
# the old history will be garbage-collected after 90 days or so if
# it's not part of the history of any other references
git checkout -B branch-it\'s-on 

并且你已经完成了,除非任何其他存储库通过获取或推送或克隆获得了混乱的历史记录,那么你将不得不强制推送或让那些repo的所有者强制重新获取(以及任何后续的他们建立在历史之上的历史,这就是为什么你真的不想发布太快的原因。)

答案 2 :(得分:0)

不,没有。 Git没有任何文件标识的概念。它存储目录树的内容。只有树作为一个整体才有历史概念。

只有一个原因可以跟踪文件是否已重命名,而不是旧文件已删除,并添加了新文件,这是为了允许合并该文件中的更改。由于您更改了文件(超出重命名检测认为的类似),因此无法在没有冲突的情况下合并更改,因此应该没有实际区别。

请注意,Git会通过搜索类似文件来处理合并原因。它会在git status和所有合并中自动进行,并在git loggit diff以及其他显示更改的命令中执行此操作。如果找不到重命名,则不太可能进行合并。