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

6

如果更改了文件的名称和内容,提交后是否有可能标记移动操作?

例如:

  1. file1.txt 更改为 file2.txt 并更改了内容。
  2. git commit
  3. Git 认为 file1.txt 已被删除,而 file2.txt 是一个不相关的新文件。

是否有一种方法可以在提交后将其标记为重命名操作?


3个回答

4
不是,因为Git不会进行重命名跟踪...但它会进行重命名检测(基于文件名称和内容的相似程度)。这意味着:
- `git log --follow file2.txt` 将通过重命名跟踪文件历史记录(注意:这不总是正确工作的,因为 `--follow` 是一个小技巧), - `git blame -C -C file2.txt` 将跟随逐行文件历史记录,包括文件重命名、内容复制和移动以及文件内部的移动, - `git show -C` 将显示文件已被重命名(您可以配置Git在显示差异时始终执行重命名,并可选择进行复制检测)。
希望对您有所帮助。

Git 存储这些信息的位置在哪里,还是在您请求时“即兴生成”? - BanksySan
@BanksySan:它是即时生成的。 - Jakub Narębski

2

正如你已经发现的那样,如果同时进行重大更改和移动操作,git不会将其检测为重命名。

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

因此,您需要插入一个新的提交,作为git log等可以检测到的重命名,然后是自那时以来累积的其余历史记录,这意味着您的分支需要一个新的历史记录,即重新定义基础或挑选。

所以:

# 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 

完成啦!除非其他代码库通过fetch、push或克隆获取了错误的历史记录,否则你只需这样就可以了。如果有其他代码库获取了错误的历史记录,你需要强制进行推送或者让那些代码库的所有者强制重新获取(以及他们在其上构建的任何后续历史记录,这就是为什么你真的不想太早发布的原因)。


谢谢,看起来 git mv 实际上并没有做任何事情。 - BanksySan

0

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

跟踪文件重命名而不是删除旧文件并添加新文件的唯一原因是允许合并该文件中的更改。由于您更改了文件(超出重命名检测认为相似的范围),因此无论如何都无法合并更改而不发生冲突,因此应该没有实际区别。

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


还有一个原因,就是为了保留文件的历史记录。新文件没有任何历史记录。 - BanksySan
@BanksySan:一个原因可能是你会问历史记录有什么用。可惜你没有这么说。是的,新文件没有历史记录,其他任何文件也没有。只有整个项目有历史记录。 - Jan Hudec
据我所知,Git已经添加了基于相似度的重命名检测功能,使得自动合并重命名文件成为可能——当一方更改文件而另一方将其重命名时,Git会知道它必须将更改应用于新名称下的文件。@JanHudec - Jakub Narębski
@JanHudec,这解决了一些问题,谢谢。我想这意味着git mv实际上是相当冗余的。它不会改变中央仓库上的任何内容。 - BanksySan
1
@BanksySan:git mv old new 只是 mv old new 的简写,等同于 git rm old ; git add _new_。这样你只需要输入一个命令而不是三个。 - Jan Hudec
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接