尝试使用 git filter-branch 修复行尾,但没有运气

Posted

技术标签:

【中文标题】尝试使用 git filter-branch 修复行尾,但没有运气【英文标题】:Trying to fix line-endings with git filter-branch, but having no luck 【发布时间】:2010-12-03 09:44:38 【问题描述】:

我被 git 的 Windows/Linux 行尾问题所困扰。看来,通过 GitHub、MSysGit 和其他来源,最好的解决方案是将本地存储库设置为使用 linux 样式的行尾,但将 core.autocrlf 设置为 true。不幸的是,我没有足够早地这样做,所以现在每次我拉变化时,行尾都是无聊的。

我以为我找到了答案here,但我无法让它为我工作。我的 Linux 命令行知识充其量是有限的,所以我什至不确定“xargs fromdos”行在他的脚本中做了什么。我不断收到有关不存在此类文件或目录的消息,当我设法将其指向现有目录时,它告诉我我没有权限。

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

【问题讨论】:

我对这个帖子的投票还不够。 +1 ++,因为它提供了关于此事的最佳答案。 同意查尔斯。但是,在我的情况下(使用 Mac OS X 10.8)> git config core.autocrlf false 工作,而不是> git config core.autocrlf input 【参考方案1】:

“| xargs fromdos”从标准输入(find 找到的文件)读取,并将其用作命令fromdos 的参数,该命令转换行尾。 (这些环境中的 fromdos 标准吗?我习惯于 dos2unix)。请注意,您可以避免使用 xargs(如果您有足够的文件而参数列表对于 xargs 来说太长,则特别有用):

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

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

我不完全确定您的错误消息。我成功地测试了这个方法。每个程序都在生产什么程序?您没有权限访问哪些文件/目录?然而,这里是猜测你可能是什么的尝试:

为脚本获取“找不到文件”错误的一种简单方法是使用相对路径 - 使用绝对路径。同样,如果您没有使脚本可执行(chmod +x),您可能会收到权限错误。

添加 cmets,我会尽力帮助您解决问题!

【讨论】:

我看到了另一个使用 dos2unix 的示例,我认为这是以某种方式将文件复制到名为该文件夹的文件夹中,但现在我明白了。哇,现在看起来很明显。感谢您的帮助!【参考方案2】:

解决此问题的最简单方法是进行一次修复所有行结尾的提交。假设您没有任何修改过的文件,那么您可以这样做。

# 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 .

【讨论】:

P.S.我向 github.com 上的人推荐了您的修复程序,他们更新了他们的帮助指南以使用您的解决方案(以前它刚刚推荐了一个新的克隆和一个硬重置,这似乎没有得到所有文件。)help.github.com/dealing-with-lineendings跨度> 谢谢...这是一个很好的修复。在 GitHub 上找到它。 您可能还需要检查 config.safecrlf 以确保您不会更改非文本文件(例如二进制文件)中的 crlfs。查看文档kernel.org/pub/software/scm/git/docs/git-config.html @vrish88:但是,如果您处于这种情况,您可能会遇到混合衬里结尾的问题,并且 core.safecrlf 实际上可能会阻止您做您需要做的事情。不使用 safecrlf 可能更容易。 git 不会经常检测到二进制文件错误,如果出现这种情况,您可以使用 .gitattribute 手动将其标记为二进制文件,并从上一次提交中恢复正确的版本。 下面Russ Egan's 回答中推荐的较新的解决方案更简单,并且不涉及诸如删除所有源代码之类的可怕事情,所以我真的建议人们使用它,即使虽然这个旧解决方案的票数是原来的 10 倍!【参考方案3】:

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 处理的文本文件 不检测可以有归一化 手动启用。

weirdchars.txt text

这利用了 2018 年 1 月发布的 git v2.16.0 中添加的新 --renormalize 标志。对于旧版本的 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 reset 的用途是什么? 强制 git 重建索引,在此期间它扫描每个文件以猜测其是否为二进制文件。 rm 删除旧索引,reset 建立新索引。 谢谢,这对我有用。运行git status 后的一个有用命令是运行git diff --ignore-space-at-eol,以确保您提交的唯一更改是行尾。 注意:此解决方案与“旧”解决方案之间的唯一“真正”区别在于存在 .gitattributes(具有适当的内容)。没有这个,git reset 将检测不到任何修改,因此毫无用处。 gitattributes 页面上的说明已更新,以利用 2018 年 1 月发布的 git v2.16.0 中添加的 --renormalize 标志。--renormalize 标志整合了将每个跟踪文件的行尾重新处理为单个命令:git add --renormalize .【参考方案4】:
git status --short|grep "^ *M"|awk 'print $2'|xargs fromdos

