gitattributes

优质
小牛编辑
123浏览
2023-12-01

名称

gitattributes - 定义每个路径的属性

概要

$GIT_DIR/info/attributes, .gitattributes

描述

一个gitattributes文件是一个给attributes路径名的简单文本文件。

gitattributes文件中的每一行都是以下格式:

pattern        attr1 attr2 ...

也就是说,一个模式后跟一个属性列表,由空格分隔。前导空白和尾随空白被忽略。开头的行#被忽略。以双引号开头的模式以 C 风格引用。当模式与所讨论的路径相匹配时,行中列出的属性被赋予路径。

对于给定路径,每个属性可以处于以下状态之一:

Set

该路径具有特殊值“true”的属性; 这是通过仅列出属性列表中属性的名称来指定的。

Unset

路径具有特殊值“false”的属性; 这是通过列出-在属性列表中以短划线为前缀的属性的名称来指定的。

Set to a value

路径具有指定字符串值的属性; 这是通过=在属性列表中列出属性的名称,后跟等号和其值来指定的。

Unspecified

没有模式匹配路径,并且没有任何说明路径是否具有该属性,路径的属性被称为未指定。

当多于一个模式匹配路径时,稍后的一行覆盖较早的一行。这个重写是按属性完成的。模式如何匹配路径的规则与.gitignore文件中的相同;见 gitignore [5]。不像.gitignore,消极的模式是禁止的。

当决定哪些属性被分配给一个路径时,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 checkoutgit merge运行。它们也会影响 Git 如何将存储在库中工作树中的内容存储在git addgit commit之上。

text

该属性启用并控制行结束标准化。当一个文本文件被标准化时,它的行尾将在存储库中转换为 LF。要控制工作目录中使用的行结束风格,请使用单个文件的eol属性和所有文本文件的core.eol配置变量。请注意,core.autocrlf覆盖core.eol

Set

text在路径上设置属性可启用行结束标准化并将路径标记为文本文件。换行转换不需要猜测内容类型。

Unset

取消设置text路径上的属性会告诉 Git 在签入或结帐时不要尝试任何换行转换。

Set to string value "auto"

text设置为“自动”时,该路径被标记为自动换行结束。如果 Git 确定内容是文本,则它的行尾在登记时会转换为 LF。用 CRLF 提交文件时,不进行转换。

Unspecified

如果text属性未指定,Git 使用core.autocrlf配置变量来确定文件是否应该转换。

任何其他值都会导致 Git 去扮演就像text未被指定一样。

eol

该属性设置了要在工作目录中使用的特定行结束样式。它可以在没有任何内容检查的情况下实现行尾转换,从而有效地设置text属性。请注意,在具有 CRLF 行结尾的索引中的路径上设置此属性可能会使路径被认为是脏的。再次将路径添加到索引将标准化索引中的行尾。

Set to string value "crlf"

此设置强制 Git 在签入时对该文件的行结束进行标准化,并在文件签出时将其转换为 CRLF。

Set to string value "lf"

此设置强制 Git 在签入时将行尾标准化为 LF,并在签出文件时阻止转换为 CRLF。

向后兼容crlf属性

为了向后兼容,该crlf属性被解释如下:

crlf                text-crlf                -text
crlf=input        eol=lf

换行结束

虽然 Git 通常只保留文件内容,但可以将其配置为在存储库中将行尾标准化为 LF,并可选择将文件检出时转换为 CRLF。

如果您只是想在工作目录中拥有 CRLF 行结束符,而不考虑您正在使用的存储库,则可以在不使用任何属性的情况下设置配置变量“core.autocrlf”。

[core]
        autocrlf = true

这不会强制对文本文件进行标准化,但会确保引入到存储库的文本文件的行结束符在添加时标准化为 LF,并且存储库中已经标准化的文件保持标准化。

如果您想确保任何贡献者向存储库引入的文本文件的行结束都已标准化,则可以将all文件的text属性设置为“自动” all

*        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

注意

当使用推送到中央存储库的跨平台项目中启用 text = auto 转换时,应该对包含 CRLF 的文本文件进行规范化。

从一个干净的工作目录:

