自定义 Git - Git 属性



Git 属性

我们可以使用**Git 属性**来设置 Git 对仓库中特定文件或文件夹的行为。

对于临时或本地设置,我们在**.git/info/attributes**文件中或**.gitattributes**文件中声明这些属性,后者通常位于根目录。

  • 使用属性,我们可以自定义合并技术来解决冲突。

  • 在进行合并和 diff 时,可以对非文本文件进行不同的处理。

  • 为了确保 Git 按照项目的特定要求运行,我们还可以实现过滤器,在提交或检出之前评估文件内容。

**.gitattributes**文件应放在仓库的根目录。您也可以在子目录中创建它,以将规则应用于项目的特定部分。

二进制文件

Git 属性允许我们识别二进制文件,并为 Git 提供关于如何处理它们的指令。

这些属性帮助 Git 对它可能无法自动识别的二进制文件应用某些准则。

  • 虽然有些二进制文件可以进行 diff,但有些机器生成的文本文件可能不行。

  • 通过指定这些属性,我们确保 Git 正确处理每种类型的文件。

  • 现在,Git 更有效地处理和比较我们仓库中的各种文件类型。

识别二进制文件

尽管某些文件看起来像文本,但由于其预期用途,它们应被视为二进制数据。

例如,Xcode 项目中名为**.pbxproj**的 UTF-8 文本文件充当小型数据库。

  • 由于其性质,这些文件不适合合并或 diff。

  • 即使它们是基于文本的,其目的也不是人工编辑,而是机器使用。

  • 为了防止合并和 diff 出现问题,我们需要设置 Git 以使其将这些文件作为二进制文件处理。

