.gitattributes 正确使用姿势
这篇文章的由来是因为项目上的一个神奇问题,之前觉得写重复的创建项目太繁琐就封装了一个创建模板文件 CLI ,当时心想自己真是一个上进的小伙子。
后来某天 xx 领导对我说有一个新项目交给我做,当时心想终于可以大展拳脚试试新的工具了,一顿操作后项目完成了,不过在推送 GitLab 时发现图片竟然无法预览。why?后面根据 git log 记录一个个回滚和但是这也无法复现 entire,后面又对项目文件屏蔽检查终于发现原来是 .gitattributes 文件填写问题。
之前.gitattributes 写法
* text eol=lf
那是不是直接删除 .gitattributes 文件就可以了呢?如果只考虑解决图片提交格式损坏当时是没问题。
.gitattributes 作用
不过回到标题,当时之所以在模板文件中添加 .gitattributes 主要是有两个目的:
- 确保文件行尾序列符合一致,在 windows 下行尾序列为 CRLF 而在 mac 和 linux 则是 LF。行尾序列不同在某些 Eslint 规则下会显示报错,这是为了规范你的代码。
- 避免 git 提交记录莫名差异,例如从仓库下拉取了一个项目,更改了一个某一个文件的内容发现不对又撤销了,但是因为系统不同行尾序列已经发生了变更,git 会显示这个文件的差异。
以上操作是假设仓库的文件是 LF 格式,且你是 windows 电脑下操作
如何编写.gitattributes 文件
按照开头我最初的写法肯定是错误的
* text eol=lf
这里会把代码的所有文件都 LF 化,对于文本文件是没问题的,但是对于一些图片文件、pdf 等二进制文件就会导致额外的问题。
这里参考两个库的写法 v8 .gitattributes
# Automatically normalize line endings (to LF) for all text-based files.
* text=auto eol=lf
# Do not modify line endings for binary files (which are sometimes auto
# detected as text files by git).
*.png binary
# Don't include minified JS in git grep/diff output
test/mjsunit/asm/sqlite3/*.js -diff
上面会把所有的文件都 LF 化,不同的是单独为需要的资源添加了 binary,而翻阅 git 官方 gitattributes 文档 可以看到
如果你不希望产生文本差异,以及行尾转换应用到任何二进制文件。可以使用系统内置的 binary,它会取消 text 和 diff 属性。
而第三行 test/mjsunit/asm/sqlite3/*.js -diff
则是说不要跟踪 diff 差异。
再来看一个 pdf .gitattributes
# Force Unix line endings for most file formats (except binary files)
*.js text eol=lf
*.jsm text eol=lf
*.css text eol=lf
*.html text eol=lf
*.md text eol=lf
*.properties text eol=lf
*.yml text eol=lf
*.json text eol=lf
*.config text eol=lf
*.inc text eol=lf
*.manifest text eol=lf
*.rdf text eol=lf
*.jade text eol=lf
*.coffee text eol=lf
# PDF files shall not modify CRLF line endings
*.pdf -crlf
# Linguist language overrides
*.js linguist-language=JavaScript
*.jsm linguist-language=JavaScript
*.inc linguist-language=XML
它将资源前置化处理,需要的文件全部 LF 处理,而 *.pdf -crlf
则是说强制 crlf 处理,下面的 linguist-language
是 Linguist 库的属性,它用于生成我们常见的语言分布
综合上面两个库来看,有两种编写 .gitattributes 的方式
前置后添加
这就是 pdf.js 所采用的,将需要用的序列化,例如如果你是 React 项目,只可能只需要这样指定
*.js text eol=lf
*.jsm text eol=lf
*.jsx text eol=lf
*.ts text eol=lf
*.tsx text eol=lf
*.json text eol=lf
*.css text eol=lf
*.html text eol=lf
后面如果还有新的需要行尾序列的后缀可以继续添加
全局后添加
这是 V8 的做法,假定所有资源都是文本相关,如果后续有新的二进制文件再对 .gitattributes 文件进行编辑。
* text eol=lf
# 如果有新的二进制文件
* png eol=binary
迁移指南
如果你的项目已经存在很久,但是也想添加 .gitattributes 文件来统一行尾序列,下面就介绍一下相关方法。
- 添加相关的 .gitattributes 文件到项目(详情见如何编写.gitattributes 文件
- 运行
git add .
添加所有文件 - 运行
git commit -m "Saving files before refreshing line endings"
来保存本次更改 - 删除所有文件,不包括 .git 目录,
git rm -rf --cached .
- 运行
git reset --hard HEAD
,恢复上一次的提交,这里会得到正确的行尾序列
兼容指南
如果你发现 monorepo 项目中还是没有得到正确的行尾序列,可以参考一下下面 .gitattributes 的写法
* text=auto
# Force the following filetypes to have unix eols, so Windows does not break them
*.* text eol=lf
# Windows forced line-endings
/.idea/* text eol=crlf
#
## These files are binary and should be left untouched
#
# (binary is a macro for -text -diff)
*.png binary
添加了兼容性的写法,强制在 window 下 lf 化
最后
如果文章有相关错误欢迎指出
参考了