通常当我在git中重命名/移动文件时,git extensions会在文件暂存后将其显示为重命名操作。像this one这样的其他SO问题表明无论我使用git mv
还是常规移动,这都应该自动发生。但是,我今天进行了大规模的重组,准备git subtree split
(基本上有一个Src
文件夹,我将其分为Core
和Main
,并进行记录我使用Windows资源管理器移动文件夹,而不是git mv
)。当我暂停更改时(只更改了几个项目文件,没有任何源代码),几乎所有更改都显示为添加+删除而不是重命名。我希望这只是Git Extensions中的一个小故障,但是当我推送到github时,它并没有任何问题。你可以看到这里的烂摊子:
https://github.com/qwertie/Loyc/commit/3eb4bd9dbe3d0023858659cb96e860921f0819e3
执行本地git subtree split --prefix=Core -b core
并推送到另一个本地仓库后,Core
文件夹中的所有文件的历史记录都已丢失。
发生了什么事?有没有办法保留所有这些移动文件的历史记录?
> git version
git version 1.8.3.msysgit.0
答案 0 :(得分:2)
鉴于你正在使用Windows,我首先怀疑的是(除了试图阻止它之外的事情并不重要)将换行符转换为CRLF,反之亦然,这样每条线路确实是不同的。我能够克隆URL,当然,还有一些修改过的CRLF:
$ git show HEAD^ | vis | head -40
[snip]
diff --git a/Src/Baadia/ArrowheadControl.cs b/Baadia/ArrowheadControl.cs
similarity index 94%
rename from Src/Baadia/ArrowheadControl.cs
rename to Baadia/ArrowheadControl.cs
index 2e7aa5c..cdb374f 100644
--- a/Src/Baadia/ArrowheadControl.cs
+++ b/Baadia/ArrowheadControl.cs
@@ -1,18 +1,18 @@
-\M-o\M-;\M-?using System;\^M
-using System.Collections.Generic;\^M
-using System.ComponentModel;\^M
[snip]
+\M-o\M-;\M-?using System;
+using System.Collections.Generic;
[snip]
(\ Mo等是一个字节顺序标记,它没有改变。它是删除\ ^ Ms,回车,在每一行的末尾都有git确信它不仅仅是一个简单的重命名。)
编辑:既然已经(有点)跟踪了CR-LF vs LF的来源,你想要“插入”一个只进行去CR的提交......
让我们说(基于我克隆时看到的内容)你有三个提交序列:
... - A - B - C <-- branch
其中A
是具有CRLF的提交,B
是提交,其中所有文件都重命名为,也是CRLF到LF的转换,{{1} }是分支C
的提示。
首先,您要提取提交A,并进入“分离的HEAD”模式。这很简单:
branch
接下来,您要清除所有文件以删除CR,同时保留LF。在类似Unix的盒子上,您可以使用git checkout branch~2 # branch = C, branch~1 = B, branch~2 = A
或其他任何东西,但是假设dos2unix
命令以递归方式zoop
执行:
-R
现在提交结果:
zoop -R . # I'm assuming you're at the top of your work tree
提交图现在看起来像这样:
git commit -am 'CRLF -> LF only' # or whatever message
现在你只想让工作树和索引看起来像commit ... - A - B - C <-- branch
\
A2 <-- HEAD
,我们可以用两个命令来完成:
B
第一个git命令完全清空树和索引,第二个命令从提交git rm -rf .; git checkout branch~1 -- .
重新填充索引和树,即提交branch~1
。 (请注意,这种形式的B
不会更改分支,它只是提取文件。在存储库的顶部,我们提取文件git checkout
,递归提取所有文件。)使用提交结果来自.
的日志消息:
B
,并提供:
git commit -C branch~1
提交... - A - B - C <-- branch
\
A2 - B' <-- HEAD
的树与B'
的树匹配,消息也是如此;只有父ID(和一些时间戳)是不同的。
为提交B
重复步骤 - { - 1}},这次可以命名为B
,而不是C
。
完成所有操作后,将分支branch
移至指向提交branch~1
,由branch
命名:
C'
或:
HEAD
(这不允许您指定自定义消息),然后git update-ref -m "move to rewritten history" refs/heads/branch HEAD
重新开始,将旧提交git branch -f branch HEAD
放弃到reflogs。
(您可以使用git checkout branch
复制提交C
和git cherry-pick
,但这可能会更慢,如果它被CRLF混淆也会失败 - &gt; LF变化。)
当到B
结果时,你将不得不使用强制推送,因为在github上更新C
将不是快进操作(将放弃旧的{{} 1}}和git push
提交)。