更改core.autocrlf后如何强制转换工作树文件? [英] How to force converting worktree files after changing core.autocrlf?

查看:78
本文介绍了更改core.autocrlf后如何强制转换工作树文件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在Windows上,并且具有系统范围的core.autocrlf=true.

I'm on Windows and have systemwide core.autocrlf=true.

对于特定的存储库,我已经在本地将其覆盖为false.

For a specific repository, I've overridden it locally to false.

但是,这并没有转换检出文件中的行尾.我该怎么办?

But that didn't convert line endings in checked-out files. How do I do that?

  • 如果我使用例如手动转换文件dos2unix,它们显示为已更改.
  • 也尝试过git checkout --force HEAD,它没有效果.
  • If I convert the files manually with e.g. dos2unix, they show as altered.
  • Also tried git checkout --force HEAD, it had no effect.

我发现的唯一工作方法是删除所有文件,然后删除git reset --hard,这很尴尬(=没有简单可靠的命令来执行此操作,并且它做了很多不必要的工作-一切都是从从头开始,而不仅仅是覆盖需要转换的文件.

The only working way I have found is to delete all the files, then git reset --hard which is rather awkward (=there's no simple and reliable command to do that, and it does lots of unnecessary work -- everything is recreated from scratch rather than just overwriting the files that need to be converted).

推荐答案

TL; DR

这是三种可能的解决方案(不一定是 only 三种).

  1. 使用:

  1. Use:

git add --renormalize .

(在存储库的顶层完成一次).这需要更新的Git,但这是最简单的方法.

(done in the top level of the repository, once). This requires a newer Git, but is the simplest method.

注意:尚不清楚这是否影响工作树版本;您可能仍然需要git checkout -- .从索引重新复制到工作树.

Note: it's not at all clear to me whether this affects the work-tree versions; you might still need git checkout -- . to re-copy from index to work-tree.

对于git status抱怨的每个文件:rm file; git checkout -- file. rm删除工作树副本,以便git checkout实际上必须根据新的行尾规则重新提取文件.

For each file that git status is complaining about: rm file; git checkout -- file. The rm removes the work-tree copy so that git checkout must actually re-extract the file according to the new line-ending rules.

您可以使用git rm -r .; git checkout HEAD -- .(仅两个命令)在某种程度上简化此操作,但这会产生副作用,即触摸工作树中的所有文件,甚至包括不需要更改的任何文件(不包含回车符的文件)他们).

You can simplify this somewhat with git rm -r .; git checkout HEAD -- . (just two commands) but this has the side effect of touching all the files in the work-tree, even any files with no changes needed (files that have no carriage-returns in them).

像往常一样使用dos2unix,然后在文件(或.)上运行git add.尽管出现了,但这应该使索引保持不变.

Use dos2unix as you have been, then run git add on the files (or on .). Despite appearances, this should leave the index unchanged.

此后,在所有情况下,git status都应显示nothing to commit, working tree clean.

In all cases, afterward, git status should say nothing to commit, working tree clean.

这不是相当 Git的重复:如何在所有修订版的所有文件中重新规范行尾?,因为您不想重新复制一堆现有的提交.但是,在那里的git add --renormalize答案应该起作用.

This is not quite a duplicate of Git: how to renormalize line endings in all files in all revisions?, as you don't want to re-copy a bunch of existing commits. However, the git add --renormalize answer there should work.

如果失败,您可以尝试 PetSerAl的评论答案.

Failing that, you can try PetSerAl's comment answer.

或者,如果失败,或者您的Git太旧而无法使用--renormalize选项:

Or, if that fails or if your Git is too old to have the --renormalize option:

如果我使用例如dos2unix,它们显示为已更改.

If I convert the files manually with e.g. dos2unix, they show as altered.

您可以先手动转换文件,然后再转换git add .,或者删除工作树副本并再次git checkout. git checkout --force HEAD之所以失败,是因为Git为了自身的利益太聪明了:它(错误地)看到工作树副本已经正确,并且避免对其进行工作.

You can convert the files manually, then git add ., or remove the work-tree copies and git checkout them again. The git checkout --force HEAD failed because Git was too smart for its own good: it saw (incorrectly) that the work-tree copy was already correct and avoided doing work on it.

每个文件始终有三个活动副本.假设您有一个README.txt和一个prog.cc,它们在工作树中都有CRLF结尾,而在存储库中只有LF行结尾.

There are, at all times, three active copies of each file. Let's say you have a README.txt and a prog.cc, both of which have CRLF endings in your work-tree, but LF-only line endings in the repository.

   HEAD          index       work-tree
----------    ----------    ----------
README.txt    README.txt    README.txt
prog.cc       prog.cc       prog.cc

提交中的副本以存在的任何形式是神圣不可侵犯的,并且被永久冻结(或只要存在该提交). (我现在假设这些文件中的每个文件都有LF样式的行尾.)它也已压缩.

The copy in the commit is sacrosanct, inviolable, frozen forever (or as long as that commit exists) in whatever form it has there. (I'm assuming for now that each of these files has LF-style line endings.) It's compressed, too.

index 中的副本是可写的,但最初与提交中的副本匹配.因此,它也将具有仅LF的行尾.它也被压缩了(起初它实际上只是对已提交副本的引用).

The copy in the index is writable, but initially matches the copy in the commit. So it will also have LF-only line endings too. It's compressed, too (it's actually just a reference to the committed copy, at first).

工作树中的副本未压缩,并且具有您告诉Git通过.gitattributes文件使用的行尾(无)以及core.autocrlfcore.eol等. .您已经将它们设置为将LF更改为CRLF,因此您的工作树中的副本此刻具有CRLF结尾.

The copy in the work-tree is uncompressed and has the line endings you told Git to use through your .gitattributes file (none) and your core.autocrlf and core.eol and so on. You had them set to change LF to CRLF, so the copies in your work-tree have CRLF endings at the moment.

现在(在结帐后 )-您更改您的设置,这样,被结帐的文件将具有仅LF的行尾,或保留其中的行尾.指数.不幸的是,文件的每个索引副本中的一项是关于工作树副本的信息.这使得Git 假定工作树副本与索引副本相同.

Now—after the checkout—you change your settings, so that files that get checked-out will have LF-only line endings, or will preserve what's in the index. Unfortunately, one of the entries in each index copy of the file is information about the work-tree copy. This makes Git assume that the work-tree copy is the same as the index copy.

很显然,由于工作树副本具有CRLF结尾,而索引副本具有仅LF结尾,因此两者是不同的.但是,如果您没有更改行尾设置,则需要> 否则,因此必须进行此假设.

Clearly, since the work-tree copy has CRLF endings while the index copy has LF-only endings, the two are different. But if you had not changed your end-of-line settings, git status is required to say otherwise, so it has to make this assumption.

如果您没有更改EOL设置,则git status不会说什么,这不会打扰任何人,因为如果您在README.txt上运行git add,则会将工作树副本复制回去进入索引.这样一来,这会将CRLF行尾转换为仅LF行尾,然后重新压缩文件.生成的文件将与HEAD副本匹配,并且git status不必说什么.

If you hadn't changed the EOL settings, git status would say nothing and this would bother no one, because if you ran git add on, say, README.txt, that would copy the work-tree copy back into the index. Along the way this would turn CRLF line endings into LF-only line endings, and re-compress the file. The resulting file would match the HEAD copy, and git status would have to say nothing.

但是您没有更改了EOL设置,因此,如果您现在运行git add,Git应该将CRLF结尾复制到索引中.从本质上讲,git status被愚弄了:索引是故意的-表示工作树副本匹配(即使不匹配),并且在工作树副本具有CRLF行尾的情况下运行git add索引副本.

But you did change the EOL settings, so if you ran git add now, Git should copy the CRLF ending into the index. Essentially, git status has been fooled: the index says—on purpose!—that the work-tree copy matches (even though it doesn't), and running git add while the work-tree copy has CRLF line endings would change the index copy.

如果在文件上使用dos2unix来更改工作树副本,则Git现在会看到工作树副本的统计信息与索引的已保存此文件是干净的"统计信息不匹配.也就是说,git status 仍然被愚弄,但是现在说工作树副本是不同的!如果git add文件 now ,则Git在更新索引副本时将保留仅LF的行尾.最终结果将是索引副本毕竟与HEAD副本匹配, Git更新文件的缓存工作树统计信息关于,以便它知道索引副本与工作树副本匹配.

If you use dos2unix on the file to change the work-tree copy, Git now sees that the work-tree copy's statistics don't match the index's saved "this file is clean" statistics. That is, git status remains fooled but now says that the work-tree copy is different! If you git add the file now, Git will keep the LF-only line endings while updating the index copy. The end result will be that the index copy matches the HEAD copy after all, and that Git updates the cached work-tree statistics about the file so that it knows that the index copy matches the work-tree copy.

本质上,在更改.gitattributes和/或core.*变量中的行尾设置之后,您必须让Git修复索引的干净/脏污"缓存数据.在git add --renormalize之前,唯一的方法就是强制Git从索引复制到工作树:

Essentially, after changing line-ending settings—in .gitattributes and/or core.* variables—you must have Git fix the index's "clean/dirty" cache data. Until git add --renormalize the only way to do that was to force Git to copy from index to work-tree:

rm worktreefile
git checkout -- worktreefile

或强制Git从工作树复制到索引:

or force Git to copy from work-tree to index:

git add worktreefile

这两种方法都可以修复索引的缓存数据,但是显然在此过程中还会产生一些额外的暴力行为.

both of which fix up the index's cache data, but obviously do a bit of additional violence in the process.

假定README.txt的已提交副本具有CRLF结尾.然后,最初:

Suppose that the committed copy of README.txt has CRLF endings. Then, initially:

  • 索引副本照常与HEAD副本匹配,因此具有CRLF结尾;
  • 工作树中的CRLF结尾,所有三个副本都匹配;
  • 但是,如果您在工作树中选择仅LF结尾,并且做到了这一点,那么工作树副本将不同于HEAD和索引.
  • the index copy matches the HEAD copy as usual, so it has CRLF endings;
  • with CRLF endings in the work-tree, all three copies match;
  • but if you select LF-only endings in the work-tree, and make that happen, the work-tree copy differs from both HEAD and index.

这是真的,无论git status是否被欺骗.

This is true regardless of whether git status is fooled.

一旦您将工作树的仅LF行尾复制到索引中,从而使索引也具有仅LF行尾,则 now 索引副本(暂存为提交")与HEAD副本.此时,如果您进行 new 提交,则该提交将仅具有LF行尾,并且您将处于我们先前所述的状态.

Once you copy the work-tree's LF-only line endings into the index such that the index also has LF-only line endings, now the index copy ("staged for commit") differs from the HEAD copy. At this point, if you make a new commit, that commit will have LF-only line endings, and you'll be in the state we described earlier.

这篇关于更改core.autocrlf后如何强制转换工作树文件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