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

发布于 2024-08-06 00:59:30 字数 540 浏览 6 评论 0原文

我一直被 git 的 Windows/Linux 行结束问题困扰。通过 GitHub、MSysGit 和其他来源看来,最好的解决方案是将本地存储库设置为使用 Linux 风格的行结尾,但将 core.autocrlf 设置为 true.不幸的是,我没有尽早做到这一点,所以现在每次我进行更改时,行尾都会被破坏。

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

我已经在 Windows 上使用 MSysGit 以及通过 Mac OS X 终端尝试过此操作。

I have been bitten by the Windows/Linux line-ending issue with git. It seems, via GitHub, MSysGit, and other sources, that the best solution is to have your local repos set to use linux-style line endings, but set core.autocrlf to true. Unfortunately, I didn't do this early enough, so now every time I pull changes the line endings are borked.

I thought I had found an answer here but I can't get it to work for me. My Linux command line knowledge is limited at best, so i am not even sure what the "xargs fromdos" line does in his script. I keep getting messages about no such file or directory existing, and when I manage to point it to an existing directory, it tells me I don't have permissions.

I've tried this with MSysGit on Windows and via the Mac OS X terminal.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

緦唸λ蓇 2024-08-13 00:59:30

解决此问题的最简单方法是进行一次提交来修复所有行结尾。假设您没有任何修改的文件,那么您可以按如下方式执行此操作。

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

The easiest way to fix this is to make one commit that fixes all the line endings. Assuming that you don't have any modified files, then you can do this as follows.

# 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 .
花辞树 2024-08-13 00:59:30

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 status 中,
之前取消设置它们的文本属性
运行 git add -u。

手册.pdf-文本

相反,git 处理的文本文件
不检测可以进行归一化
手动启用。

weirdchars.txt 文本

这利用了 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"

The git documentation for gitattributes now documents another approach for "fixing" or normalizing all the line endings in your project. Here's the gist of it:

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

If any files that should not be
normalized show up in git status,
unset their text attribute before
running git add -u.

manual.pdf -text

Conversely, text files that git does
not detect can have normalization
enabled manually.

weirdchars.txt text

This leverages a new --renormalize flag added in git v2.16.0, released Jan 2018.
But it may fail if you have "un-staged deleted files", hence stage those first, like:

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

For older versions of git, there are a few more steps:

$ 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"
一抹淡然 2024-08-13 00:59:30

我处理行结尾的过程如下(在许多存储库上进行过测试):

创建新存储库时:

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

处理现有存储库时:

  • 相应地创建/修改 .gitattributes
  • git commit -a -m“修改的 gitattributes”
  • git rm --cached -r 。 && git reset --hard && git commit -a -m '标准化 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 跟踪的不同扩展名,看这里

规范化后的问题

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

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

解决方案是进行一次假提交(git add -A . && git commit -m 'fake commit'),然后git rebase master。变基后,假提交应该消失。

My procedure for dealing with the line endings is as follows (battle tested on many repos):

When creating a new repo:

  • put .gitattributes in the very first commit along with other typical files as .gitignore and README.md

When dealing with an existing repo:

  • Create / modify .gitattributes accordingly
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n (--no-verify is to skip pre-commit hooks)
    • I have to do it often enough that I defined it as an alias alias fixCRLF="..."
  • repeat the previous command
    • yep, it's voodoo, but generally I have to run the command twice, first time it normalizes some files, second time even more files. Generally it's probably best to repeat until no new commit is created :)
  • go back-and-forth between the old (just before normalization) and new branch a few times. After switching the branch, sometimes git will find even more files that need to be renormalized!

In .gitattributes I declare all text files explicitly as having LF EOL since generally Windows tooling is compatible with LF while non-Windows tooling is not compatible with CRLF (even many nodejs command line tools assume LF and hence can change the EOL in your files).

Contents of .gitattributes

My .gitattributes usually looks like:

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

To figure out what distinct extensions are tracked by git in the current repo, look here

Issues after normalization

Once this is done, there's one more common caveat though.

Say your master is already up-to-date and normalized, and then you checkout outdated-branch. Quite often right after checking out that branch, git marks many files as modified.

The solution is to do a fake commit (git add -A . && git commit -m 'fake commit') and then git rebase master. After the rebase, the fake commit should go away.