要指示 Git 将所有**.pbxproj**文件作为二进制数据处理,请在我们的**.gitattributes**文件中包含**/*.pbxproj binary**。

使用**git show**或**git diff**时,此设置会阻止 Git 转换 CRLF 行尾,并阻止它为某些文件的更改创建 diff。

*.pbxproj binary

二进制文件的 Diff

Git 属性可用于通过将二进制数据转换为文本格式进行比较来管理二进制文件的 diff。

此方法在 Git 中非常适合管理二进制文件,例如 Microsoft Word 文档。

  • 通过配置 Git 以转换二进制数据,我们可以有效地跟踪更改并将版本控制应用于这些文件。

  • 使用此方法,即使是原始二进制文件,我们也可以在 Git 中对二进制文件使用 diff 工具。

  • 通过正确的配置,我们可以更有效地管理和版本控制 Git 仓库中的二进制文件。

对二进制文件运行**git diff**的结果表明,**report.docx**的两个版本有所不同,但 Git 只显示文件已更改,而不是实际内容。

必须配置 Git 属性才能直接在编辑器中比较二进制文件(例如 docx)的版本。

例如,我们可以实现自定义过滤器来执行比较**.docx**文件的任务。以下是配置方法:

在**.gitattributes**文件中写入以下内容:

*.docx diff=word

此行指示 Git 使用**word**过滤器显示**.docx**文件的 diff。

  • 为了将 Word 文件转换为可读格式,需要设置**word**过滤器。

  • 例如,我们可以配置 Git 使用**docx2text**或其他工具将 docx 转换为文本格式,以便可以进行 diff。

  • 通过此配置,可以通过将 docx 文件转换为文本文件进行 diff 分析,从而轻松比较 docx 版本。

使用 Git 对**.docx**文件进行 diff

从 SourceForge 下载**docx2txt**并按照设置指南进行安装。

创建包装器脚本:将以下内容键入名为**docx2txt**的脚本中:

#!/bin/bash
docx2txt.pl "$1" -

将此脚本放在系统 PATH 中的目录。

**使脚本可执行**:要为脚本提供可执行权限,请运行以下命令:

chmod a+x /path/to/docx2txt

**配置 Git**:在 Git 的配置中设置 textconv 过滤器,以指示 Git 对.docx 文件使用该脚本。

git config diff.word.textconv docx2txt
  • Git 已设置为对涉及**.docx**文件的 diff 使用**docx2txt**工具。

  • Git 使用**word**过滤器将**.docx**文件转换为文本。

  • 因此,Git 现在可以生成可读的基于文本的 Word 文档 diff。

可以通过提取和比较图像信息(而不是实际图像内容)来解决 diff 图像文件的问题。

  • 我们可以使用诸如**exiftool**之类的工具将图像的 EXIF 元数据转换为文本格式。

  • 现在,Git 可以根据文本元数据的更改进行 diff,从而提供有关对图像文件所做任何更改的信息。

要设置 Git 以比较图像的元数据以进行 diff:

修改**.gitattributes**:在**.gitattributes**文件中包含以下行,以指示**.png**文件需要使用**exif**过滤器:

*.png diff=exif

**设置 Git**:使用此命令配置 Git 以对**exif**过滤器使用 exiftool:

git config diff.exif.textconv exiftool

通过此配置,Git 将能够使用**exiftool**将图像元数据转换为文本,从而基于元数据的更改启用有意义的 diff。

当我们替换图像并运行**git diff**时,Git 会显示使用**exiftool**从图像文件提取的元数据的 diff。

这不会直接比较图像内容,而是通过显示图像元数据的变化(包括文件大小、修改日期和尺寸)来提供更改的文本表示。

关键字扩展

**SVN**或**CVS**的一个特定功能,它将元数据(例如版本号或修订 ID)嵌入文件中,称为**关键字扩展**。

Git 使用校验和跟踪文件更改,从而防止提交后更新文件,这使得传统的关键字扩展不切实际。

  • 相反,Git 允许在检出期间将元数据添加到文件,然后在提交之前将其删除。

  • 此方法使用 Git 属性来控制何时以及如何添加和删除元数据。

  • Git 属性提供两种处理关键字扩展的方法:使用内置算法或创建自定义过滤器。

使用 Git 属性,我们可以自动将文件的(或 blob 的)SHA-1 校验和放入指定的字段(例如**$Id$**)。

  • 每次检出分支时,都会在此字段中更新文件的校验和。

  • 文件的內容由校验和表示,而不是它所属的提交。

要允许自动将 SHA-1 校验和附加到文件,请执行以下步骤:

在名为**.gitattributes**的文件中包含以下行:

*.txt ident

创建一个包含对**$Id$**的引用的测试文件。

echo '$Id$' > test.txt

删除测试文件,然后再次检出。

rm test.txt
git checkout -- test.txt

查看修改后的文件,查看注入的 SHA-1 校验和。

cat test.txt
$Id: 42812b7653c7b88933f8a9d6cad0ca16714b9bb3 $

由于它缺乏有关文件年龄的信息,因此 Git 的关键字替换获得的 SHA-1 校验和结果本身并不十分有用。

与 CVS 或 Subversion(可能包含日期戳)相比,Git 的 SHA-1 是随机的,不会显示文件的年龄。

git attributes

但是,Git 允许我们设计独特的**smudge**和**clean**过滤器来处理检出和提交期间的文件。

在检出或暂存文件之前,可以在**.gitattributes**文件中设置这些过滤器以执行不同的操作。

git attributes

示例提交消息演示了如何在提交之前使用 indent 程序自动格式化 C 源代码。

为此,请将后续行添加到我们的**.gitattributes**文件中:

*.c filter=indent

配置以下命令以指定 Git 的**indent**过滤器的行为:

指定应使用 indent 程序清理文件(在暂存之前)。

git config --global filter.indent.clean indent

在检出之前,设置 cat 命令用于涂抹文件。

git config --global filter.indent.smudge cat

通过此配置,Git 将在检出 C 源代码文件之前使用**cat**程序(什么也不做),并且在暂存它们之前将通过**indent**程序运行它们。

这保证了在提交之前,所有 C 文件都使用**indent**进行了格式化。

导出我们的仓库

Git 属性使我们能够管理项目存档期间进行的文件处理,允许我们创建包含附加元数据、过滤和转换的自定义导出。

  • 我们可以使用**export-ignore**属性指定哪些文件或目录不应包含在存档中。

  • 我们可以使用它来保留仓库中我们在导出的存档中不需要的目录或文件。

  • 要确保某些文件或目录不包含在存档中,请在其上设置**export-ignore**属性。

  • 通过保留仓库中的重要文件并删除不相关的文件,这有助于管理导出存档的内容。

如果我们在 docs/ 目录中有一些内部文档,我们不希望将其包含在项目的 zip 存档中,我们可以将以下行添加到我们的 Git 属性文件中:

docs/ export-ignore

当我们使用 git archive 生成项目的 zip 文件时,**docs/**目录将不包含在存档中。

export-subst

我们可以使用**export-subst**属性在导出期间将 Git 的日志格式和关键字扩展应用于特定文件部分。

  • 它可以将动态数据(例如版本号或提交详细信息)替换为文件中的占位符。

  • 它保证我们导出的文件中的元数据是最新的,因为它来自存储库。

要在创建存档时自动将元数据注入名为 LAST_COMMIT 的文件,请按照以下步骤操作

配置 **.gitattributes**

echo 'LAST_COMMIT export-subst' > .gitattributes

创建包含元数据占位符的 **LAST_COMMIT** 文件

echo 'Last commit date: $Format:%cd by %aN$' > LAST_COMMIT

添加并提交更改

git add LAST_COMMIT .gitattributes
git commit -am 'Add LAST_COMMIT file for archives'

创建存档并检查内容

git archive HEAD | tar xCf ../deployment-testing -
cat ../deployment-testing/LAST_COMMIT

存档中的 **LAST_COMMIT** 文件将显示元数据,例如上次提交的日期和作者。

创建存档时,我们可以使用 export-subst 属性在文件中包含格式化的提交元数据。

合并策略

Git 属性允许我们在合并时对特定文件使用多种合并算法。

  • 发生冲突时,我们可以设置 Git 合并更改,或自动偏向我们的文件版本而不是其他版本。

  • 这保证了在合并期间,关键文件或特殊文件不会发生更改。

  • 通过定义这些合并方法,我们可以控制在复杂的合并场景中如何处理文件。

我们可以这样设置属性:

strings.json merge=ours

然后,使用以下命令配置虚拟的 **ours** 合并策略:

git config --global merge.ours.driver true

当我们从另一个分支执行合并时,我们将避免与 **strings.json** 发生合并冲突。

相反,我们会看到这样的输出:

$ git merge feature-branch
Auto-merging strings.json
Merge made by recursive.

在这种情况下,**strings.json** 将保持其原始状态,不会发生合并更改。

使用 Git 属性的优势

以下是使用 **Git 属性**的一些优势:

  • 它确保在各种环境和操作系统中一致地处理文件。

  • 对于特定文件,它有助于管理合并冲突和差异。

  • 它为文件处理定义了清晰而精确的规则,从而使协作更加轻松有效。

广告