如何使更改 .gitattributes 生效

36

我正在处理一个项目,我们最近开始使用git。从一开始设置并不完美,所以在人们开始克隆/工作后,我设置了.gitattributes文件,并且仍在对该文件进行一些更改。

考虑以下设置...

Alice和Bob都已经克隆了"repo.git",并且该存储库包含文件/myproj/src/file.ending,行尾使用\n作为换行符,即该文件不包含\r字符。

他们也都有.gitattributes文件,具有以下设置:

/myproj/src/file.ending -text
这告诉 git file.ending 不应被视为文本文件,因此不应进行换行符转换。
因此,Alice 和 Bob 工作树中的文件也都使用 \n 作为行结尾符。
现在,Alice 对 .gitattributes 进行以下更改:
/myproj/src/file.ending text

Alice希望这个变化能够生效,对她和Bob都有好处。

目前我所知道的唯一方法相当具有干扰性:

git rm --cached -r .
git reset --hard

我希望避免两件事情:

  • 艾丽斯必须提交她的`.gitattributes`文件,才能真正测试它(上面的重置操作将覆盖她的更改)。
  • 鲍勃必须清除他的索引和工作目录以获取更新。鲍勃不高兴。

那么,哪种方法是首选?


@PetSerAl - 这不是 git 检测变化的方式。 - Mark Adelsberger
1
@MarkAdelsberger - 单单使用git checkout是不够的。 - jgreen81
Git会在索引中缓存状态信息。当索引中缓存的状态信息与工作目录中的状态信息匹配时,Git会假设该文件未更改。即使.gitattributes以某种方式更改,你现在需要使用不同的策略过滤器(例如行末转换),Git也是这样假设的。 - user4003407
@MarkAdelsberger,你没有说/问是否仅结帐就足够了。我搞砸了你的名称标签。抱歉。 - jgreen81
我对git还很陌生,所以我刚学习了有关smudge和clean过滤器的知识。有没有人能指导我一些详细的资源呢?例如,要更改过滤器以运行需要改变什么?Git要如何注册“更改”等?在这种情况下,我不知道时间戳的东西。 - jgreen81
显示剩余10条评论
5个回答

24

如果我理解正确,你不需要进行硬重置。

我的情况类似。我在运行中的项目中添加了一个“.gitattributes”文件。我需要让我拥有的文件和在线存储库中的文件都受gitattr控制。

# This will force git to recheck and "reapply" gitattributes changes.
git rm --cached -r .
git add -A

您的提交将重新添加您提到的所有.ending文件,并且您不会失去任何可能的更改。当然,Bob需要拉取以获取它。


12
这有一个严重的问题。它会添加未版本化且不应存在的文件。 - Jan Hudec
2
确实,这个解决方案必须有一个巨大的警告。对于任何中大型代码库来说,这绝对不是一个好的做法。 - Leonid Usov
实际上,对我来说,问题中提到的解决方案效果更好。在执行此操作后,git会转换行尾。然而,所有的文件都会显示为已更改。相比之下,git reset --hardgit add -A效果更好。 - undefined

9

osseirc://chat.freenode.net/#git 给了我这个方法,而它运行得相当不错:

git rm -r :/ && git checkout HEAD -- :/

如果您的代码库中存在未提交的更改,这将会发出警告。

不过,似乎还应该有更好的方法。


2
这个答案在Windows Powershell上不起作用,因为它没有&&参考)。在Powershell上,请使用git rm -r :/; git checkout HEAD -- :/ - Jason R. Coombs
一个(大)改进是仅将 git rm 应用于受 .gitattributes 更改影响的文件。 在这种情况下,是 *.ending。 因此:find . -iname "*.ending" | xargs -n 1 git rm(也许不需要 -n 1,但它为每个输入行提供输出行,并且不会触及未知于 git 的文件)。 - Matt Chambers

