试图修复行结束与git过滤器分支,但没有运气

我曾被Windows/Linux git的行结束问题所困扰。通过GitHub, MSysGit和其他来源,似乎最好的解决方案是让您的本地回购设置为使用linux风格的行结束符,但将core.autocrlf设置为true。不幸的是,我没有做到这一点足够早,所以现在每次我拉改变线结束是borked。

我以为我已经找到了答案,但我不能让它为我工作。我的Linux命令行知识有限,所以我甚至不确定“xargs fromdos”行在他的脚本中起什么作用。我不断收到关于不存在这样的文件或目录的消息,当我设法将其指向一个现有目录时,它告诉我我没有权限。

我已经在Windows和Mac OS X终端上尝试了MSysGit。

77221 次浏览

"| xargs fromdos"从标准输入(find找到的文件)中读取,并将其用作转换行结束符的命令fromdos的参数。(fromdos在那些环境中是标准的吗?我习惯使用dos2unix)。注意,你可以避免使用xargs(特别是当你有足够多的文件,而参数列表对于xargs来说太长时):

find <path, tests...> -exec fromdos '{}' \;

find <path, tests...> | while read file; do fromdos $file; done

我不是很确定你的错误信息。我成功地测试了这个方法。哪个程序在生成它们?哪些文件/目录您没有权限?不过,下面让我们来猜测一下你的目标是什么:

获取脚本“file not found”错误的一个简单方法是使用相对路径——使用绝对路径。同样,如果你没有让你的脚本可执行(chmod +x),你可能会得到一个权限错误。

添加评论,我会试着帮你解决!

修复这个问题最简单的方法是提交一次,修复所有的行结束符。假设您没有任何修改过的文件,那么您可以按照下面的方法进行操作。

# From the root of your repository remove everything from the index
git rm --cached -r .


# Change the autocrlf setting of the repository (you may want
#  to use true on windows):
git config core.autocrlf input


# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add


# Commit
git commit -m "Fixed crlf issue"


# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .

gitattributes的git文档现在记录了“修复”的另一种方法。或者规范化项目中的所有行结束符。以下是要点:

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

如果任何文件不应该 正常显示在git状态, 之前不设置它们的文本属性 运行git add -u.

manual.pdf -text

相反,git所做的文本文件 未检测可有归一化 手动启用。< / p >

weirdchars.txt text

这利用了在2018年1月发布的git v2.16.0中添加的新--renormalize标志。
但如果你有“未分阶段删除的文件”,它可能会失败,因此先执行那些文件,如:

git ls-files -z --deleted | xargs -0 git add

对于旧版本的git,有更多的步骤:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

解释:

  • < p > git status --short

    这将显示git知道和不知道的每一行。不在git控制下的文件在行首用'?'标记。被修改的文件用m标记

  • < p > grep "^ *M"

    .

    .

    .
  • < p > awk '{print $2}'

    这只显示没有任何标记的文件名

  • < p > xargs fromdos

    这将从前面的命令中获取文件名,并通过实用程序'fromdos'运行它们来转换行结束符

好吧……在cygwin下,我们不容易使用fromdos,如果你在修改文件的路径中有任何空格(我们已经有了),那么awk substeb就会在你的面前爆炸,所以我不得不做一些不同的事情:

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

向@lloyd的大量解决方案致敬

如果以上答案都对你不起作用,请按照以下步骤进行:

  1. 如果你在Windows上,执行git config --global core.autocrlf true;如果你在Unix上,执行git config core.autocrlf input
  2. 运行git rm --cached -r .
  3. 删除文件.gitattributes
  4. 运行git add -A
  5. 运行git reset --hard

那你的地盘现在应该干净了。

下面是我如何使用git filter-branch在整个历史中固定所有的行结束符。^M字符需要使用CTRL-V + CTRL-M输入。我使用dos2unix来转换文件,因为这会自动跳过二进制文件。

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'

我处理行尾的程序如下(在多次回购中进行了战斗测试):

当创建一个新的repo时:

  • .gitattributes与其他典型文件.gitignoreREADME.md一起放在第一次提交中

在处理现有的回购时:

  • 相应地创建/修改.gitattributes
  • git commit -a -m "Modified gitattributes"
  • <李> git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n (--no-verify是跳过预提交钩子)
    • 我必须经常这样做,所以我将它定义为别名alias fixCRLF="..."
    • 李< / ul > < / >
    • 重复以上命令
      • 是的,这是巫术,但通常我必须运行两次命令,第一次它正常化一些文件,第二次甚至更多的文件。通常情况下,最好重复这个操作,直到没有新的提交被创建:)
      • 李< / ul > < / >
      • 在旧分支(在规范化之前)和新分支之间来回切换几次。切换分支后,有时git会发现更多需要重新规范化的文件!

      .gitattributes中,我显式地声明所有文本文件具有LF EOL 因为通常Windows工具与LF兼容,而非Windows工具与CRLF不兼容(甚至许多nodejs命令行工具都假设LF,因此可以更改文件中的EOL)。

      .gitattributes的内容

      我的.gitattributes通常看起来像:

      *.html eol=lf
      *.js   eol=lf
      *.json eol=lf
      *.less eol=lf
      *.md   eol=lf
      *.svg  eol=lf
      *.xml  eol=lf
      

      要弄清楚当前repo中git跟踪哪些不同的扩展,看这里

      正常化后的问题

      一旦完成,还有一个更常见的警告。

      假设你的master已经是最新的和标准化的,然后你签出outdated-branch。通常在签出分支之后,git会将许多文件标记为已修改。

      解决方案是做一个假提交(git add -A . && git commit -m 'fake commit'),然后git rebase master。在rebase之后,假提交应该会消失。

我在一次回购中也遇到了同样的问题。如果你同时使用windows和linux系统进行相同的代码repo和pull和push,试试这个:

首先,设置你的git配置如下:

git config --global core.autocrlf true

这将确保在写入对象数据库时将CRLF转换为LF,然后在写入工作目录时再次将LF替换为CRLF。因此,你的回购将是安全的,只有一种类型的行结束,在本地你将有窗口行结束在windows系统。

对于linux/MAC, git配置如下:

git config --global core.autocrlf input

这将确保在写入对象数据库时将CRLF转换为LF,但将做相反的事情,保留linux/MAC所需的LF。

对于在linux/MAC上已经存在的错误行尾,请使用dos2unix

MAC:

brew install dos2unix # Installs dos2unix Mac
find . -type f -exec dos2unix {} \; # recursively removes windows related stuff

Linux:

sudo apt-get install -y dos2unix # Installs dos2unix Linux
sudo find . -type f -exec dos2unix {} \; # recursively removes windows related stuff

希望这能解决你的问题。