$ echo "* text=auto" >.gitattributes
$ git read-tree --empty   # Clean index, force re-scan of working directory
$ git add .$ 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设置是否可逆。对于“真实”,Git 拒绝不可逆转的转换; 对于“警告”,Git 仅打印警告,但接受不可逆转的转换。安全触发器阻止对工作树中的文件执行这种转换,但有一些例外。即使...

  • git add 本身不会触摸工作树中的文件,下一次检出会触发安全触发器;
  • git apply 使用补丁更新文本文件确实会触摸工作树中的文件,但操作是关于文本文件和 CRLF 转换是关于修复行结束的不一致性,因此安全性不会触发;
  • git diff本身不会触摸工作树中的文件,它通常会运行以检查您打算接下来的git add更改。为了及早发现潜在的问题,安全触发器。

ident

ident为路径设置属性时,Git 用blob对象中的$Id:替换$Id$,后面跟着40个字符的十六进制 blob 对象名称,后面跟着美元符号$。任何以worktree文件开头$Id:和结尾的字节序列$在登记时被$Id$替换。

filter

一个filter属性可以设置为一个字符串值,用于命名配置中指定的过滤器驱动程序。

过滤器驱动程序由一个clean命令和一个smudge命令组成,其中任何一个都可以不指定。结帐时,当smudge指定命令时,该命令从其标准输入中输入blob对象,其标准输出用于更新工作树文件。同样,该clean命令用于在签入时转换工作文件的内容。默认情况下,这些命令只处理一个blob并终止。例如git add --all,如果使用长时间运行的process过滤器来替代clean和/或smudge过滤器,则例如,Git 可以在单个Git 命令的整个生命周期内通过单个过滤器命令调用来处理所有 blob 。如果长时间运行process过滤器配置,那么它始终优先于配置的单个 blob 过滤器。有关用于与process过滤器通信的协议的说明,请参阅下面的部分。

内容过滤的一个用途是将内容按摩成更适合平台,文件系统和用户使用的形状。对于这种操作模式,这里的关键词是“更方便”,而不是“把某些不可用的东西变成可用的”。换句话说,目的是如果某人取消了过滤器驱动程序的定义,或者没有合适的过滤器程序,该项目仍然可以使用。

内容过滤的另一个用途是存储不能直接在存储库中使用的内容(例如,引用 Git 外部存储的真实内容的 UUID 或加密的内容),并在结帐时将其转换为可用的形式(例如下载外部内容或解密加密的内容)。

这两个过滤器的行为不同,默认情况下,过滤器被视为前者,将内容按摩到更方便的形状。配置中缺少的过滤器驱动程序定义或以非零状态退出的过滤器驱动程序不是错误,而是使过滤器成为无操作中继。

您可以声明过滤器通过将过滤器<driver> .需要配置变量设置为true,将本身不可用的内容转换为可用内容。

例如,在.gitattributes 中,您可以为路径分配filter属性。

*.c        filter=indent

然后,您可以在.git / config 中定义一个“filter.indent.clean”和“filter.indent.smudge”配置来指定一对命令,以在源文件签入时修改C程序的内容(“clean “运行)并检出(因为命令是”cat“,所以不做任何更改)。

[filter "indent"]
        clean = indent
        smudge = cat

为了获得最佳效果,clean如果运行两次(“清洁→清洁”应该相当于“清洁”),并且多个smudge命令不应该改变clean输出(“污迹→污迹→清洁”应当相当以“清洁”)。请参阅下面的合并部分。

“indent”过滤器在这方面表现良好:它不会修改已经正确缩进的输入。在这种情况下,缺少污迹过滤器意味着干净的过滤器must接受自己的输出而不修改它。

如果过滤器must成功以使存储的内容可用,则可以在配置中声明过滤器是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。这是通过使用基于标准输入和标准输出的数据包格式(pkt-line,参见technical / protocol-common.txt)来实现的,如下所示。除“* CONTENT”数据包和“0000”清除数据包之外的所有数据包都被视为文本,因此以LF结尾。

Git在遇到需要清理或弄脏的第一个文件时启动过滤器。过滤器启动后,Git 发送一个欢迎消息(“git-filter-client”),一个支持的协议版本号列表和一个 flush 数据包。Git希望从先前发送的列表中读取一个欢迎响应消息(“git-filter-server”),一个协议版本号和一个 flush 数据包。所有进一步的沟通将基于选定的版本。下面的其余协议描述文档“version= 2”。请注意,以下示例中的“version = 42”不存在,仅用于说明协议在多个版本中的外观。

版本协商之后,Git 发送它支持的所有功能和清除数据包的列表。Git 希望读取所需功能的列表,该列表必须是支持的功能列表的一个子集,以及作为响应的 flush 数据包:

