设置和配置
获取和创建项目
基本快照
分支和合并
共享和更新项目
检查和比较
补丁
调试
邮件
外部系统
服务器管理
指南
管理
底层命令
-
2.49.0
2025-03-14
- 2.46.1 → 2.48.1 没有变化
-
2.46.0
2024-07-29
- 2.44.1 → 2.45.3 没有变化
-
2.44.0
2024-02-23
- 2.43.1 → 2.43.6 没有变化
-
2.43.0
2023-11-20
- 2.42.1 → 2.42.4 没有变化
-
2.42.0
2023-08-21
- 2.41.1 → 2.41.3 没有变化
-
2.41.0
2023-06-01
- 2.40.1 → 2.40.4 没有变化
-
2.40.0
2023-03-12
- 2.36.1 → 2.39.5 没有变化
-
2.36.0
2022-04-18
- 2.32.1 → 2.35.8 没有变化
-
2.32.0
2021-06-06
- 2.30.1 → 2.31.8 没有变化
-
2.30.0
2020-12-27
- 2.27.1 → 2.29.3 没有变化
-
2.27.0
2020-06-01
- 2.25.1 → 2.26.3 没有变化
-
2.25.0
2020-01-13
- 2.24.1 → 2.24.4 没有变化
-
2.24.0
2019-11-04
- 2.23.1 → 2.23.4 没有变化
-
2.23.0
2019-08-16
- 2.22.1 → 2.22.5 没有变化
-
2.22.0
2019-06-07
- 2.21.1 → 2.21.4 没有变化
-
2.21.0
2019-02-24
- 2.19.3 → 2.20.5 没有变化
-
2.19.2
2018-11-21
- 2.18.1 → 2.19.1 没有变化
-
2.18.0
2018-06-21
- 2.17.1 → 2.17.6 没有变化
-
2.17.0
2018-04-02
-
2.16.6
2019-12-06
- 2.15.4 没有变化
-
2.14.6
2019-12-06
-
2.13.7
2018-05-22
- 2.12.5 没有变化
-
2.11.4
2017-09-22
-
2.10.5
2017-09-22
-
2.9.5
2017-07-30
- 2.7.6 → 2.8.6 没有变化
-
2.6.7
2017-05-05
-
2.5.6
2017-05-05
-
2.4.12
2017-05-05
- 2.3.10 没有变化
-
2.2.3
2015-09-04
- 2.1.4 没有变化
-
2.0.5
2014-12-17
描述
gitattributes
文件是一个简单的文本文件,它为 attributes
赋予路径名。
gitattributes
文件中的每一行都采用以下形式
pattern attr1 attr2 ...
即,一个模式后跟一个属性列表,用空格分隔。忽略开头和结尾的空格。以 *#* 开头的行将被忽略。以双引号开头的模式以 C 样式引用。当模式与相关路径匹配时,该行上列出的属性将赋予该路径。
对于给定的路径,每个属性都可以处于以下状态之一
当多个模式与该路径匹配时,后面的行将覆盖前面的行。此覆盖是按属性进行的。
模式与路径匹配的规则与 .gitignore
文件中的规则相同(请参阅 gitignore[5]),但有几个例外
-
禁止使用否定模式
-
与目录匹配的模式不会递归匹配该目录内的路径(因此,在属性文件中使用尾部斜杠
path/
语法毫无意义;请改用path/**
)
在决定将哪些属性分配给路径时,Git 会查阅 $GIT_DIR/info/attributes
文件(该文件具有最高优先级)、与相关路径位于同一目录中的 .gitattributes
文件及其父目录,直到工作树的顶层(包含 .gitattributes
的目录距离相关路径越远,其优先级越低)。最后,考虑全局和系统范围的文件(它们具有最低优先级)。
当工作树中缺少 .gitattributes
文件时,索引中的路径将用作后备。在检出过程中,使用索引中的 .gitattributes
,然后将工作树中的文件用作后备。
如果你希望仅影响单个存储库(即,为特定于该存储库的某个用户的工作流程的文件分配属性),则应将属性放置在 $GIT_DIR/info/attributes
文件中。应将应进行版本控制并分发到其他存储库的属性(即,所有用户都感兴趣的属性)放入 .gitattributes
文件中。应影响单个用户的所有存储库的属性应放置在由 core.attributesFile
配置选项指定的文件中(请参阅 git-config[1])。其默认值为 $XDG_CONFIG_HOME/git/attributes。如果未设置 $XDG_CONFIG_HOME 或为空,则改用 $HOME/.config/git/attributes。应影响系统上所有用户的属性应放置在 $(prefix)/etc/gitattributes
文件中。
有时你需要将路径的属性设置覆盖为 Unspecified
状态。这可以通过列出以感叹号 !
开头的属性名称来完成。
影响
Git 的某些操作可能会受到将特定属性分配给路径的影响。当前,以下操作可以识别属性。
检出和检入
这些属性影响在运行 git switch、git checkout 和 git merge 等命令时,存储库中存储的内容如何复制到工作树文件。它们还会影响 Git 在 git add 和 git commit 时如何将你在工作树中准备的内容存储在存储库中。
text
此属性将路径标记为文本文件,从而启用行尾转换:当将匹配的文件添加到索引时,该文件的行尾将在索引中规范化为 LF。相反,当文件从索引复制到工作目录时,其行尾可能会从 LF 转换为 CRLF,具体取决于 eol
属性、Git 配置和平台(请参阅下面对 eol
的说明)。
- 设置
-
在路径上设置
text
属性会启用对检入和检出的行尾转换,如上所述。每次检入文件时,行尾都会在索引中规范化为 LF,即使该文件之前已使用 CRLF 行尾添加到 Git 中也是如此。 - 取消设置
-
取消设置路径上的
text
属性会告诉 Git 在检入或检出时不尝试任何行尾转换。 - 设置为字符串值 "auto"
-
当
text
设置为 "auto" 时,Git 会自行决定该文件是文本文件还是二进制文件。如果它是文本文件,并且该文件以前未使用 CRLF 结尾位于 Git 中,则如上所述,行尾将在检入和检出时进行转换。否则,在检入或检出时不进行任何转换。 - 未指定
-
如果未指定
text
属性,则 Git 使用core.autocrlf
配置变量来确定是否应转换该文件。
任何其他值都会导致 Git 的行为就像 text
保持未指定一样。
eol
此属性标记一个路径,以便在检出时在工作树中使用特定的行尾样式。它仅在设置了 text
或 text=auto
时才有效(请参阅上文),但如果 text
保持未指定状态,则指定 eol
会自动设置 text
。
- 设置为字符串值 "crlf"
-
此设置会在检出文件时将工作目录中文件的行尾转换为 CRLF。
- 设置为字符串值 "lf"
-
此设置在检出文件时,在工作目录中使用与索引中相同的行尾。
- 未指定
-
如果未指定文件的
eol
属性,则工作目录中文件的行尾由core.autocrlf
或core.eol
配置变量确定(请参阅 git-config[1] 中这些选项的定义)。如果设置了text
,但未设置这两个变量中的任何一个,则 Windows 上的默认值为eol=crlf
,所有其他平台上的默认值为eol=lf
。
行尾转换
虽然 Git 通常会保持文件内容不变,但可以将其配置为将行尾规范化为存储库中的 LF,并可以选择在检出文件时将其转换为 CRLF。
如果你只是想在工作目录中具有 CRLF 行尾,而与你正在使用的存储库无关,则可以设置配置变量 "core.autocrlf",而无需使用任何属性。
[core] autocrlf = true
这不会强制规范化文本文件,但会确保你添加到仓库的文本文件在线尾符被规范化为 LF 后再添加,以及确保仓库中已经规范化的文件保持规范化。
如果你想确保任何贡献者添加到仓库的文本文件都经过线尾符规范化,你可以将所有文件的 text
属性设置为 “auto”。
* text=auto
这些属性允许对线尾符的转换进行细粒度控制。以下是一个示例,它将使 Git 规范化 .txt、.vcproj 和 .sh 文件,确保 .vcproj 文件在工作目录中具有 CRLF,.sh 文件具有 LF,并阻止 .jpg 文件被规范化,无论其内容如何。
* text=auto *.txt text *.vcproj text eol=crlf *.sh text eol=lf *.jpg -text
注意
|
在跨平台项目中使用 push 和 pull 到中心仓库时,如果启用了 text=auto 转换,则包含 CRLF 的文本文件应被规范化。 |
从一个干净的工作目录开始
$ echo "* text=auto" >.gitattributes $ git add --renormalize . $ git status # Show files that will be normalized $ git commit -m "Introduce end-of-line normalization"
如果任何不应被规范化的文件出现在 *git status* 中,请在运行 *git add -u* 之前取消设置其 text
属性。
manual.pdf -text
相反,Git 未检测到的文本文件可以手动启用规范化。
weirdchars.txt text
如果 core.safecrlf
设置为 “true” 或 “warn”,Git 会验证当前 core.autocrlf
设置下的转换是否可逆。 对于 “true”,Git 会拒绝不可逆的转换; 对于 “warn”,Git 仅打印警告但接受不可逆的转换。 安全性触发器用于防止对工作树中的文件进行此类转换,但有一些例外。 即使……
-
*git add* 本身不会触及工作树中的文件,但下次检出会,因此会触发安全性检查;
-
*git apply* 使用补丁更新文本文件会触及工作树中的文件,但该操作是关于文本文件的,而 CRLF 转换是关于修复线尾符不一致的,因此不会触发安全性检查;
-
*git diff* 本身不会触及工作树中的文件,但通常会运行它来检查你打算在下次 *git add* 中进行的更改。 为了尽早发现潜在问题,会触发安全性检查。
working-tree-encoding
Git 将以 ASCII 或其超集之一(例如 UTF-8、ISO-8859-1、…)编码的文件识别为文本文件。 以某些其他编码(例如 UTF-16)编码的文件被解释为二进制文件,因此内置的 Git 文本处理工具(例如 *git diff*)以及大多数 Git Web 前端默认情况下不显示这些文件的内容。
在这些情况下,你可以使用 working-tree-encoding
属性告诉 Git 工作目录中文件的编码。 如果具有此属性的文件被添加到 Git,则 Git 会将内容从指定的编码重新编码为 UTF-8。 最后,Git 将 UTF-8 编码的内容存储在其内部数据结构(称为 “索引”)中。 检出时,内容会重新编码回指定的编码。
请注意,使用 working-tree-encoding
属性可能会遇到一些陷阱
-
替代 Git 实现(例如 JGit 或 libgit2)和旧版本的 Git(截至 2018 年 3 月)不支持
working-tree-encoding
属性。 如果你决定在仓库中使用working-tree-encoding
属性,强烈建议确保所有与仓库交互的客户端都支持它。例如,Microsoft Visual Studio 资源文件 (
*.rc
) 或 PowerShell 脚本文件 (*.ps1
) 有时以 UTF-16 编码。 如果你将*.ps1
文件声明为 UTF-16 并添加foo.ps1
,并且启用了working-tree-encoding
的 Git 客户端,则foo.ps1
将在内部存储为 UTF-8。 不支持working-tree-encoding
的客户端会将foo.ps1
检出为 UTF-8 编码的文件。 这通常会给此文件的用户带来麻烦。如果不支持
working-tree-encoding
属性的 Git 客户端添加一个新文件bar.ps1
,则bar.ps1
将 “按原样” 存储在内部(在本例中可能为 UTF-16)。 支持working-tree-encoding
的客户端会将内部内容解释为 UTF-8,并尝试在检出时将其转换为 UTF-16。 该操作将失败并导致错误。 -
将内容重新编码为非 UTF 编码可能会导致错误,因为转换可能不是 UTF-8 往返安全的。 如果你怀疑你的编码不是往返安全的,请将其添加到
core.checkRoundtripEncoding
以使 Git 检查往返编码(请参阅 git-config[1])。 众所周知,SHIFT-JIS(日语字符集)与 UTF-8 存在往返问题,默认情况下会进行检查。 -
重新编码内容需要资源,这可能会减慢某些 Git 操作(例如 *git checkout* 或 *git add*)。
仅当你无法以 UTF-8 编码存储文件并且你希望 Git 能够将内容作为文本处理时,才使用 working-tree-encoding
属性。
例如,如果你的 **.ps1
* 文件是带字节顺序标记 (BOM) 的 UTF-16 编码,并且你希望 Git 根据你的平台执行自动行尾转换,请使用以下属性。
*.ps1 text working-tree-encoding=UTF-16
如果你的 **.ps1
* 文件是不带 BOM 的 UTF-16 小端编码,并且你希望 Git 在工作目录中使用 Windows 行尾符,请使用以下属性(如果要使用带 BOM 的 UTF-16 小端,请使用 UTF-16LE-BOM
而不是 UTF-16LE
)。 请注意,如果使用 working-tree-encoding
属性以避免歧义,强烈建议使用 eol
显式定义行尾符。
*.ps1 text working-tree-encoding=UTF-16LE eol=crlf
你可以使用以下命令获取平台上所有可用编码的列表
iconv --list
如果你不知道文件的编码,则可以使用 file
命令来猜测编码
file foo.ps1
ident
当为路径设置属性 ident
时,Git 会在检出时将 blob 对象中的 $Id$
替换为 $Id:
,后跟 40 个字符的十六进制 blob 对象名称,后跟一个美元符号 $
。 工作树文件中任何以 $Id:
开头并以 $
结尾的字节序列都会在签入时被替换为 $Id$
。
filter
可以将 filter
属性设置为一个字符串值,该值指定配置中定义的筛选器驱动程序。
筛选器驱动程序由 clean
命令和 smudge
命令组成,两者都可以不指定。 检出时,如果指定了 smudge
命令,则该命令会从标准输入接收 blob 对象,并使用其标准输出更新工作树文件。 类似地,clean
命令用于在签入时转换工作树文件的内容。 默认情况下,这些命令仅处理单个 blob 并终止。 如果使用长时间运行的 process
筛选器代替 clean
和/或 smudge
筛选器,则 Git 可以在单个 Git 命令的整个生命周期内使用单个筛选器命令调用处理所有 blob,例如 git add --all
。 如果配置了长时间运行的 process
筛选器,则它始终优先于配置的单个 blob 筛选器。 有关用于与 process
筛选器通信的协议的描述,请参阅下面的部分。
内容过滤的一个用途是将内容调整为更方便平台、文件系统和用户使用的形式。 对于此操作模式,这里的关键短语是 “更方便”,而不是 “将不可用的东西变成可用”。 换句话说,目的是如果有人取消设置筛选器驱动程序定义,或者没有适当的筛选器程序,则该项目仍然可用。
内容过滤的另一个用途是存储无法直接在仓库中使用的内容(例如,指向 Git 外部存储的真实内容的 UUID,或加密内容),并在检出时将其转换为可用形式(例如,下载外部内容,或解密加密内容)。
这两种筛选器的行为不同,默认情况下,筛选器被视为前者,即将内容调整为更方便的形式。 配置中缺少筛选器驱动程序定义,或筛选器驱动程序以非零状态退出,这不是错误,而是使筛选器成为空操作传递。
你可以通过将 filter.<driver>.required 配置变量设置为 true
来声明筛选器将本身不可用的内容转换为可用内容。
注意:每当更改 clean 筛选器时,应重新规范化仓库:$ git add --renormalize .
例如,在 .gitattributes 中,你将为路径分配 filter
属性。
*.c filter=indent
然后,你将在 .git/config 中定义 “filter.indent.clean” 和 “filter.indent.smudge” 配置,以指定一对命令来修改 C 程序的内容,当源文件被签入(运行 “clean”)和检出时(由于命令是 “cat”,因此不进行更改)。
[filter "indent"] clean = indent smudge = cat
为了获得最佳效果,如果再次运行 clean
,则不应进一步更改其输出(“clean→clean” 应等效于 “clean”),并且多个 smudge
命令不应更改 clean
的输出(“smudge→smudge→clean” 应等效于 “clean”)。 请参阅下面的合并部分。
“indent” 筛选器在这方面表现良好:它不会修改已经正确缩进的输入。 在这种情况下,缺少 smudge 筛选器意味着 clean 筛选器必须接受其自身的输出而不进行修改。
如果筛选器必须成功才能使存储的内容可用,则可以在配置中声明该筛选器为 required
[filter "crypt"] clean = openssl enc ... smudge = openssl enc -d ... required
筛选器命令行上的序列 "%f" 被替换为筛选器正在处理的文件的名称。 筛选器可能会在关键字替换中使用它。 例如
[filter "p4"] clean = git-p4-filter --clean %f smudge = git-p4-filter --smudge %f
请注意,"%f" 是正在处理的路径的名称。 根据正在筛选的版本,磁盘上相应的文件可能不存在,或者可能具有不同的内容。 因此,smudge 和 clean 命令不应尝试访问磁盘上的文件,而只能充当提供给它们的标准输入内容的筛选器。
长时间运行的筛选器进程
如果筛选器命令(字符串值)通过 filter.<driver>.process
定义,则 Git 可以在单个 Git 命令的整个生命周期内使用单个筛选器调用处理所有 blob。 这是通过使用长时间运行的进程协议(在 Documentation/technical/long-running-process-protocol.adoc 中描述)实现的。
当 Git 遇到第一个需要清理或涂抹的文件时,它会启动筛选器并执行握手。 在握手中,Git 发送的欢迎消息是 "git-filter-client",仅支持版本 2,支持的功能包括 "clean"、"smudge" 和 "delay"。
之后,Git 会发送一个以刷新数据包结尾的 “key=value” 对列表。 该列表将至少包含筛选器命令(基于支持的功能)和要筛选的相对于仓库根目录的文件路径名。 紧接着刷新数据包,Git 会将内容拆分为零个或多个 pkt-line 数据包和一个刷新数据包,以终止内容。 请注意,筛选器在收到内容和最终刷新数据包之前不得发送任何响应。 另请注意,“key=value” 对的 “value” 可以包含 “=” 字符,而键永远不会包含该字符。
packet: git> command=smudge packet: git> pathname=path/testfile.dat packet: git> 0000 packet: git> CONTENT packet: git> 0000
过滤器应返回以 flush 数据包结尾的 "key=value" 键值对列表。如果过滤器没有遇到问题,则该列表必须包含一个 "success" 状态。 在这些数据包之后,过滤器应以零个或多个 pkt-line 数据包的形式发送内容,并在最后发送一个 flush 数据包。 最后,应返回第二个以 flush 数据包结尾的 "key=value" 键值对列表。 过滤器可以在第二个列表中更改状态,也可以保持状态不变,使用空列表。 请注意,无论如何,空列表都必须以 flush 数据包结尾。
packet: git< status=success packet: git< 0000 packet: git< SMUDGED_CONTENT packet: git< 0000 packet: git< 0000 # empty list, keep "status=success" unchanged!
如果结果内容为空,则过滤器应返回 "success" 状态和一个 flush 数据包,以表示内容为空。
packet: git< status=success packet: git< 0000 packet: git< 0000 # empty content! packet: git< 0000 # empty list, keep "status=success" unchanged!
如果过滤器无法或不想处理内容,则应返回 "error" 状态。
packet: git< status=error packet: git< 0000
如果过滤器在处理过程中遇到错误,则可以在发送(部分或全部)内容后发送 "error" 状态。
packet: git< status=success packet: git< 0000 packet: git< HALF_WRITTEN_ERRONEOUS_CONTENT packet: git< 0000 packet: git< status=error packet: git< 0000
如果过滤器无法或不想处理内容,以及 Git 进程生命周期内的任何未来内容,则应在协议中的任何时候返回 "abort" 状态。
packet: git< status=abort packet: git< 0000
如果设置了 "error"/"abort" 状态,Git 既不会停止也不会重启过滤器进程。 但是,Git 会根据 filter.<driver>.required
标志设置其退出代码,从而模仿 filter.<driver>.clean
/ filter.<driver>.smudge
机制的行为。
如果过滤器在通信过程中死亡,或者不遵守协议,那么 Git 将停止该过滤器进程,并使用下一个需要处理的文件重新启动它。根据 filter.<driver>.required
标志,Git 会将其解释为错误。
延迟
如果过滤器支持 "delay" 功能,那么 Git 可以在过滤器命令和路径名之后发送 "can-delay" 标志。 此标志表示过滤器可以通过不返回内容,而是返回 "delayed" 状态和一个 flush 数据包来延迟过滤当前 blob(例如,为了补偿网络延迟)。
packet: git> command=smudge packet: git> pathname=path/testfile.dat packet: git> can-delay=1 packet: git> 0000 packet: git> CONTENT packet: git> 0000 packet: git< status=delayed packet: git< 0000
如果过滤器支持 "delay" 功能,那么它必须支持 "list_available_blobs" 命令。 如果 Git 发送此命令,那么过滤器应返回一个路径名列表,表示之前已延迟但现在可用的 blob。 该列表必须以 flush 数据包结尾,然后是也是以 flush 数据包结尾的 "success" 状态。 如果尚未提供延迟路径的任何 blob,则过滤器应阻止响应,直到至少一个 blob 可用。 过滤器可以通过发送空列表来告诉 Git 它没有更多延迟的 blob。 一旦过滤器返回一个空列表,Git 就会停止询问。 Git 此时没有收到的所有 blob 都被认为是丢失的,并将导致错误。
packet: git> command=list_available_blobs packet: git> 0000 packet: git< pathname=path/testfile.dat packet: git< pathname=path/otherfile.dat packet: git< 0000 packet: git< status=success packet: git< 0000
在 Git 收到路径名后,它将再次请求相应的 blob。 这些请求包含一个路径名和一个空内容部分。 过滤器应以上述通常方式返回经过涂抹的内容。
packet: git> command=smudge packet: git> pathname=path/testfile.dat packet: git> 0000 packet: git> 0000 # empty content! packet: git< status=success packet: git< 0000 packet: git< SMUDGED_CONTENT packet: git< 0000 packet: git< 0000 # empty list, keep "status=success" unchanged!
示例
可以在 Git 核心仓库的 contrib/long-running-filter/example.pl
中找到一个长时间运行的过滤器演示实现。 如果您开发自己的长时间运行的过滤器进程,那么 GIT_TRACE_PACKET
环境变量对于调试非常有用(请参阅 git[1])。
请注意,您不能将现有的 filter.<driver>.clean
或 filter.<driver>.smudge
命令与 filter.<driver>.process
一起使用,因为前两者使用不同的进程间通信协议。
签入/签出属性之间的交互
在签入代码路径中,工作区文件首先使用 filter
驱动程序进行转换(如果已指定并定义了相应的驱动程序),然后使用 ident
处理结果(如果已指定),最后使用 text
处理结果(同样,如果已指定并适用)。
在签出代码路径中,blob 内容首先使用 text
进行转换,然后使用 ident
,并提供给 filter
。
合并具有不同签入/签出属性的分支
如果您已将属性添加到某个文件,导致该文件的规范存储库格式发生更改,例如添加了 clean/smudge 过滤器或 text/eol/ident 属性,那么合并任何没有该属性的内容通常会导致合并冲突。
为了防止这些不必要的合并冲突,可以告诉 Git 对每个需要三向内容合并的文件的所有三个阶段运行虚拟签出和签入,方法是设置 merge.renormalize
配置变量。 这可以防止因签入转换引起的更改在合并已转换文件和未转换文件时导致虚假的合并冲突。
只要 "smudge→clean" 产生的结果与 "clean" 相同,即使在已经经过涂抹的文件上,此策略也会自动解决所有与过滤器相关的冲突。 以这种方式不执行操作的过滤器可能会导致必须手动解决的额外合并冲突。
生成 diff 文本
diff
属性 diff
影响 Git 如何为特定文件生成差异。 它可以告诉 Git 是为路径生成文本补丁,还是将路径视为二进制文件。 它还可以影响在 hunk 标头 @@ -k,l +n,m @@
行上显示哪一行,告诉 Git 使用外部命令生成差异,或要求 Git 在生成差异之前将二进制文件转换为文本格式。
- 设置
-
设置了
diff
属性的路径被视为文本,即使它们包含通常永远不会出现在文本文件中的字节值,例如 NUL。 - 取消设置
-
取消设置了
diff
属性的路径将生成Binary files differ
(或者二进制补丁,如果启用了二进制补丁)。 - 未指定
-
未指定
diff
属性的路径首先会检查其内容,如果它看起来像文本并且小于 core.bigFileThreshold,则将其视为文本。 否则它会生成Binary files differ
。 - 字符串
-
差异使用指定的 diff 驱动程序显示。 每个驱动程序可以指定一个或多个选项,如下节所述。 diff 驱动程序 "foo" 的选项由 Git 配置文件中 "diff.foo" 部分的配置变量定义。
定义外部差异驱动程序
差异驱动程序的定义是在 gitconfig
中完成的,而不是在 gitattributes
文件中,所以严格来说,本手册页是不应该谈论它的。 但是……
要定义一个外部差异驱动程序 jcdiff
,请向您的 $GIT_DIR/config
文件(或 $HOME/.gitconfig
文件)添加一个像这样的部分
[diff "jcdiff"] command = j-c-diff
当 Git 需要显示 diff
属性设置为 jcdiff
的路径的差异时,它会使用上述配置调用您指定的命令,即 j-c-diff
,带有 7 个参数,就像调用 GIT_EXTERNAL_DIFF
程序一样。 有关详细信息,请参阅 git[1]。
如果程序能够忽略某些更改(类似于 git diff --ignore-space-change
),那么也请将选项 trustExitCode
设置为 true。 如果它发现重大更改,则预计返回退出代码 1,如果没有发现,则返回 0。
设置内部差异算法
差异算法可以通过 diff.algorithm
配置键设置,但有时按路径设置差异算法可能会很有用。 例如,可能希望对 .json 文件使用 minimal
差异算法,对 .c 文件使用 histogram
,等等,而无需每次都通过命令行传入算法。
首先,在 .gitattributes
中,为路径分配 diff
属性。
*.json diff=<name>
然后,定义一个 "diff.<name>.algorithm" 配置来指定差异算法,从 myers
、patience
、minimal
或 histogram
中选择。
[diff "<name>"] algorithm = histogram
此差异算法适用于面向用户的差异输出,如 git-diff(1)、git-show(1),也用于 --stat
输出。 合并机制将不会使用通过此方法设置的差异算法。
注意
|
如果为具有 diff=<name> 属性的路径定义了 diff.<name>.command ,则它将作为外部差异驱动程序执行(参见上文),添加 diff.<name>.algorithm 没有效果,因为该算法不会传递给外部差异驱动程序。 |
定义自定义 hunk 标头
文本差异输出中的每个更改组(称为 "hunk")都以以下形式的行作为前缀
@@ -k,l +n,m @@ TEXT
这被称为hunk 标头。"TEXT" 部分默认是一行,以字母、下划线或美元符号开头; 这与 GNU diff -p 输出使用的相匹配。 然而,这种默认选择不适合某些内容,您可以使用自定义模式来进行选择。
首先,在 .gitattributes 中,您将为路径分配 diff
属性。
*.tex diff=tex
然后,您将定义一个 "diff.tex.xfuncname" 配置来指定一个正则表达式,该表达式与您希望显示为 hunk 标头 "TEXT" 的行匹配。 向您的 $GIT_DIR/config
文件(或 $HOME/.gitconfig
文件)添加一个像这样的部分
[diff "tex"] xfuncname = "^(\\\\(sub)*section\\{.*)$"
注意:配置文件的解析器会吃掉单层反斜杠,因此您需要将反斜杠加倍; 上面的模式选择一个以反斜杠开头的行,以及零个或多个出现的 sub
,后跟 section
,后跟左大括号,直到行尾。
有一些内置模式可以简化此操作,而 tex
就是其中之一,因此您不必在配置文件中编写上述内容(您仍然需要通过属性机制,通过 .gitattributes
来启用此功能)。 以下内置模式可用
-
ada
适用于 Ada 语言的源代码。 -
bash
适用于 Bourne-Again SHell 语言的源代码。 涵盖了 POSIX shell 函数定义的超集。 -
bibtex
适用于包含 BibTeX 编码引用的文件。 -
cpp
适用于 C 和 C++ 语言的源代码。 -
csharp
适用于 C# 语言的源代码。 -
css
适用于层叠样式表。 -
dts
适用于设备树 (DTS) 文件。 -
elixir
适用于 Elixir 语言的源代码。 -
fortran
适用于 Fortran 语言的源代码。 -
fountain
适用于 Fountain 文档。 -
golang
适用于 Go 语言的源代码。 -
html
适用于 HTML/XHTML 文档。 -
java
适用于 Java 语言的源代码。 -
kotlin
适用于 Kotlin 语言的源代码。 -
markdown
适用于 Markdown 文档。 -
matlab
适用于 MATLAB 和 Octave 语言的源代码。 -
objc
适用于 Objective-C 语言的源代码。 -
pascal
适用于 Pascal/Delphi 语言的源代码。 -
perl
适用于 Perl 语言的源代码。 -
php
适用于 PHP 语言的源代码。 -
python
适用于 Python 语言的源代码。 -
ruby
适用于 Ruby 语言的源代码。 -
rust
适用于 Rust 语言的源代码。 -
scheme
适用于 Scheme 语言的源代码。 -
tex
适用于 LaTeX 文档的源代码。
自定义单词差异
你可以自定义 git diff --word-diff
用来分割一行中单词的规则,通过在 "diff.*.wordRegex" 配置变量中指定合适的正则表达式。例如,在 TeX 中,反斜杠后跟一系列字母组成一个命令,但多个这样的命令可以不带空格地运行在一起。要分隔它们,可以在你的 $GIT_DIR/config
文件(或 $HOME/.gitconfig
文件)中使用如下的正则表达式:
[diff "tex"] wordRegex = "\\\\[a-zA-Z]+|[{}]|\\\\.|[^\\{}[:space:]]+"
为前一节中列出的所有语言提供了内置模式。
执行二进制文件的文本差异
有时,希望看到一些二进制文件的文本转换版本的差异。 例如,可以将文字处理器文档转换为 ASCII 文本表示形式,并显示该文本的差异。 即使此转换会丢失一些信息,但生成的差异对于人工查看仍然很有用(但不能直接应用)。
textconv
配置选项用于定义执行此类转换的程序。 该程序应采用一个参数,即要转换的文件的名称,并在 stdout 上生成结果文本。
例如,要显示文件的 exif 信息而不是二进制信息(假设你已安装 exif 工具),请将以下部分添加到你的 $GIT_DIR/config
文件(或 $HOME/.gitconfig
文件):
[diff "jpg"] textconv = exif
注意
|
文本转换通常是单向转换;在此示例中,我们失去了实际的图像内容,而只关注文本数据。 这意味着 textconv 生成的差异不适合应用。 因此,只有 git diff 和 git log 命令系列(即,log,whatchanged,show)才会执行文本转换。 git format-patch 永远不会生成此输出。 如果你想向某人发送二进制文件的文本转换差异(例如,因为它能快速传达你所做的更改),则应单独生成它,并将其作为注释附加到你可能发送的常规二进制差异。 |
由于文本转换可能很慢,尤其是在使用 git log -p
进行大量文本转换时,Git 提供了一种机制来缓存输出并在以后的差异中使用它。 要启用缓存,请在差异驱动程序的配置中设置 "cachetextconv" 变量。 例如:
[diff "jpg"] textconv = exif cachetextconv = true
这将无限期地缓存对每个 blob 运行 "exif" 的结果。 如果你更改了差异驱动程序的 textconv 配置变量,Git 将自动使缓存条目无效并重新运行 textconv 过滤器。 如果你想手动使缓存无效(例如,因为你的 "exif" 版本已更新,现在可以生成更好的输出),则可以使用 git update-ref -d refs/notes/textconv/jpg
手动删除缓存(其中 "jpg" 是差异驱动程序的名称,如上例所示)。
选择 textconv 还是外部差异
如果要在存储库中显示二进制或特殊格式 blob 之间的差异,可以选择使用外部 diff 命令,或者使用 textconv 将它们转换为可差异的文本格式。 你选择哪种方法取决于你的具体情况。
使用外部 diff 命令的优点是灵活性。 你不必局限于查找面向行的更改,也不需要输出类似于统一差异。 你可以自由地找到并报告最适合你的数据格式的更改。
相比之下,textconv 的限制要大得多。 你提供数据到面向行的文本格式的转换,Git 使用其常规差异工具来生成输出。 选择此方法有几个优点:
-
易于使用。 编写二进制到文本转换通常比执行你自己的差异要简单得多。 在许多情况下,现有程序可以用作 textconv 过滤器(例如,exif、odt2txt)。
-
Git 差异功能。 通过仅执行转换步骤,你仍然可以使用 Git 的许多差异功能,包括着色、单词差异以及合并的组合差异。
-
缓存。 Textconv 缓存可以加快重复差异的速度,例如你可能通过运行
git log -p
触发的差异。
将文件标记为二进制文件
Git 通常通过检查内容的开头来正确猜测 blob 是否包含文本或二进制数据。 但是,有时你可能想要覆盖它的决定,要么是因为 blob 在文件的后面包含二进制数据,要么是因为内容虽然在技术上由文本字符组成,但对于人类读者来说是不透明的。 例如,许多 postscript 文件仅包含 ASCII 字符,但会产生嘈杂且无意义的差异。
将文件标记为二进制文件的最简单方法是取消设置 .gitattributes
文件中的 diff 属性:
*.ps -diff
这将导致 Git 生成 Binary files differ
(如果启用了二进制补丁,则生成二进制补丁)而不是常规差异。
但是,也可能需要指定其他差异驱动程序属性。 例如,你可能想要使用 textconv
将 postscript 文件转换为 ASCII 表示形式以供人工查看,但在其他情况下将其视为二进制文件。 你不能同时指定 -diff
和 diff=ps
属性。 解决方案是使用 diff.*.binary
配置选项:
[diff "ps"] textconv = ps2ascii binary = true
执行三向合并
merge
当在 git merge
以及其他命令如 git revert
和 git cherry-pick
中需要进行文件级别的合并时,merge
属性会影响如何合并文件的三个版本。
- 设置
-
内置的三向合并驱动程序用于以类似于
RCS
套件的 *merge* 命令的方式合并内容。 这适用于普通的文本文件。 - 取消设置
-
从当前分支获取版本作为临时合并结果,并声明合并存在冲突。 这适用于没有明确定义的合并语义的二进制文件。
- 未指定
-
默认情况下,这使用与设置
merge
属性时相同的内置三向合并驱动程序。 但是,merge.default
配置变量可以命名不同的合并驱动程序,用于未指定merge
属性的路径。 - 字符串
-
三向合并使用指定的自定义合并驱动程序执行。 可以通过请求 "text" 驱动程序来显式指定内置的三向合并驱动程序;可以使用 "binary" 请求内置的 "采用当前分支" 驱动程序。
定义自定义合并驱动程序
合并驱动程序的定义在 .git/config
文件中完成,而不是在 gitattributes
文件中完成,因此严格来说,本手册页不适合讨论它。 然而……
要定义自定义合并驱动程序 filfre
,请将一个部分添加到你的 $GIT_DIR/config
文件(或 $HOME/.gitconfig
文件),如下所示:
[merge "filfre"] name = feel-free merge driver driver = filfre %O %A %B %L %P recursive = binary
merge.*.name
变量为驱动程序提供了一个人类可读的名称。
merge.*.driver
变量的值用于构造一个命令来运行公共祖先的版本 (%O
)、当前版本 (%A
) 和其他分支的版本 (%B
)。 构建命令行时,这三个令牌将替换为包含这些版本内容的临时文件的名称。 此外,%L
将替换为冲突标记大小(见下文)。
合并驱动程序应通过覆盖操作将合并结果保留在以 %A
命名的文件中,如果能够干净地合并它们,则以零状态退出;如果存在冲突,则以非零状态退出。 当驱动程序崩溃(例如,被 SEGV 终止)时,预计它将以高于 128 的非零状态退出,在这种情况下,合并会导致失败(这与产生冲突不同)。
merge.*.recursive
变量指定在调用合并驱动程序以进行公共祖先之间的内部合并时,在有多个公共祖先的情况下,要使用哪个其他合并驱动程序。 如果未指定,则驱动程序本身将用于内部合并和最终合并。
合并驱动程序可以通过占位符 %P
了解合并结果将存储在其中的路径名。 可以分别使用 %S
、%X
和 %Y
传递用于公共祖先、本地头和其他头的冲突标签。
检查空格错误
whitespace
core.whitespace
配置变量允许你定义 *diff* 和 *apply* 应该将什么视为空格错误,适用于项目中的所有路径(请参阅 git-config[1])。 此属性为你提供每个路径更精细的控制。
创建归档
export-subst
如果文件设置了 export-subst
属性,那么 Git 在将此文件添加到归档时将展开几个占位符。展开取决于提交 ID 的可用性,即如果 git-archive[1] 被赋予一个树而不是一个提交或标签,那么将不会进行替换。这些占位符与 git-log[1] 的 --pretty=format:
选项相同,除了它们需要像这样被包裹起来:文件中的 $Format:PLACEHOLDERS$
。例如,字符串 $Format:%H$
将被提交哈希替换。但是,每个归档文件只展开一个 %(describe)
占位符,以避免拒绝服务攻击。
在 GUI 工具中查看文件
encoding
此属性的值指定 GUI 工具(例如 gitk[1] 和 git-gui[1])应该用来显示相关文件内容的字符编码。请注意,由于性能考虑,除非您手动在其选项中启用每个文件的编码,否则 gitk[1] 不会使用此属性。
如果未设置此属性或其值无效,则将改用 gui.encoding
配置变量的值(请参阅 git-config[1])。
使用宏属性
您不希望将任何行尾转换应用于您跟踪的任何二进制文件,也不希望生成文本差异。你需要指定,例如:
*.jpg -text -diff
但是当您有很多属性时,这可能会变得很麻烦。 使用宏属性,您可以定义一个属性,当设置该属性时,也会同时设置或取消设置许多其他属性。 系统知道一个内置的宏属性,binary
*.jpg binary
设置 "binary" 属性也会取消设置如上的 "text" 和 "diff" 属性。 请注意,宏属性只能 "设置",尽管设置一个属性可能会产生设置或取消设置其他属性,甚至将其他属性返回到 "未指定" 状态的效果。
定义宏属性
自定义宏属性只能在顶级 gitattributes 文件 ($GIT_DIR/info/attributes
, 工作树顶层的 .gitattributes
文件,或者全局或系统范围的 gitattributes 文件) 中定义,而不能在工作树子目录中的 .gitattributes
文件中定义。 内置宏属性 "binary" 等同于
[attr]binary -diff -merge -text
示例
如果您有以下三个 gitattributes
文件
(in $GIT_DIR/info/attributes) a* foo !bar -baz (in .gitattributes) abc foo bar baz (in t/.gitattributes) ab* merge=filfre abc -foo -bar *.c frotz
赋予路径 t/abc
的属性计算如下
-
通过检查
t/.gitattributes
(它与所讨论的路径位于同一目录中),Git 发现第一行匹配。merge
属性被设置。 它还发现第二行匹配,并且属性foo
和bar
被取消设置。 -
然后它检查
.gitattributes
(它位于父目录中),并发现第一行匹配,但是t/.gitattributes
文件已经决定了应该如何将merge
、foo
和bar
属性赋予此路径,因此它保留foo
和bar
取消设置的状态。 属性baz
被设置。 -
最后,它检查
$GIT_DIR/info/attributes
。 此文件用于覆盖树内设置。 第一行是一个匹配,并且foo
被设置,bar
恢复到未指定状态,并且baz
被取消设置。
因此,t/abc
的属性分配变为
foo set to true bar unspecified baz set to false merge set to string value "filfre" frotz unspecified