.gitignore 与 .gitattributes 文件详解
.gitignore和.gitattributes是 Git 版本控制系统中两个重要的配置文件,它们帮助开发者精细地控制 Git 如何处理工作目录中的文件。gitignore主要用于忽略不应该被版本控制的文件,而gitattributes则用于定义不同文件的属性,影响 Git 存储和比较文件的方式。理解和正确使用这两个文件对于维护干净、高效且一致的 Git 仓库至关重要。
核心思想:
.gitignore告诉 Git 哪些文件或目录应该被忽略,不纳入版本控制。.gitattributes告诉 Git 如何对待特定类型的文件,例如行尾符、合并策略、文本转换等。
一、.gitignore 文件详解
.gitignore 文件用于指定 Git 应该忽略哪些文件或目录。 这些被忽略的文件不会被 Git 跟踪,也不会被添加到仓库中。这对于排除构建产物、日志文件、敏感配置、IDE 特定文件等内容非常有用,可以保持仓库的整洁,避免提交不必要的文件,并减少仓库大小。
1.1 工作原理
Git 在执行 git add 或 git commit 等命令时,会检查工作目录中是否存在 .gitignore 文件。它会自底向上地查找(从当前目录到父目录),并应用找到的所有 .gitignore 文件中的规则。最接近文件的 .gitignore 规则优先级最高。
你可以在项目的任意层级创建 .gitignore 文件。通常,一个项目只有一个位于根目录的 .gitignore 文件。此外,Git 还支持一个全局的 .gitignore 文件,通过 git config --global core.excludesfile ~/.gitignore_global 配置。
1.2 规则格式
.gitignore 文件中的每行都代表一个忽略规则。规则支持通配符和各种模式:
- 空行或以
#开头的行:被视为空白或注释,会被 Git 忽略。 - 普通文件名:忽略指定名称的文件。
1
mysecret.conf
- 目录名:忽略指定目录及其所有内容。
1
2bin/ # 忽略项目根目录下的 bin 目录
/logs # 忽略项目根目录下的 logs 目录 - 通配符
*:匹配零个或多个字符。1
2*.log # 忽略所有 .log 文件
*build/ # 忽略所有以 build 结尾的目录 - 通配符
?:匹配单个字符。1
file?.txt # 匹配 file1.txt, fileA.txt 等
- 方括号
[]:匹配括号内任何一个字符。1
file[0-9].txt # 匹配 file0.txt 到 file9.txt
- 感叹号
!:用于否定之前的规则,强制包含某个文件或目录。1
2*.log # 忽略所有 .log 文件
!important.log # 但不忽略 important.log - 斜杠
/:- 在模式的开头表示只匹配项目根目录的文件或目录。
1
/temp # 只忽略项目根目录下的 temp 目录 (不会忽略 subdir/temp)
- 在模式的末尾表示只匹配目录。
1
build/ # 忽略名为 build 的目录
- 在模式的开头表示只匹配项目根目录的文件或目录。
- 双星号
**:匹配任意中间目录,即递归匹配。1
2**/logs # 忽略任意层级下的 logs 目录
docs/**/*.md # 忽略 docs 目录下任意子目录中的所有 .md 文件
1.3 示例
在 Go 项目中一个典型的 .gitignore 文件可能会包含以下内容:
1 | # IDE specific files |
在 Python 项目中一个典型的 .gitignore 文件可能会包含以下内容:
1 | # Byte-code files |
1.4 注意事项
- 只忽略未被 Git 跟踪的文件:
.gitignore规则只对尚未被 Git 跟踪的文件生效。如果一个文件已经被 Git 跟踪(即已经通过git add添加到仓库并提交),即使后来将其添加到.gitignore中,Git 也不会将其忽略。你需要先从仓库中移除该文件 (但不从工作目录删除),然后 Git 才会遵守.gitignore规则:1
2git rm --cached <file_path>
git commit -m "Remove <file_path> from gitignore" - 全局
.gitignore(Optional):可以设置一个全局的.gitignore文件来忽略所有项目通用的文件 (如操作系统生成的.DS_Store、Thumbs.db,或个人 IDE 配置文件)。这通过修改 Git 配置完成:1
git config --global core.excludesfile ~/.gitignore_global
二、.gitattributes 文件详解
.gitattributes 文件用于为特定文件或路径模式定义属性。 这些属性会影响 Git 处理文件的方式,例如行尾转换、差异比较、合并策略、二进制文件处理等。它允许你为不同类型的文件指定不同的 Git 行为。
2.1 工作原理
与 .gitignore 类似,Git 在检查文件时也会查找 .gitattributes 文件,并应用其定义的规则。它也是自底向上地查找,最接近文件的规则优先级最高。
.gitattributes 文件通常位于项目的根目录,但也允许存在于子目录中。它也可以被配置为全局文件,但这种情况较少见,大多数属性通常是项目特定的。
2.2 规则格式
.gitattributes 文件中的每行由一个文件模式和一系列属性组成。
pattern attribute1 attribute2=value ...
pattern:与.gitignore类似的 glob 模式,用于匹配文件。attribute:定义对匹配文件应用的属性。
2.3 常用属性
以下是一些常见的 gitattributes 属性及其用途:
2.3.1 text 属性:行尾转换
这是最常用的属性之一,用于处理不同操作系统之间的行尾符差异。Windows 使用 CR LF (\r\n),Unix-like 系统使用 LF (\n)。Git 默认会尝试在检出时将 LF 转换为 CR LF (Windows),在提交时将 CR LF 转换为 LF。但这种自动转换有时会导致问题,text 属性允许你明确控制:
text(或text=auto):Git 会根据文件内容尝试自动处理行尾。这是 Git 的默认行为。text eol=lf:强制 Git 始终将行的结束存储为 LF。这适用于所有文本文件,确保在所有平台都使用 LF。在检出时,Windows 用户会转换为 CRLF。text eol=crlf:强制 Git 始终将行的结束存储为 CRLF。较少使用,通常只在特定 Windows 遗留系统上需要。-text:强制 Git 将文件视为二进制文件,完全不进行行尾转换。通常用于图像、视频等二进制文件,或被加密的文件。text=auto eol=lf:一个推荐的配置,将所有文件都视为text=auto,但如果 Git 确定它是文本文件,则在提交时确保其内部行尾是 LF。
2.3.2 binary 属性:二进制文件
binary:这是一个宏属性,等同于-text -diff -merge。它告诉 Git 将文件视为二进制文件,不进行行尾转换,不尝试对它们进行差异比较(只显示修改),也不尝试进行合并(如果发生冲突,通常会选择一方的版本)。这对于图像、编译后的可执行文件、压缩包等非常重要。
2.3.3 diff 属性:差异比较
diff:告诉 Git 如何生成文件的差异。diff:允许对文件进行差异比较 (默认)。-diff:禁用对该文件的差异比较。与binary属性的一部分相同。diff=tool:为特定类型的文件指定外部差异工具或特定的差异生成算法(例如,为文本型的代码文件使用按行比较,为 JSON/XML 等结构化文件使用智能差异)。1
*.json diff=json
2.3.4 merge 属性:合并策略
merge:指定文件在合并冲突时的处理策略。merge=text:默认,使用 Git 的标准三路合并策略。merge=binary:不尝试合并,如果发生冲突,以 BASE 或 HEAD 版本的整个文件作为结果。与binary属性的一部分相同。merge=union:尝试在有冲突时合并所有有冲突的行,这对于配置文件 (如 Dockerfile) 可能有用。merge=ours:如果发生冲突,使用我们(当前分支)的版本。merge=theirs:如果发生冲突,使用他们(传入分支)的版本。
2.3.5 linguist-language, linguist-vendored, linguist-generated 属性:GitHub Linguist
这些属性主要由 GitHub 用来识别仓库中的代码语言,并生成语言统计图。
linguist-language=<language>:强制指定文件的语言。1
*.json linguist-language=JSON
linguist-vendored:将文件标记为被 vendored(供应商提供的),这样它们就不会计入仓库的语言统计。1
vendor/** linguist-vendored
linguist-generated:将文件标记为自动生成,同样不会计入语言统计。1
*.pb.go linguist-generated # Protocol Buffer 生成的 Go 文件
2.4 示例
在一个 Go 项目中,一个典型的 .gitattributes 文件可能包含以下内容:
1 | # Set default line endings to LF for all text files where Git deems it appropriate. |
2.5 推荐配置 (.gitattributes 的推荐配置)
为了最大程度地避免跨平台行尾问题,以下是一个推荐的 .gitattributes 配置:
1 | # 设置自动行尾转换,并确保文本文件在仓库中是 LF |
这个配置意味着 Git 会尝试自动检测文件类型。对于它认为是文本的文件,在提交到仓库时,所有行尾都会被标准化为 LF。在 Windows 上检出时,LF 会被转换为 CRLF;在其他系统上,LF 保持不变。这解决了大多数行尾问题。
三、.gitignore 与 .gitattributes 的区别
| 特性 | .gitignore |
.gitattributes |
|---|---|---|
| 主要目的 | 告诉 Git 不要跟踪某些文件或目录。 | 告诉 Git 如何处理/对待某些已跟踪的文件。 |
| 作用对象 | 只对未被 Git 跟踪的文件生效。 | 对已被 Git 跟踪的文件和即将被跟踪的文件都生效。 |
| 影响范围 | 影响文件是否进入 Git 仓库。 | 影响文件在仓库中的存储方式 (如行尾)、差异比较、合并行为等。 |
| 常见用途 | 忽略编译产物、日志、IDE 配置文件、node_modules、venv 等。 |
规范行尾、标记二进制文件、定义合并策略、自定义差异比较、GitHub Linguist 属性。 |
| 文件内容 | 模式列表,指示要忽略的文件。 | 模式与属性对列表,指示如何处理文件。 |
四、总结
.gitignore 和 .gitattributes 都是 Git 项目中非常重要的配置文件,它们各自承担着不同的职责,但共同协作以确保 Git 仓库的整洁、一致性和功能性。
- 使用
.gitignore来管理不应该进入版本控制的文件,保持仓库的精简。 - 使用
.gitattributes来定义文件级别的 Git 行为,特别是处理跨平台行尾问题、标记二进制文件以及优化差异和合并操作。
正确地配置这两个文件可以避免许多常见的 Git 问题,尤其是在跨平台协作和处理生成的代码时,从而提高开发效率和代码质量。务必将这两个文件纳入版本控制,以便团队成员之间共享这些重要的配置。