packet:          git> git-filter-client
packet:          git> version=2packet:          git> version=42packet:          git> 0000packet:          git< git-filter-server
packet:          git< version=2packet:          git< 0000packet:          git> capability=clean
packet:          git> capability=smudge
packet:          git> capability=not-yet-invented
packet:          git> 0000packet:          git< capability=clean
packet:          git< capability=smudge
packet:          git< 0000

版本2中支持的过滤器功能是“干净”,“污迹”和“延迟”( "clean", "smudge", and "delay")。

之后,Git 发送一个以 flush 数据包结尾的“key = value”对的列表。该列表将至少包含 filter 命令(基于支持的功能)以及要相对于存储库根目录过滤的文件的路径名。在冲洗数据包之后,Git 发送分割零或多个 pkt-line 数据包的内容和一个 flush 数据包来终止内容。请注意,过滤器在收到内容和最终清除数据包之前不得发送任何响应。另请注意,“key = value”对的“值”可以包含“=”字符,而该键不会包含该字符。

packet:          git> command=smudge
packet:          git> pathname=path/testfile.dat
packet:          git> 0000packet:          git> CONTENT
packet:          git> 0000

预计过滤器将以一个以“flush =”数据包结尾的“key = value”对列表作为响应。如果过滤器没有遇到问题,则列表必须包含“成功”状态。在这些数据包之后,过滤器应该在零或多个 pkt-line 数据包中发送内容,并在最后发送一个flush数据包。最后,预计会有一个以 flush 数据包结尾的“key = value”对的第二个列表。过滤器可以更改第二个列表中的状态或保持状态为空列表。请注意,空列表必须以 flush 数据包终止,无论如何。

packet:          git< status=success
packet:          git< 0000packet:          git< SMUDGED_CONTENT
packet:          git< 0000packet:          git< 0000  # empty list, keep "status=success" unchanged!

如果结果内容为空,则预计过滤器将以“成功”状态和清除数据包来响应空信息。

packet:          git< status=success
packet:          git< 0000packet:          git< 0000  # empty content!packet:          git< 0000  # empty list, keep "status=success" unchanged!

如果过滤器不能或不想处理内容,则预期会以“错误”状态进行响应。

packet:          git< status=error
packet:          git< 0000

如果过滤器在处理过程中遇到错误,则可以在内容(部分或完全)发送后发送状态“错误”。

packet:          git< status=success
packet:          git< 0000packet:          git< HALF_WRITTEN_ERRONEOUS_CONTENT
packet:          git< 0000packet:          git< status=error
packet:          git< 0000

如果过滤器无法或不想处理内容以及 Git 进程生命周期内的任何未来内容,则预计会在协议中的任何时间以“中止”状态进行响应。

packet:          git< status=abort
packet:          git< 0000

如果设置了“错误”/“中止”状态,Git 既不停止也不重新启动过滤器进程。但是,Git 根据filter.<driver>.required标志设置退出代码,模仿filter.<driver>.clean/ filter.<driver>.smudge机制的行为。

如果过滤器在通信过程中死亡或者不遵守协议,则 Git 将停止过滤器过程,并使用下一个需要处理的文件重新启动它。根据filter.<driver>.required标志,Git会将其解释为错误。

过滤器处理完一个命令后,需要等待包含下一个命令的“key = value”列表。Git 会在退出时关闭命令管道。预计过滤器会检测 EOF 并自行退出。Git 将等待,直到过滤器进程停止。

延迟

如果过滤器支持“延迟”功能,则 Git 可以在过滤器命令和路径名后面发送“can-delay”标志。这个标志表示过滤器可以通过没有内容但响应状态“延迟”和清除数据包来延迟过滤当前 blob(例如以补偿网络等待时间)。

packet:          git> command=smudge
packet:          git> pathname=path/testfile.dat
packet:          git> can-delay=1packet:          git> 0000packet:          git> CONTENT
packet:          git> 0000packet:          git< status=delayed
packet:          git< 0000

如果过滤器支持“延迟”功能,那么它必须支持“list_available_blobs”命令。如果Git发送这个命令,那么过滤器应该会返回一个路径名列表,这些路径名代表早先被延迟并且现在可用的斑点。该列表必须以 flush 数据包结尾,后跟“success”状态,该数据也以 flush 数据包终止。如果没有用于延迟路径的斑点可用,则过滤器预计将阻止该响应,直到至少有一个斑点可用。过滤器可以通过发送一个空列表来告诉 Git 它没有更多的延迟斑点。只要过滤器响应一个空的列表,Git 就会停止询问。此时 Git 尚未收到的所有斑点都将被视为丢失,并会导致错误。