6
“would like this change to take effect” 是指Alice希望她和Bob的工作副本都切换到Windows风格的行结尾吗?那么第一个问题是,为什么Alice要对Bob的工作树负责呢?
如果新属性更好地描述了该文件,则可以编辑 .gitattributes 文件,并像其他文件一样进行测试和提交。
你建议采取的步骤对于两个原因都不太合理:
首先,为什么要清除索引? 文本属性影响索引和工作副本之间的关系。 在您的示例中,似乎需要更改的是工作副本,而不是索引。
其次,为什么要从索引中删除所有内容? 只需要处理属性发生更改的路径即可。
因此,在您的示例中,如果Alice想在本地反映新属性,最多只需要进行以下操作:
rm myproj/src/file.ending
git checkout -- myproj/src/file.ending

由于此过程不会覆盖.gitattributes文件,因此没有必要过早提交它。
我不清楚什么让Bob对您的原始程序感到不满意,因此我不知道这个更改是否会让他更加满意。也许他只是希望更新在拉取时自动进行;虽然这并不是不合理的期望,但我不确定git是否能够实现。
问题在于如何检测更改。在几乎每种情况下,如果git在合并或快进(例如完成拉取)结束时更新工作树,它只需要比较旧提交和新提交的索引对象的哈希值即可判断是否有更改要应用。
例外情况是属性(或过滤器定义)更改-如上所述,这不会更改索引。但是这些条件相对较少,并且为它们检查的成本比几乎每次都正确的哈希检查昂贵得多,因此,与其使每个比较都负担大部分毫无意义的成本,不如允许在您知道已做某些事情时,您必须采取额外的措施。
因此,如果这将发生一次,请让团队进行沟通。 “此路径的属性正在更改;您可能需要刷新受影响文件的工作副本。”
如果这将不停地发生,我最好的建议是找出为什么会一直发生并加以修复。您可以尝试设置某种脚本化自动化,甚至使用钩子来检测和处理属性更改;但这是很多复杂性,并且可能会引起比它修复的问题还要多的麻烦。

2
关于Alice和Bob之间的同步,我不明白你在想什么,为什么Bob想要这些更改。正如你所说,.gitattributes的更改更好地描述了文件,因此Bob想要利用这个描述。我正在清除整个索引,因为使用一个特定的文件只是一个例子。似乎仅使用rm(而不是git rm)也很有用。所以你可以使用它。我之前不知道。正如我在原始文本的评论中所述,“touch”也似乎有效,并且可能被认为是不太侵入性的。 - jgreen81
@eversceptic - 这不是关于Bob是否想要更改的问题,而是关于谁决定Bob是否想要更改的问题。如果我更改文件属性,那么决定你的工作树是否需要更改并不取决于我,而是取决于你。(例如,Bob可能在Mac或Unix系统上运行,在这种情况下,更改甚至不会影响他的工作树。)Alice所需要做的就是确保Bob知道属性已经更改;让她“希望更改对Bob生效”是一个糟糕的要求。 - Mark Adelsberger
@eversceptic - 如果你更喜欢使用 touch 而不是 rm,那就用 touch 吧。我会继续使用 rm。当命令的目的是从索引中覆盖文件时,两者都不是“较少侵入性”的选择。 - Mark Adelsberger
关于Alice和Bob的关系,我理解你的观点 :) 在我们的情况下,我们遇到了一些问题,影响了同事们,这是解决这些问题的方法。说Bob想要修复程序比说Alice想给Bob修复程序更准确。 - jgreen81
提醒:由于某些原因,我无法在这些评论中标记马克。但是我可以在我的原始帖子的评论中进行标记。 - jgreen81
显示剩余5条评论

2

在你提交了 .gitattributes 的更改之后,运行以下命令来应用这些更改

git rm --cached -r .
git reset --hard

那正是我说的,他不想这样做,因为这太过于侵入性了。 - undefined

0
为了使更改生效,您需要某种类型的git服务器,例如Gitlab。将存储库推送到Gitlab,然后创建一个新文件夹,进入您创建的新文件夹,然后通过克隆存储库将其克隆到其中。
git clone <repository> .

然后更改应该被正确应用。 这样你就可以避免你提到的相当侵入性的其他选项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接