池予 2024-08-13 00:59:30
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

说明:

  • git status --short

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

  • grep "^ *M"

    这仅过滤掉那些已被修改的文件。

  • awk '{print $2}'

    这仅显示不带任何标记的文件名。

  • xargs fromdos

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

git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

Explanation:

  • git status --short

    This displays each line that git is and is not aware of. Files that are not under git control are marked at the beginning of the line with a '?'. Files that are modified are marked with an M.

  • grep "^ *M"

    This filters out only those files that have been modified.

  • awk '{print $2}'

    This shows only the filename without any markers.

  • xargs fromdos

    This takes the filenames from the previous command and runs them through the utility 'fromdos' to convert the line-endings.

鹿! 2024-08-13 00:59:30

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

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

Here's how I fixed all line endings in the entire history using git filter-branch. The ^M character needs to be entered using CTRL-V + CTRL-M. I used dos2unix to convert the files since this automatically skips binary files.

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'
满地尘埃落定 2024-08-13 00:59:30

“| 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),您可能会收到权限错误。

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

The "| xargs fromdos" reads from standard input (the files find finds) and uses it as arguments for the command fromdos, which converts the line endings. (Is fromdos standard in those enviroments? I'm used to dos2unix). Note that you can avoid using xargs (especially useful if you have enough files that the argument list is too long for xargs):

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

or

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

I'm not totally sure about your error messages. I successfully tested this method. What program is producing each? What files/directories do you not have permissions for? However, here's a stab at guessing what your it might be:

One easy way to get a 'file not found' error for the script is by using a relative path - use an absolute one. Similarly you could get a permissions error if you haven't made your script executable (chmod +x).

Add comments and I'll try and help you work it out!

木格 2024-08-13 00:59:30

好吧......在 cygwin 下,我们没有容易获得的 fromdos,如果修改文件的路径中有任何空格(我们有),那么 awk substeb 就会在你面前爆炸,所以我必须采取不同的做法:

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

荣誉发送给 @lloyd 以获取此解决方案的大部分内容

okay... under cygwin we don't have fromdos easily available, and that awk substeb blows up in your face if you have any spaces in paths to modified files (which we had), so I had to do that somewhat differently:

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

kudos to @lloyd for the bulk of this solution

栩栩如生 2024-08-13 00:59:30

我在我的一个存储库中遇到了同样的问题。如果您同时使用 Windows 和 Linux 系统进行相同的代码存储库并同时拉取和推送,请尝试以下操作:

首先,针对 Windows 设置 git 配置,如下所示:

git config --global core.autocrlf true

这将确保在写入对象数据库时将 CRLF 转换为 LF,并且然后在写入工作目录时再次将 LF 替换为 CRLF。因此,您的存储库仅使用一种类型的行结尾是安全的,并且在本地,您将在 Windows 系统上拥有 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

希望这可以解决您的问题。

I had the same problem in one of my repos. If you are using both windows and linux systems for the same code repo and pulling and pushing simultaneously, try this:

First, set your git config as follows for windows:

git config --global core.autocrlf true

This will make sure to convert CRLF to LF when writing into the object database and then again replace LF with CRLF when writing out into the working directory. As a result, your repo will be safe with only one type of line endings and locally you'll have windows line ending on the windows system.

For linux/MAC set the git config as follows:

git config --global core.autocrlf input

This will make sure to convert CRLF to LF when writing into the object database but will not do the reverse, preserving LF which is needed for linux/MAC.

For the wrong line endings that are already there on your linux/MAC use dos2unix

For MAC:

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

For Linux:

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

Hope this solves your problem.

狠疯拽 2024-08-13 00:59:30

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

  1. 如果您使用的是 Windows,请执行 git config --global core.autocrlf true;如果您使用的是 Unix,请执行 git config core.autocrlf input
  2. Run git rm --cached -r .
  3. 删除文件 .gitattributes
  4. Run < code>git add -A
  5. 运行 git reset --hard

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

Follow these steps if none of other answers works for you:

  1. If you are on Windows, do git config --global core.autocrlf true; if you are on Unix, do git config core.autocrlf input
  2. Run git rm --cached -r .
  3. Delete the file .gitattributes
  4. Run git add -A
  5. Run git reset --hard

Then your local should be clean now.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文