尝试使用 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
与其他典型文件一起放入第一个提交中,如.gitignore
和README.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="..."
重复上一个命令
是的,它是巫术,但通常我必须运行该命令两次,第一次规范化一些文件,第二次甚至更多文件。一般来说,最好重复一次,直到没有创建新的提交:)
在旧分支(就在规范化之前)和新分支之间来回切换几次。切换分支后,有时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 . && git commit -m 'fake commit'
),然后再进行 git rebase master
。在 rebase 之后,虚假提交应该会消失。
【讨论】:
我以为我快疯了,直到我读了你的帖子,因为我也必须多次运行指定的命令序列。巫毒! ;) 使用 git 版本2.7.0.windows.1
,我使用了以下内容:git rm --cached -r . && git reset --hard && git add . && git commit -m "Normalize EOL" -n
以上是关于尝试使用 git filter-branch 修复行尾,但没有运气的主要内容,如果未能解决你的问题,请参考以下文章
在 filter-branch --tree-filter 之后从 git repo 中删除 refs/original/heads/master?