重写git历史记录以将所有CRLF替换为LF?


32

我将要将私有的Git存储库从Win32 Box转移到Ubuntu。尽管我可以进行最后的dos2unix提交,但是我想重写整个历史记录,因此某些Git GUI将正确显示log / diff。例如,gitg将为每个CR / LF插入空行。

Answers:


25

您可以使用git filter-branch--tree-filter选项,并为该选项指定--all分支。

这是一个示例(从带有Unix类型文本文件的空目录开始:

制备:

$ hexdump -C testfile 
00000000  61 0d 0a 62 0d 0a 63 0d  0a                       |a..b..c..|
00000009

$ git init
Initialized empty Git repository in /home/seigneur/tmp/a/.git/

$ git add testfile && git commit -m "dos file checked in"
[master (root-commit) df4970f] dos file checked in
 1 files changed, 3 insertions(+), 0 deletions(-)
 create mode 100644 testfile

命令:

$ git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all

输出:

Rewrite df4970f63e3196216d5986463f239e51eebb4014 (1/1)dos2unix: converting file testfile to Unix format ...

Ref 'refs/heads/master' was rewritten

$ hexdump -C testfile 
00000000  61 0a 62 0a 63 0a                                 |a.b.c.|
00000006

强烈建议事先进行完整备份。从Linux机器上运行该程序(除非您在Windows环境中设置了一个好的shell)可能会更容易。

编辑:第一次时转换已逆转。


1
谢谢,这篇文章对我有很大帮助。我有几个文件名中带有空格的文件,对原始命令进行了一些改动以解决该问题:git filter-branch --tree-filter 'git ls-files -z | xargs -0 dos2unix' -- --all。标志-z-0告诉git ls-filesxargs打印和解释null为行尾。
伊万

dos2unix命令的另一种替代方法是依靠git本身:git filter-branch --prune-empty --tree-filter 'git add --renormalize .' -- --all
Vilmantas Baranauskas

6

Mat的回答已将问题直接放在了头上。不幸的是,在Ubuntu Linux上,从版本10.04(Lucid Lynx)开始,dos2unix / unix2dos命令不再可用,并已由fromdos / todos代替。此外,这两组转换命令对二进制文件的存在都有不同程度的了解,因此,如果您的存储库中包含图像,字体等,它们将被此过程破坏。

我能够找到一种解决二进制文件损坏问题的方法,该问题使用Linux的“文件”命令正确地识别和处理仅文本文件,如下所示。下面的命令使用--tag-name-filter选项通过将现有标签移动到新修订的提交中来保留它们。它还使用--force标志来确保该命令在以前在存储库上运行tree-filter的情况下也能使用。

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs fromdos' --tag-name-filter cat -- --all

3

而且没有任何其他工具(例如“ fromdos”,“ dos2unix”等):

git filter-branch --force --tree-filter 'git ls-files | xargs file | sed -n -e "/.*: .*text.*/s/\(.*\): .*/\1/p" | xargs -0 sed -i"" -e "s/"$(printf "\015")"$//"' --tag-name-filter cat -- --all

跨平台(OS X,FreeBSD,Linux)有用的模拟“ fromdos”,“ dos2unix”:

sed -i'' -e 's/'"$(printf '\015')"'$//'

也许有用的“ unix2dos”:

sed -i '' -e 's|$|'"`printf '\015'`"'|' file.name

如果您绝对不知道正在做什么,则可以使用以下简单的内联命令从当前目录“。”中的所有文件中删除“ / r”:

find . -type f -exec sed -i'' -e 's/'"$(printf '\015')"'$//' {} \;

1
而是将\ r \ n更改为\ n而不是仅删除\ r
xdevs23

我认为对应 sed调用可以替换为较短的调用:sed -n -e "s/\(.*\): .*text.*/\1/p"
dma_k
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.