packet:          git> command=list_available_blobs
packet:          git> 0000packet:          git< pathname=path/testfile.dat
packet:          git< pathname=path/otherfile.dat
packet:          git< 0000packet:          git< status=success
packet:          git< 0000

After Git received the pathnames, it will request the corresponding blobs again. These requests contain a pathname and an empty content section. The filter is expected to respond with the smudged content in the usual way as explained above.

packet:          git> command=smudge
packet:          git> pathname=path/testfile.dat
packet:          git> 0000packet:          git> 0000  # empty content!packet:          git< status=success
packet:          git< 0000packet:          git< SMUDGED_CONTENT
packet:          git< 0000packet:          git< 0000  # empty list, keep "status=success" unchanged!

示例

长时间运行的过滤器演示实现可以在contrib/long-running-filter/example.pl位于 Git 核心存储库中找到。如果您开发自己的长时间运行的过滤器进程,那么GIT_TRACE_PACKET环境变量对调试非常有帮助(请参阅 git [1])。

请注意,由于前两者使用不同的进程间通信协议,因此不能使用现有filter.<driver>.cleanfilter.<driver>.smudge命令filter.<driver>.process

签入/签出属性之间的交互

在签入代码路径中,首先使用filter驱动程序(如果指定了相应的驱动程序并将其定义)转换为工作树文件,那么使用ident(如果已指定)处理结果,然后使用text(如果指定并适用,则再次)处理结果。

在签出代码路径中,blob 内容首先被text转换,然后被ident提交filter

合并具有不同签入/签出属性的分支

如果您已将属性添加到导致该文件的规范存储库格式发生更改的文件(如添加干净/污迹过滤器或 text / eol / ident 属性),那么合并属性不在位的任何东西通常会导致合并冲突。

为了防止这些不必要的合并冲突,可以通过设置merge.renormalize配置变量来解决三向合并问题时,可以让 Git 运行虚拟检出和检入文件的所有三个阶段。这样可以防止转换文件与未转换文件合并时由检入转换引起的更改导致虚假合并冲突。

只要“污迹→清理”与“干净”相同,即使对已经被污染的文件也会产生相同的输出,此策略将自动解决所有与过滤器有关的冲突。不以这种方式操作的过滤器可能会导致额外的合并冲突,必须手动解决。

生成差异文本

diff

该属性diff影响 Git 如何为特定文件生成差异。它可以告诉 Git 是为路径生成文本补丁还是将路径视为二进制文件。它也可以影响在 Hunk 标题@@ -k,l +n,m @@行上显示的行,告诉 Git 使用外部命令来生成 diff,或者在生成 diff 之前让 Git 将二进制文件转换为文本格式。

Set

diff属性设置的路径视为文本,即使它们包含通常从不出现在文本文件中的字节值(例如 NUL)。

Unset

diff属性未设置的路径将生成Binary files differ(如果启用了二进制修补程序,则会生成二进制修补程序)。

Unspecified

diff首先未指定属性的路径将检查其内容,如果它看起来像文本且小于 core.bigFileThreshold,则将其视为文本。否则会产生Binary files differ

String

Diff 使用指定的 diff 驱动程序显示。每个驱动程序可以指定一个或多个选项,如以下部分所述。diff 驱动程序“foo”的选项由 Git 配置文件的“diff.foo”部分中的配置变量定义。

定义一个外部差异驱动程序

差异驱动程序的定义是在gitconfig,而非gitattributes文件中完成的,所以严格来说,这个手册页是一个错误的地方来谈论它。然而...

要定义一个外部差异驱动程序jcdiff,添加一个部分到你的$GIT_DIR/config文件(或$HOME/.gitconfig文件),像这样:

[diff "jcdiff"]
        command = j-c-diff

当 Git 需要向diff属性设置为jcdiff的路径显示 diff 时,它会调用您使用上述配置指定的命令,即j-c-diff使用7个参数,就像GIT_EXTERNAL_DIFF调用程序一样。有关详细信息,请参阅 git [1]。

定义一个自定义的 hunk-header

文本差异输出中的每组变化(称为“大块”)都以以下格式的行作为前缀:

@@ -k,l +n,m @@ TEXT

