一、.gitattributes 概念与总体作用#
1. .gitattributes 是什么#
- .gitattributes 是 Git 仓库中的一个配置文件,用来“按文件路径匹配”控制 Git 对这些文件的各种行为。
- 它可以存在于:
- 仓库根目录(最常见)
- 任意子目录(子目录中的 .gitattributes 会叠加/覆盖上层目录的规则)
- 在克隆仓库时,.gitattributes 作为普通文件一起被拉取,因此所有协作者都会拿到同样的“文件行为规则”。
2. .gitattributes 大致控制哪些行为#
主要控制这些:
- 文本/二进制识别
- 告诉 Git 某些文件是文本还是二进制(影响 diff、merge、换行处理等)
- 换行符(CRLF/LF)与文本规范
- 控制工作区里的换行符(eol=lf, eol=crlf)
- 控制提交到仓库里的换行处理策略(text, text=auto)
- diff 行为
- 是否对某些文件做文本 diff(还是视为二进制)
- 是否使用自定义 diff 驱动(diff=NAME)
- merge 行为
- 是否对某些文件使用特殊合并策略(merge=NAME)
- filter(清洗/还原过滤器)
- 使用 clean/smudge 过滤器在工作区与仓库存储之间双向转换内容
- Git LFS 就是基于 filter 机制实现的
- 导出行为(git archive)
- export-ignore:打包/发布归档时忽略哪些文件
- export-subst:打包时做占位符替换(如 $Id$)
3. 与 .gitignore、.gitconfig 的区别#
- .gitignore
- 用来告诉 Git 哪些文件“不参与版本控制”(不加入 index)
- 不影响已经被跟踪的文件的行为
- 不控制 diff/merge/换行等
- .gitattributes
- 作用于“已被 Git 跟踪或将要跟踪的文件”
- 控制这些文件的 diff、merge、换行、filter 等行为
- .gitconfig
- Git 配置文件,分系统级、用户级、仓库级
- 配置用户信息、别名、全局 diff/merge 驱动等
- 某些配置(比如 diff 驱动、filter)在 .gitconfig 定义,在 .gitattributes 按路径引用
一句话区分:
- .gitignore = 哪些文件不进 Git
- .gitattributes = 进了 Git 的文件要怎么被处理
- .gitconfig = Git 的行为默认设置和扩展组件定义(diff/merge/filter 名称等)
二、语法与匹配规则基础#
1. 模式匹配规则#
- 跟 .gitignore 很像(但不是百分百相同),常用:
*.txt:匹配所有 .txt 文件docs/**:匹配 docs 目录及其子目录下的所有内容path/file.ext:精确文件路径subdir/*.js:匹配指定目录下的 js 文件
- 重要区别(常见误区):
- .gitignore 支持前缀
!用来“反选忽略”,.gitattributes 不需要这个行为(它是叠加属性)。 - .gitattributes 更像“最后匹配优先”:同一文件被多条规则匹配时,后面的规则会覆盖前面的同名属性。
- .gitignore 支持前缀
2. 属性标记方式#
一条规则一般长这样:
pattern attrpattern -attrpattern attr=value
含义:
attr:开启/设置该属性为“true”。比如text表示此匹配的文件被当作文本处理。-attr:显式关闭该属性。比如-text告诉 Git“不要当作文本”,通常意味着视为二进制。attr=value:设置属性具体值。比如eol=lf、diff=markdown、filter=lfs。
3. 一个最简单示例#
假设仓库根目录有一个 .gitattributes:
# 所有文本文件统一做换行规范
*.txt text eol=lf
# 所有 PNG 图片标记为二进制
*.png -text
# Markdown 使用自定义 diff 驱动
*.md text diff=markdown逐行说明:
*.txt text eol=lf- 匹配所有 .txt 文件
- text:告诉 Git 这些是文本(提交时可以按文本规则处理)
- eol=lf:工作区中的换行统一为 LF(仓库内部实际会标准化处理)
*.png -text- 匹配所有 .png
- -text:明确标记为非文本(视为二进制)
- Git 不会对它做换行转换,diff 和 merge 会当作二进制处理
*.md text diff=markdown- 匹配所有 .md
- text:文本文件
- diff=markdown:使用名为 markdown 的 diff 驱动(具体行为在 .gitconfig 里配置)
三、常用属性分类详解(非 LFS 场景)#
3.1 文本与换行符相关属性#
1)text、-text、text=auto
- text
- 把文件当作文本处理
- Git 在提交到仓库时会做一定的换行规范化(结合 core.autocrlf 等)
- -text
- 禁用文本处理,通常意味着当作二进制
- 不做换行转换,不做文本 diff(除非另有 diff 属性)
- text=auto
- 让 Git 自动根据内容判断(启发式)文件是不是文本
- 类似
core.autocrlf默认处理方式,但显式写在仓库中,所有人一致 - 推荐在跨平台项目中使用
2)eol=lf / eol=crlf
- eol=lf
- 工作区中使用 LF 换行(Unix 风格)
- eol=crlf
- 工作区中使用 CRLF 换行(Windows 风格)
- 注意:eol 控制的是“工作区”换行形式,仓库内部通常会被规范化为一种一致的格式(一般是 LF)。
3)跨平台团队推荐策略
- 推荐:仓库内部统一使用 LF,工作区按需转换(但尽量也用 LF)
- 实际配置建议:
- 文本文件统一
text=auto,对某些语言/文件使用 eol=lf 强制 LF - 对确需 CRLF 的文件(某些 Windows 批处理脚本 .bat/.cmd)使用 eol=crlf
- 文本文件统一
示例:跨平台项目常用配置
# 1. 默认所有文件自动按文本检测
* text=auto
# 2. 源代码统一 LF(推荐)
*.c text eol=lf
*.h text eol=lf
*.cpp text eol=lf
*.hpp text eol=lf
*.js text eol=lf
*.ts text eol=lf
*.py text eol=lf
*.java text eol=lf
*.go text eol=lf
*.rb text eol=lf
# 3. 脚本文件:同样统一 LF
*.sh text eol=lf
*.bash text eol=lf
# 4. Windows 特有脚本使用 CRLF(cmd/powershell)
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# 5. 明确声明二进制文件(不做换行转换)
*.png -text
*.jpg -text
*.jpeg -text
*.gif -text
*.pdf -text
*.zip -text
*.exe -text
*.dll -text3.2 binary / diff 相关属性#
1)binary 属性
- binary 等价于
-text -diff(在多数版本的 Git 中的约定) - 表示:
- 不做文本换行转换
- 不做文本 diff(把 diff 视为二进制)
- 何时用:
- 对于图像、音视频、压缩包等确实不能按文本解析的文件,显式标记 binary 更安全清晰
示例:
*.png binary # 图片当作二进制,不做文本处理
*.jpg binary
*.zip binary
*.pdf binary2)diff / diff=NAME
- diff(不带值)
- 表示允许对这些文件做文本 diff(默认行为)
- 实际上很多时候不写 diff 属性也会被按文本 diff
- diff=NAME
- 使用自定义 diff 驱动 NAME
- 需要在 .gitconfig(或仓库级 .git/config)中定义对应的 diff 驱动行为
例:为 *.md 使用自定义 markdown diff 驱动
.gitattributes:
*.md text diff=markdown.gitconfig(或 .git/config)中:
[diff "markdown"]
textconv = markdown-diff-filter # 调用一个外部脚本对 Markdown 做预处理再 diff- 这样,Git 在 diff .md 文件时,会先用 textconv 指定的命令转换内容,再比较,能更好处理 Markdown 标题、列表等。
再例:为 *.png 显式标记为 binary:
*.png binary # 强制当作二进制,禁用文本 diff3.3 merge 相关属性#
1)merge / merge=NAME
- merge(单独)
- 表示允许三路合并(默认行为)
- merge=NAME
- 为匹配的文件使用自定义 merge 驱动(在 .gitconfig 里定义)
- 常见场景:
- 某些配置文件(如 JSON/ YAML / XML )希望使用更智能的合并脚本
- 某些文件不适合自动合并(如锁文件、生成文件),希望用 ours/theirs 之类策略简化冲突
示例:对某类配置文件使用特殊 merge 驱动
.gitattributes:
# 自定义对 JSON 的合并方式
*.json merge=jsonmerge.gitconfig:
[merge "jsonmerge"]
name = custom json merge
driver = json-merge-driver %O %A %B- json-merge-driver 是你自定义的脚本,负责把 base(%O)、current(%A)、other(%B) 合并成一个结果文件。
示例:对生成的锁文件使用 ours 策略(只保留当前分支版本)
# package-lock.json 冲突时总是优先使用当前分支版本
package-lock.json merge=ours3.4 filter 相关属性(clean/smudge)#
1)filter、filter=NAME 的含义
- filter=NAME
- 告诉 Git 对匹配的文件启用名为 NAME 的过滤器
- 过滤器是 Git 的 clean/smudge 机制:
- clean:工作区 -> Git 对象库(提交/添加之前)时的过滤
- smudge:Git 对象库 -> 工作区(checkout)时的过滤
Git LFS 就是一个典型的 filter 使用案例:提交时把大文件转成“指针文本”,checkout 时再从 LFS 服务器拉回实际大文件。
简单例子(概念):
.gitattributes:
# 自动格式化 JSON(假设有一个 filter 叫 formatjson)
*.json filter=formatjson.gitconfig:
[filter "formatjson"]
clean = json-format-cli --normalize
smudge = cat- clean:提交之前用 json-format-cli 把 JSON 规范化
- smudge:checkout 时原样输出(不做处理)
3.5 导出相关(git archive)#
1)export-ignore
- 当执行
git archive(用于打包发布)时,被标记 export-ignore 的文件不会被包含进去 - 常用于忽略:
- 开发脚本
- 测试数据
- CI 配置文件等非发布内容
2)export-subst
- 允许在归档时对特定占位符做替换,如
$Id$等 - 用得相对少,这里只做概念了解
示例:
# 打包发布时忽略以下文件和目录
.gitignore export-ignore
.gitattributes export-ignore
tools/** export-ignore
tests/** export-ignore
docs/dev/** export-ignore四、Git LFS 场景重点讲解#
4.1 Git LFS 的基本原理(简要)#
1)LFS 做了什么
- Git LFS(Git Large File Storage)并没有修改 Git 的内部核心机制,而是通过:
- 在 Git 里存储“小的指针文件”(文本)
- 把真正的大文件内容放在一个独立的 LFS 服务器或存储(可以是 git 服务器扩展)
- 对开发者来说:
- 提交/checkout 文件的流程基本一样
- Git 里看到的是指针文件,但 Git LFS 在工作区自动替换成真正的大文件
2)为什么用 LFS
- 避免大文件直接进入 Git 对象库:
- 仓库体积会快速膨胀
- clone/pull 非常慢
- 历史清理极其困难(大文件一旦进了历史,很难完全清除)
- LFS 的好处:
- Git 历史中只记录小指针文件,体积大幅缩小
- LFS 对大文件有专门的存储和传输机制,更适合大体积和多版本
- clone 时可以选择是否下载所有 LFS 内容
4.2 .gitattributes 在 LFS 中的核心角色#
1)git lfs track 实际干了什么
当你执行:
git lfs track "*.psd"Git LFS 会自动在 .gitattributes 中添加一行类似:
*.psd filter=lfs diff=lfs merge=lfs -text也就是说,“LFS 管理哪些文件类型”,实际是通过 .gitattributes 来告知 Git 的。
2)典型规则格式逐项解释
以这行为例:
*.psd filter=lfs diff=lfs merge=lfs -text*.psd- 匹配所有 Photoshop 文件
filter=lfs- 使用名为 lfs 的 filter
- 这就是 Git LFS 注册的 clean/smudge 过滤器
- clean:提交时,把真实的二进制 PSD 文件转换为一个 LFS 指针文本
- smudge:checkout 时,根据指针文件从 LFS 存储拉回真实 PSD 到工作区
diff=lfs- 使用 LFS 的 diff 方式(通常不会显示具体二进制 diff,而是显示文件 ID 变化等)
merge=lfs- 使用 LFS 的 merge 方式(一般是“把文件当作整体二进制对象处理”,不做文本合并)
-text- 明确声明这些文件不做文本处理
- 防止 Git 对它们做任何换行转换或默认文本 diff
3).gitattributes 对 LFS 的影响总结
- .gitattributes 是 LFS 生效的关键:
- 没有在 .gitattributes 中标记为 filter=lfs 的文件类型,Git LFS 就不会接管这些文件,它们会以普通方式进入 Git 仓库(这是很多人踩的坑)。
- 所以:
- LFS 类型配置 = 修改 .gitattributes
- git lfs track/untrack = 帮你自动操作 .gitattributes
4.3 常见 LFS 配置示例(典型大文件项目)#
假设你有一个项目,包含:
- 图片:*.png, *.jpg, *.jpeg
- 音视频:*.mp3, *.wav, *.mp4
- 压缩包:*.zip, *.tar.gz
- 模型/权重:*.bin, *.h5, *.pt, *.onnx
可以这样配置:
# =======================
# Git LFS 管理的大文件
# =======================
# 图片资源(通常体积大且频繁修改)
*.png filter=lfs diff=lfs merge=lfs -text # 位图图片,如 UI 素材、纹理等
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
# 音频/音效资源
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
# 视频资源
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
# 压缩包、归档数据(导入数据包/资源包)
*.zip filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.tar.gz filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
# 机器学习/游戏模型、权重文件
*.bin filter=lfs diff=lfs merge=lfs -text # 自定义二进制权重/参数文件
*.h5 filter=lfs diff=lfs merge=lfs -text
*.hdf5 filter=lfs diff=lfs merge=lfs -text
*.pt filter=lfs diff=lfs merge=lfs -text # PyTorch 模型
*.pth filter=lfs diff=lfs merge=lfs -text
*.onnx filter=lfs diff=lfs merge=lfs -text
*.pb filter=lfs diff=lfs merge=lfs -text # TensorFlow GraphDef
*.tflite filter=lfs diff=lfs merge=lfs -text
# 其他体积可能较大的二进制资源
*.iso filter=lfs diff=lfs merge=lfs -text
*.dll filter=lfs diff=lfs merge=lfs -text
*.so filter=lfs diff=lfs merge=lfs -text
*.dmg filter=lfs diff=lfs merge=lfs -text说明:
- 这些规则都表示“由 LFS 接管这些文件类型”,提交它们时,只会在 Git 中存一个小指针文件。
- 正常开发时,你看的是完整资源文件(因为 checkout 时 LFS 帮你从存储拉回来了)。
4.4 Git LFS + .gitattributes 实战注意事项#
1)正确顺序:先配置 LFS,再提交大文件
正确流程:
- 初始化 LFS(仓库内执行一次):
git lfs install - 针对大文件类型执行 track(会更新 .gitattributes):
git lfs track "*.png" git lfs track "*.mp4" git lfs track "*.pt" - 提交 .gitattributes(必须先提交 .gitattributes):
git add .gitattributes git commit -m "Configure LFS for binary assets" - 再提交对应大文件:
git add assets/*.png models/*.pt git commit -m "Add initial assets and models"
2)如果先提交大文件,再配置 LFS 会怎样
- 已经提交的历史中的大文件,已经被存入 Git 对象库(而不是 LFS 存储)。
- 此时你再 git lfs track + 提交,只会影响以后新提交的版本:
- 旧的版本依然很大
- 仓库体积不会自动缩小
- 想要“把历史中的大文件迁移到 LFS”:
- 需要使用 git lfs migrate 或者 git filter-repo(低版本用 filter-branch)等历史重写工具,风险和成本较高。
- 因此强烈建议:新项目一开始就配置好 LFS。
3)不要随意手动删除或修改 LFS 相关 .gitattributes 规则
- 如果有人删除了类似:
*.png filter=lfs diff=lfs merge=lfs -text - 后果:
- 删除规则之后新提交的 .png 文件就不再通过 LFS 管理,而是直接进入 Git 对象库。
- 之前已经在 LFS 管理下的旧版本仍然在 LFS 中,导致历史不一致:
- 某些版本的 .png 在 LFS,某些版本直接在 Git
- clone 时行为可能令人困惑
- 团队管理建议:
- 把 .gitattributes 视为“仓库行为约定”,修改前要经过代码审查。
- 在 MR/PR 中对 LFS 规则变更特别留意。
4)多人协作时的同步问题
- .gitattributes 是版本文件,必须和代码一起被同步:
- 当有人新增 LFS 规则后,其他人拉取最新代码,会同时获得 .gitattributes 更新。
- 只有在每个开发者本地都安装了 Git LFS(git lfs install),LFS 规则才会真正生效。
- 常见坑:
- 某个开发者没装 Git LFS,结果他提交时,LFS 没有正确接管,可能导致指针文件被当作普通文本处理。
- 团队规范建议:在项目 README 或贡献指南中,写明:
- “此项目必须安装 Git LFS”
- 第一次 clone 后先运行
git lfs install和git lfs pull
五、完整示例:带注释的 .gitattributes 文件#
5.1 示例 1:普通跨平台文本项目(不使用 LFS)#
场景:纯代码项目(例如 Web/后端应用),不使用 LFS,仅需要:
- 统一换行符策略
- 合理区分文本/二进制
- 对部分文件设置特殊 diff/merge 或导出规则
示例 .gitattributes:
##############################################
# 通用规则:文本检测与换行符处理
##############################################
# 默认:所有文件自动按文本检测
* text=auto
# 源代码统一使用 LF 换行(推荐跨平台策略)
*.c text eol=lf
*.h text eol=lf
*.cpp text eol=lf
*.hpp text eol=lf
*.cc text eol=lf
*.java text eol=lf
*.kt text eol=lf
*.scala text eol=lf
*.js text eol=lf
*.ts text eol=lf
*.jsx text eol=lf
*.tsx text eol=lf
*.py text eol=lf
*.rb text eol=lf
*.go text eol=lf
*.php text eol=lf
# 脚本同样统一 LF
*.sh text eol=lf
*.bash text eol=lf
*.zsh text eol=lf
# Windows 专用脚本使用 CRLF(避免某些环境因 LF 失败)
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# 文本配置文件(统一 LF)
*.yml text eol=lf
*.yaml text eol=lf
*.json text eol=lf
*.xml text eol=lf
*.toml text eol=lf
*.ini text eol=lf
*.conf text eol=lf
*.env text eol=lf
*.properties text eol=lf
# 文档文件
*.md text eol=lf
*.txt text eol=lf
*.rst text eol=lf
*.csv text eol=lf
##############################################
# 二进制文件显式标记(避免误判)
##############################################
# 图片资源
*.png binary # 等价于 -text -diff
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.svgz binary
# 字体文件
*.ttf binary
*.otf binary
*.woff binary
*.woff2 binary
# 压缩文件
*.zip binary
*.gz binary
*.bz2 binary
*.xz binary
*.7z binary
*.rar binary
# 可执行/库文件
*.exe binary
*.dll binary
*.so binary
*.dylib binary
##############################################
# diff & merge 自定义
##############################################
# Markdown 使用自定义 diff 驱动(需在 .gitconfig 定义 diff.markdown)
*.md text diff=markdown
# 某些自动生成的锁文件,不做复杂合并,直接使用当前分支版本
package-lock.json merge=ours
yarn.lock merge=ours
pnpm-lock.yaml merge=ours
##############################################
# 导出相关(用于 git archive 打包发布)
##############################################
# 不把这些文件/目录打包到发布包中
.gitignore export-ignore
.gitattributes export-ignore
.github/** export-ignore
.gitlab/** export-ignore
tools/** export-ignore
scripts/dev/** export-ignore
tests/** export-ignore
docs/dev/** export-ignore5.2 示例 2:使用 Git LFS 的项目(大量资源文件)#
场景:Web/游戏/数据项目,有大量图片、音视频、模型等大文件,需要:
- 文本文件统一规范
- 所有大资源文件交给 LFS 管理
示例 .gitattributes:
##############################################
# 文本文件:统一换行符与编码处理
##############################################
# 默认文本自动检测
* text=auto
# 源码统一 LF
*.js text eol=lf
*.ts text eol=lf
*.jsx text eol=lf
*.tsx text eol=lf
*.css text eol=lf
*.scss text eol=lf
*.html text eol=lf
*.vue text eol=lf
*.cs text eol=lf
*.cpp text eol=lf
*.h text eol=lf
*.py text eol=lf
*.go text eol=lf
*.java text eol=lf
# 配置与脚本
*.json text eol=lf
*.yml text eol=lf
*.yaml text eol=lf
*.xml text eol=lf
*.ini text eol=lf
*.toml text eol=lf
*.conf text eol=lf
*.env text eol=lf
*.sh text eol=lf
*.bat text eol=crlf
*.cmd text eol=crlf
*.ps1 text eol=crlf
# 文档
*.md text eol=lf
*.txt text eol=lf
LICENSE text eol=lf
##############################################
# Git LFS 管理的资源文件
##############################################
# 注意:这些规则对应 `git lfs track` 命令生成的配置
# 修改前请确认了解影响
# 1. 图片资源(大分辨率、贴图、UI 素材)
*.png filter=lfs diff=lfs merge=lfs -text
*.jpg filter=lfs diff=lfs merge=lfs -text
*.jpeg filter=lfs diff=lfs merge=lfs -text
*.tga filter=lfs diff=lfs merge=lfs -text
*.psd filter=lfs diff=lfs merge=lfs -text # Photoshop 源文件
*.bmp filter=lfs diff=lfs merge=lfs -text
*.tiff filter=lfs diff=lfs merge=lfs -text
# 2. 音频和音效
*.mp3 filter=lfs diff=lfs merge=lfs -text
*.wav filter=lfs diff=lfs merge=lfs -text
*.ogg filter=lfs diff=lfs merge=lfs -text
*.flac filter=lfs diff=lfs merge=lfs -text
# 3. 视频和过场动画
*.mp4 filter=lfs diff=lfs merge=lfs -text
*.mov filter=lfs diff=lfs merge=lfs -text
*.avi filter=lfs diff=lfs merge=lfs -text
*.webm filter=lfs diff=lfs merge=lfs -text
# 4. 压缩包/导入数据包
*.zip filter=lfs diff=lfs merge=lfs -text
*.rar filter=lfs diff=lfs merge=lfs -text
*.7z filter=lfs diff=lfs merge=lfs -text
*.tar filter=lfs diff=lfs merge=lfs -text
*.tar.gz filter=lfs diff=lfs merge=lfs -text
*.tgz filter=lfs diff=lfs merge=lfs -text
# 5. 模型/权重/大数据文件
*.bin filter=lfs diff=lfs merge=lfs -text # 自定义二进制参数文件
*.h5 filter=lfs diff=lfs merge=lfs -text
*.hdf5 filter=lfs diff=lfs merge=lfs -text
*.pt filter=lfs diff=lfs merge=lfs -text # PyTorch 模型
*.pth filter=lfs diff=lfs merge=lfs -text
*.onnx filter=lfs diff=lfs merge=lfs -text
*.pb filter=lfs diff=lfs merge=lfs -text # TensorFlow 模型
*.tflite filter=lfs diff=lfs merge=lfs -text
*.npz filter=lfs diff=lfs merge=lfs -text # 压缩 numpy 数组
*.npy filter=lfs diff=lfs merge=lfs -text
# 6. 游戏引擎资源(例如 Unity/Unreal)
*.unity filter=lfs diff=lfs merge=lfs -text
*.prefab filter=lfs diff=lfs merge=lfs -text
*.asset filter=lfs diff=lfs merge=lfs -text
*.fbx filter=lfs diff=lfs merge=lfs -text
*.uasset filter=lfs diff=lfs merge=lfs -text
*.umap filter=lfs diff=lfs merge=lfs -text
# 7. 其他可能较大的二进制文件
*.iso filter=lfs diff=lfs merge=lfs -text
*.dmg filter=lfs diff=lfs merge=lfs -text
*.apk filter=lfs diff=lfs merge=lfs -text
*.ipa filter=lfs diff=lfs merge=lfs -text
##############################################
# 导出规则:打包时不需要的开发文件
##############################################
.gitignore export-ignore
.gitattributes export-ignore
.gitattributes.example export-ignore
.github/** export-ignore
.gitlab/** export-ignore
docs/dev/** export-ignore
tools/** export-ignore
scripts/dev/** export-ignore
tests/** export-ignore六、最佳实践与常见坑总结#
1)新项目一开始就建立合适的 .gitattributes#
- 原因:
- 早期确定好文本/二进制规则和 LFS 管理范围,能避免后期历史重写。
- 特别是 LFS,如果大文件一开始就没进 Git 正常对象库,你以后几乎不用考虑迁移/清理。
- 建议流程:
- 创建仓库初始时,就添加 .gitattributes。
- 如果需要 LFS,立即做:
- git lfs install
- git lfs track “*.xxx”
- 提交 .gitattributes 之后再添加资源文件。
2)跨平台项目的 text/eol 策略#
- 推荐策略:
- 仓库内部统一使用 LF。
- 工作区尽量也用 LF(windows 端编辑器通常默认支持 LF,按需配置)。
- 实战建议:
- 在 .gitattributes 中明确设置:
* text=auto- 对源代码、配置、脚本使用
eol=lf - 对 .bat / .cmd / .ps1 使用
eol=crlf
- 禁用 core.autocrlf(设置为 false),把换行控制尽量统一写到 .gitattributes 中,保证团队一致性。
- 在 .gitattributes 中明确设置:
3)使用 LFS 的团队规范#
- 规范 1:必须安装 Git LFS
- 在项目 README 中写清:
- “克隆本仓库前,请先安装 Git LFS”
- “首次使用:git lfs install(每台机器只需要执行一次)”
- 在项目 README 中写清:
- 规范 2:统一通过 git lfs track 修改 .gitattributes
- 不要求所有人手写 LFS 规则,鼓励通过命令添加:
git lfs track "*.psd"
- 这样可以避免属性书写错误(少写 diff=lfs / merge=lfs 等)
- 不要求所有人手写 LFS 规则,鼓励通过命令添加:
- 规范 3:修改 LFS 规则要走正常审查流程
- 特别是删除/放宽某些 LFS 规则时,一定要在 MR/PR 里说明原因和影响。
4)常见错误场景与解决思路#
(1)仓库突然异常庞大
- 可能原因:
- 大文件直接被提交到 Git(没有通过 LFS)
- 经常更新的大文件(如日志、构建产物)被反复提交
- 解决思路:
- 查找大对象:
git count-objects -vH- 或使用
git-sizer、git rev-list --objects --all | sort -k 2
- 对已有的大文件:
- 若希望迁移到 LFS:
- 使用
git lfs migrate import --include="*.xxx"重写历史(需要全员配合,更换远程等)
- 使用
- 或者用
git filter-repo清理(同样是历史重写)
- 若希望迁移到 LFS:
- 防止再次发生:
- 在 .gitattributes 中为这些文件类型配置 LFS 或标记为 binary,并在流程中避免提交生成文件。
- 查找大对象:
(2)换行符混乱(CRLF/LF 交替)
- 典型表现:
- 某些文件每次被别人改动后,你这边总是显示整文件被修改(CRLF/LF 切换)。
- 解决思路:
- 在 .gitattributes 中明确该文件类型的 eol(通常 eol=lf)。
- 同时建议每个人关闭 core.autocrlf,统一使用 .gitattributes 来做换行控制:
git config core.autocrlf false
- 对已经混乱的文件,可以统一一次性转换:
- 在一个 clean 的分支上用脚本统一转换换行,然后提交;后续由 .gitattributes 保持稳定。
(3)大文件未通过 LFS 管理
- 典型情况:
- 已经用了 LFS,但是某类新出现的大文件类型(如 .npz)忘记 track。
- 几个月后发现仓库变大,才意识到这些文件走的是普通 Git。
- 解决思路:
- 先补上 .gitattributes 规则:
git lfs track "*.npz"
- 新提交开始由 LFS 接管
- 对于历史:视情况选择是否用 git lfs migrate / filter-repo 来迁移已有历史。
- 先补上 .gitattributes 规则:
- 预防:
- 当引入新类型的大文件时,把“添加 LFS track”作为 code review 的检查项;
- 或用 pre-receive hook / CI 检查提交中是否包含未 LFS 管理的大文件(超过某大小阈值)。
(4)LFS 文件 checkout 变成指针文本,无法使用
- 现象:
- 打开某个资源文件(png、mp4 等),看到的是类似:
version https://git-lfs.github.com/spec/v1 oid sha256:xxxx size 1234567
- 打开某个资源文件(png、mp4 等),看到的是类似:
- 可能原因:
- 本地没有安装 Git LFS,或没有执行
git lfs install。
- 本地没有安装 Git LFS,或没有执行
- 解决:
- 安装 Git LFS(根据平台:brew / apt / choco 等)
- 在仓库中执行:
git lfs install git lfs pull git checkout HEAD -- . - 让 LFS 重新 smudge,把指针文件替换为真实大文件。
总结一句话:
- .gitattributes 是 Git 里“按路径控制文件行为”的核心配置,负责文本/二进制识别、换行规范、diff/merge 策略、filter(包括 LFS)和导出规则。
- 在 Git LFS 场景中,.gitattributes 是 LFS 生效的“入口”:哪些文件由 LFS 管理,完全靠它决定(filter=lfs diff=lfs merge=lfs -text 等)。
- 只要从项目一开始就认真设计 .gitattributes,并在团队中把它当作“仓库行为规范”的一部分来管理,就能避免绝大多数大文件和换行相关的坑。