解释:

git status --short

这会显示 git 知道和不知道的每一行。不受 git 控制的文件在行首标有“?”。被修改的文件用 M 标记。

grep "^ *M"

这只会过滤掉那些被修改过的文件。

awk 'print $2'

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

xargs fromdos

这会从上一个命令中获取文件名,并通过实用程序“fromdos”运行它们以转换行尾。

【讨论】:

这太棒了。谢谢你。对于使用 Homebrew 寻找解决方案的任何人,请使用 dos2unix 而不是 fromdos【参考方案5】:

好的...在 cygwin 下,我们没有容易获得的 fromdos,如果您在修改文件的路径中有任何空格(我们有),那么 awk substeb 就会在您的脸上爆炸,所以我不得不这样做不同:

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

感谢 @lloyd 提供的大部分解决方案

【讨论】:

【参考方案6】:

如果其他答案都不适合您,请按照以下步骤操作:

    如果您使用的是 Windows,请执行 git config --global core.autocrlf true;如果您在 Unix 上,请执行 git config core.autocrlf input 运行git rm --cached -r . 删除文件.gitattributes 运行git add -A 运行git reset --hard

那么你的本地现在应该是干净的了。

【讨论】:

真的吗?删除.gitattributes文件是解决行尾问题的方法吗? 是的,请解决@AleksandrM 的评论【参考方案7】:

以下是我使用git filter-branch 修复整个历史记录中所有行尾的方法。 ^M 字符需要使用CTRL-V + CTRL-M 输入。我使用dos2unix 转换文件,因为这会自动跳过二进制文件。

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

【讨论】:

superuser.com/questions/293941/…gist.github.com/richfitz/72ac6cd41c2b531a89f1【参考方案8】:

我处理行尾的过程如下(在许多 repos 上测试过):

创建新仓库时:

.gitattributes 与其他典型文件一起放入第一个提交中,如.gitignoreREADME.md

处理现有仓库时:

相应地创建/修改.gitattributes git commit -a -m "Modified gitattributes" git rm --cached -r . &amp;&amp; git reset --hard &amp;&amp; git commit -a -m 'Normalize CRLF' -n" -n--no-verify 是跳过预提交挂钩) 我必须经常这样做,我将其定义为别名alias fixCRLF="..." 重复上一个命令 是的,它是巫术,但通常我必须运行该命令两次,第一次规范化一些文件,第二次甚至更多文件。一般来说,最好重复一次,直到没有创建新的提交:) 在旧分支(就在规范化之前)和新分支之间来回切换几次。切换分支后,有时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

要弄清楚当前仓库中 git 跟踪了哪些不同的扩展,look here

标准化后的问题

完成此操作后,还有一个更常见的警告。

假设您的master 已经是最新的并已标准化,然后您结帐outdated-branch。很多时候,在签出该分支之后,git 会将许多文件标记为已修改。

解决方案是先进行虚假提交 (git add -A . &amp;&amp; git commit -m 'fake commit'),然后再进行 git rebase master。在 rebase 之后,虚假提交应该会消失。

【讨论】:

我以为我快疯了,直到我读了你的帖子,因为我也必须多次运行指定的命令序列。巫毒! ;) 使用 git 版本 2.7.0.windows.1,我使用了以下内容:git rm --cached -r . &amp;&amp; git reset --hard &amp;&amp; git add . &amp;&amp; git commit -m "Normalize EOL" -n

以上是关于尝试使用 git filter-branch 修复行尾,但没有运气的主要内容,如果未能解决你的问题,请参考以下文章

text Git filter-branch

git filter-branch应用

核弹级的git指令 git filter-branch

在 filter-branch --tree-filter 之后从 git repo 中删除 refs/original/heads/master?

在 git 中提交消息前缀

从 Git 历史记录中删除大文件