这被称为a hunk header。默认情况下,“TEXT”部分是以字母,下划线或美元符号开头的行; 这匹配了 GNU diff -p输出使用的内容。但是,此默认选择不适用于某些内容,您可以使用自定义模式进行选择。

首先,在.gitattributes 中,您将为diff路径分配属性。

*.tex        diff=tex

然后,您将定义一个“diff.tex.xfuncname”配置来指定一个正则表达式,该正则表达式与您希望显示为大块头“TEXT”的行匹配。添加一个部分到你的$GIT_DIR/config文件(或$HOME/.gitconfig文件),像这样:

[diff "tex"]
        xfuncname = "^(\\\\(sub)*section\\{.*)$"

注意。配置文件解析器会使用单级反斜杠,因此您需要将反斜杠加倍; 上面的模式选择一行以反斜杠开始的行,以及零个或多个出现的sub紧跟着section的开放大括号,直到行尾。

有一些内置模式可以使这更容易,并且tex是其中之一,所以您不必在配置文件中编写上述内容(您仍然需要使用属性机制来启用它,通过.gitattributes)。以下内置模式可用:

  • ada 适用于 Ada 语言的源代码。
  • bibtex 适用于带有 BibTeX 编码参考的文件。
  • cpp 适用于 C和C ++语言的源代码。
  • csharp 适用于 C#语言的源代码。
  • css 适合级联样式表。
  • fortran 适用于 Fortran 语言的源代码。
  • fountain 适合喷泉文件。
  • html 适用于 HTML / XHTML 文档。
  • java 适用于 Java 语言的源代码。
  • matlab 适用于 MATLAB 语言的源代码。
  • objc 适用于 Objective-C 语言的源代码。
  • pascal 适用于 Pascal / Delphi 语言的源代码。
  • perl 适用于 Perl 语言的源代码。
  • php 适用于 PHP 语言的源代码。
  • python 适用于 Python 语言的源代码。
  • ruby 适用于 Ruby 语言的源代码。
  • 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 提供了一种缓存输出并在未来差异中使用它的机制。要启用缓存,请在 diff 驱动程序的配置中设置“cachetextconv”变量。例如:

[diff "jpg"]
        textconv = exif
        cachetextconv = true

这将无限期地缓存每个 blob 上运行“exif”的结果。如果您更改 diff 驱动程序的 textconv 配置变量,Git 将自动使缓存项无效并重新运行 textconv 过滤器。如果您想手动使缓存失效(例如,因为您的“exif”版本已更新,现在可以产生更好的输出),您可以手动删除缓存git update-ref -d refs/notes/textconv/jpg(其中“jpg”是 diff 驱动程序的名称,如上面的例子)。

选择 textconv 与外部差异

如果要显示存储库中二进制或特殊格式的斑点之间的差异,可以选择使用外部 diff 命令,或使用 textconv 将它们转换为可区分的文本格式。您选择哪种方法取决于您的具体情况。

使用外部 diff 命令的优点是灵活性。您不一定会发现面向行的更改,也不一定需要输出类似统一差异。您可以自由地以最适合您数据格式的方式查找和报告更改。

相比之下,textconv 更受限制。您将数据转换为面向行的文本格式,Git 使用其常规差异工具生成输出。选择此方法有几个优点:

  1. 使用方便。编写二进制文本转换通常要比执行自己的diff更简单。在很多情况下,现有的程序可以用作 textconv 过滤器(例如,exif,odt2txt)。
  2. Git diff 功能。通过自己执行转换步骤,您仍然可以使用许多Git的差异功能,包括着色,文字差异和组合差异进行合并。
  3. 缓存。Textconv 缓存可以加速重复的差异,比如可能通过运行git log -p触发的差异。

将文件标记为二进制文件

Git 通常会通过检查内容的开始来正确猜测 blob 是否包含文本或二进制数据。但是,有时您可能想要覆盖其决定,要么是因为 blob 稍后在文件中包含二进制数据,要么是因为在技术上由文本字符组成的内容对于人类读者而言是不透明的。例如,许多 postscript 文件只包含 ASCII 字符,但会产生嘈杂和无意义的差异。

将文件标记为二进制文件的最简单方法是在文件中取消设置 diff 属性.gitattributes

*.ps -diff

这将导致 Git 生成Binary files differ(或二进制补丁,如果启用二进制补丁)而不是常规差异。

但是,也可能需要指定其他diff驱动程序属性。例如,您可能希望使用textconv将 postscript 文件转换为 ASCII 表示以供人类查看,否则将它们视为二进制文件。您不能指定两者-diffdiff=ps属性。解决方案是使用diff.*.binary配置选项:

[diff "ps"]
  textconv = ps2ascii
  binary = true

执行三向合并

merge

该属性merge影响如何在文件级合并过程git merge中合并文件的三个版本,以及其他命令(如git revertgit cherry-pick)。

Set

内置3路合并驱动程序用于以类似于套件merge命令的方式合并内容RCS。这适用于普通的文本文件。

Unset

以当前分支的版本作为暂定合并结果,并声明合并有冲突。这适用于没有明确定义的合并语义的二进制文件。

Unspecified

默认情况下,它使用与merge设置属性时相同的内置3路合并驱动程序。但是,merge.default配置变量可以将不同的合并驱动程序命名为与未指定merge属性的路径一起使用。

String (字符串)

使用指定的自定义合并驱动程序执行3路合并。内置的3路合并驱动程序可以通过询问“文本”驱动程序来明确指定; 内置的“取当前分支”驱动程序可以用“二进制”来请求。

内置合并驱动程序

有几个内置的低级合并驱动程序可以通过merge属性进行定义。

text

文本文件的常用3路文件级别合并。冲突地区标有冲突标记<<<<<<<=======并且>>>>>>>。分支中的版本出现在=======标记之前,并且合并分支中的版本出现在=======标记之后。

二进制

将分支的版本保留在工作树中,但让路径处于冲突状态以供用户整理。

联合

对文本文件运行3路文件级别合并,但从两个版本中取出一行,而不是留下冲突标记。这往往会以随机顺序在结果文件中留下添加的行,并且用户应该验证结果。如果您不了解其含义,请不要使用它。

定义一个自定义合并驱动程序

合并驱动程序的定义是在.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的文件中,如果设法将它们完全合并,则以零状态退出;如果存在冲突,则退出非零。

merge.*.recursive变量指定在共有祖先之间进行内部合并时调用合并驱动程序时要使用的其他合并驱动程序(当存在多个合并驱动程序时)。如果未指定,则驱动程序本身用于内部合并和最终合并。

合并驱动程序可以学习合并结果将通过%P占位符存储的路径名。

conflict-marker-size

此属性控制冲突合并期间工作树文件中留下的冲突标记的长度。只有将值设置为正整数才会产生有意义的效果。

例如,.gitattributes在合并文件Documentation/git-merge.txt导致冲突时,此行可以用于告诉合并机制离开更长的时间(而不是通常的7个字符长)的冲突标记。

Documentation/git-merge.txt        conflict-marker-size=32

检查空白错误

whitespace

core.whitespace配置变量允许您定义diffapply应该考虑项目中的所有路径空白错误(请查看 git-配置[1])。该属性为您提供了更好的每个路径控制。

Set

注意 Git 已知的所有类型的潜在空白错误。选项卡宽度取自core.whitespace配置变量的值。

Unset

没有注意到任何错误。

Unspecified

使用core.whitespace配置变量的值决定要注意的错误。

String

使用与core.whitespace配置变量相同的格式指定逗号分隔的常见空白问题列表。

创建一个档案

export-ignore

具有该属性的文件和目录export-ignore不会被添加到存档文件中。

export-subst

如果该属性export-subst是为一个文件设置的,那么 Git 将在将该文件添加到存档时展开多个占位符。扩展取决于提交 ID 的可用性,也就是说,如果 git-archive [1]被赋予树而不是提交或标签,则不会执行替换。占位符与用于git-log [1]的--pretty=format:git-log [1] 选项的占位符相同,只不过它们需要像这样包装:$Format:PLACEHOLDERS$在文件中。例如,字符串$Format:%H$将被提交散列替换。

包装物品

delta

对于属性delta设置为 false 的路径,不会尝试使用块压缩增量压缩。

在 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计算如下:

  1. 通过检查t/.gitattributes(与目标路径在同一目录中),Git 发现第一行匹配。merge属性设置。它还认为,第二行相匹配,和属性foobar都没有设置。
  2. 然后,它会检查.gitattributes(这是在父目录),并发现第一个行匹配,但t/.gitattributes文件已经决定如何mergefoobar属性应该给予这条道路,所以它的叶子foobar未设置。属性baz已设置。
  3. 最后它检查$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