Git
章节 ▾ 第二版

8.1 定制 Git - Git 配置

到目前为止,我们已经介绍了 Git 的基本工作原理以及如何使用它,并且介绍了一些 Git 提供的工具,可以帮助您轻松高效地使用它。在本章中,我们将了解如何通过引入一些重要的配置设置和钩子系统,使 Git 以更自定义的方式运行。使用这些工具,可以轻松地使 Git 按照您、您的公司或您的团队的需求工作。

Git 配置

正如您在 入门 中简要阅读的那样,您可以使用 git config 命令指定 Git 配置设置。您做的第一件事之一就是设置您的姓名和电子邮件地址

$ git config --global user.name "John Doe"
$ git config --global user.email [email protected]

现在,您将学习一些更有趣的选项,您可以通过这种方式设置这些选项来自定义您的 Git 使用方式。

首先,快速回顾一下:Git 使用一系列配置文件来确定您可能需要的非默认行为。Git 首先在系统范围内的 [path]/etc/gitconfig 文件中查找这些值,该文件包含应用于系统上每个用户及其所有存储库的设置。如果您将 --system 选项传递给 git config,它将专门从此文件中读取和写入。

Git 接下来的查找位置是 ~/.gitconfig(或 ~/.config/git/config)文件,该文件特定于每个用户。您可以通过传递 --global 选项来使 Git 读取和写入此文件。

最后,Git 在您当前使用的任何存储库的 Git 目录(.git/config)中的配置文件中查找配置值。这些值特定于该单个存储库,并且表示将 --local 选项传递给 git config。如果您未指定要使用的级别,则这是默认值。

这三个“级别”(系统、全局、本地)中的每一个都覆盖先前级别的值,例如,.git/config 中的值会覆盖 [path]/etc/gitconfig 中的值。

注意

Git 的配置文件是纯文本文件,因此您也可以通过手动编辑文件并插入正确的语法来设置这些值。不过,通常运行 git config 命令更容易。

基本客户端配置

Git 识别的配置选项分为两类:客户端和服务器端。大多数选项是客户端选项,用于配置您的个人工作偏好。支持许多配置选项,但其中很大一部分仅在某些极端情况下有用;这里只介绍最常见和最有用的选项。如果您想查看您的 Git 版本识别的所有选项的列表,您可以运行

$ man git-config

此命令将详细列出所有可用选项。您也可以在 https://git.js.cn/docs/git-config 找到此参考材料。

注意

对于高级用例,您可能需要在上面提到的文档中查找“条件包含”。

core.editor

默认情况下,Git 使用您通过 shell 环境变量 VISUALEDITOR 设置的默认文本编辑器,或者回退到 vi 编辑器来创建和编辑您的提交和标签消息。要将该默认值更改为其他内容,可以使用 core.editor 设置

$ git config --global core.editor emacs

现在,无论您的默认 shell 编辑器设置为什么,Git 都会启动 Emacs 来编辑消息。

commit.template

如果将此配置设置为系统上某个文件的路径,Git 将在提交时使用该文件作为默认初始消息。创建自定义提交模板的价值在于,您可以使用它来提醒自己(或他人)在创建提交消息时应遵循的正确格式和风格。

例如,考虑一下位于~/.gitmessage.txt处的模板文件,其内容如下所示:

Subject line (try to keep under 50 characters)

Multi-line description of commit,
feel free to be detailed.

[Ticket: X]

请注意,此提交模板提醒提交者保持主题行简短(为了git log --oneline输出的简洁性),在主题行下添加更多详细信息,并在存在问题或错误跟踪器工单号时进行引用。

要告诉 Git 在运行git commit时将其用作编辑器中显示的默认消息,请设置commit.template配置值:

$ git config --global commit.template ~/.gitmessage.txt
$ git commit

然后,当您提交时,您的编辑器将打开类似以下内容的占位符提交消息:

Subject line (try to keep under 50 characters)

Multi-line description of commit,
feel free to be detailed.

[Ticket: X]
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
# modified:   lib/test.rb
#
~
~
".git/COMMIT_EDITMSG" 14L, 297C

如果您的团队有提交消息策略,那么将该策略的模板放在您的系统上并配置 Git 默认使用它,可以帮助提高该策略被定期遵循的可能性。

core.pager

此设置确定 Git 分页输出(例如logdiff)时使用的分页器。您可以将其设置为more或您喜欢的分页器(默认情况下为less),或者可以通过将其设置为空字符串来将其关闭。

$ git config --global core.pager ''

如果运行该命令,Git 将打印所有命令的完整输出,无论其长度如何。

user.signingkey

如果您正在创建签名带注释的标签(如签名您的工作中所述),将您的 GPG 签名密钥设置为配置设置可以简化操作。像这样设置您的密钥 ID:

$ git config --global user.signingkey <gpg-key-id>

现在,您可以签名标签,而无需每次都使用git tag命令指定您的密钥。

$ git tag -s <tag-name>

core.excludesfile

您可以在项目的.gitignore文件中放置模式,以使 Git 不将它们视为未跟踪的文件,或者在您对它们运行git add时尝试将其暂存,如忽略文件中所述。

但有时您希望忽略与您使用的所有存储库相关的某些文件。如果您的计算机运行的是 macOS,您可能熟悉.DS_Store文件。如果您的首选编辑器是 Emacs 或 Vim,您知道以~.swp结尾的文件名。

此设置允许您编写一种全局.gitignore文件。如果您创建一个包含以下内容的~/.gitignore_global文件:

*~
.*.swp
.DS_Store

…并且您运行git config --global core.excludesfile ~/.gitignore_global,Git 将不再打扰您关于这些文件。

help.autocorrect

如果您输入错误命令,它会显示类似以下内容:

$ git chekcout master
git: 'chekcout' is not a git command. See 'git --help'.

The most similar command is
    checkout

Git 会尝试找出您的本意,但仍然拒绝执行。如果您将help.autocorrect设置为 1,Git 将实际为您运行此命令:

$ git chekcout master
WARNING: You called a Git command named 'chekcout', which does not exist.
Continuing under the assumption that you meant 'checkout'
in 0.1 seconds automatically...

请注意“0.1 秒”部分。help.autocorrect实际上是一个整数,表示十分之一秒。因此,如果您将其设置为 50,Git 将为您提供 5 秒的时间来改变主意,然后再执行自动更正后的命令。

Git 中的颜色

Git 完全支持彩色终端输出,这极大地有助于快速轻松地视觉解析命令输出。许多选项可以帮助您根据自己的喜好设置颜色。

color.ui

Git 自动为其大部分输出着色,但如果您不喜欢此行为,则可以使用主开关。要关闭所有 Git 的彩色终端输出,请执行以下操作:

$ git config --global color.ui false

默认设置为auto,当输出直接发送到终端时会为输出着色,但当输出重定向到管道或文件时会省略颜色控制代码。

您还可以将其设置为always,以忽略终端和管道之间的差异。您很少需要这样做;在大多数情况下,如果您希望在重定向的输出中使用颜色代码,则可以改为将--color标志传递给 Git 命令以强制其使用颜色代码。默认设置几乎总是您想要的。

color.*

如果您想更具体地指定哪些命令着色以及如何着色,Git 提供了特定于动词的着色设置。每个设置都可以设置为truefalsealways

color.branch
color.diff
color.interactive
color.status

此外,如果您想覆盖每个颜色,每个设置都有子设置,您可以使用它们来为输出的各个部分设置特定的颜色。例如,要将 diff 输出中的元信息设置为蓝色前景色、黑色背景色和粗体文本,您可以运行:

$ git config --global color.diff.meta "blue black bold"

您可以将颜色设置为以下任何值:normalblackredgreenyellowbluemagentacyanwhite。如果您希望像前面的示例中的粗体这样的属性,您可以从bolddimul(下划线)、blinkreverse(交换前景色和背景色)中选择。

外部合并和差异工具

尽管 Git 具有 diff 的内部实现(我们在本书中一直展示的就是这个),但您也可以设置外部工具。您还可以设置图形化合并冲突解决工具,而不是必须手动解决冲突。我们将演示如何设置 Perforce Visual Merge Tool (P4Merge) 来执行您的差异和合并解决,因为它是一个不错的图形工具并且是免费的。

如果您想尝试一下,P4Merge 在所有主要平台上都能运行,因此您应该能够做到。我们将在示例中使用适用于 macOS 和 Linux 系统的路径名;对于 Windows,您必须将/usr/local/bin更改为环境中的可执行路径。

首先,从Perforce 下载 P4Merge。接下来,您将设置外部包装器脚本以运行您的命令。我们将使用 macOS 路径作为可执行文件;在其他系统中,它将是安装p4merge二进制文件的位置。设置一个名为extMerge的合并包装器脚本,该脚本使用提供的全部参数调用您的二进制文件:

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/p4merge.app/Contents/MacOS/p4merge $*

diff 包装器检查是否提供了七个参数,并将其中两个传递给您的合并脚本。默认情况下,Git 将以下参数传递给 diff 程序:

path old-file old-hex old-mode new-file new-hex new-mode

因为您只需要old-filenew-file参数,所以您使用包装器脚本传递您需要的参数。

$ cat /usr/local/bin/extDiff
#!/bin/sh
[ $# -eq 7 ] && /usr/local/bin/extMerge "$2" "$5"

您还需要确保这些工具是可执行的:

$ sudo chmod +x /usr/local/bin/extMerge
$ sudo chmod +x /usr/local/bin/extDiff

现在,您可以设置您的配置文件以使用自定义合并解决和差异工具。这需要许多自定义设置:merge.tool告诉 Git 使用什么策略,mergetool.<tool>.cmd指定如何运行命令,mergetool.<tool>.trustExitCode告诉 Git 该程序的退出代码是否表示成功合并解决,以及diff.external告诉 Git 运行什么命令进行差异。因此,您可以运行四个配置命令:

$ git config --global merge.tool extMerge
$ git config --global mergetool.extMerge.cmd \
  'extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"'
$ git config --global mergetool.extMerge.trustExitCode false
$ git config --global diff.external extDiff

或者,您可以编辑您的~/.gitconfig文件以添加以下行:

[merge]
  tool = extMerge
[mergetool "extMerge"]
  cmd = extMerge "$BASE" "$LOCAL" "$REMOTE" "$MERGED"
  trustExitCode = false
[diff]
  external = extDiff

在完成所有这些设置后,如果您运行以下差异命令:

$ git diff 32d1776b1^ 32d1776b1

Git 将启动 P4Merge 而不是在命令行上获取差异输出,P4Merge 看起来像这样:

P4Merge
图 168. P4Merge

如果您尝试合并两个分支并随后出现合并冲突,您可以运行命令git mergetool;它启动 P4Merge 以允许您通过该 GUI 工具解决冲突。

此包装器设置的好处在于您可以轻松更改差异和合并工具。例如,要将您的extDiffextMerge工具更改为运行 KDiff3 工具,您只需编辑您的extMerge文件即可:

$ cat /usr/local/bin/extMerge
#!/bin/sh
/Applications/kdiff3.app/Contents/MacOS/kdiff3 $*

现在,Git 将使用 KDiff3 工具进行差异查看和合并冲突解决。

Git 预设使用许多其他合并解决工具,无需您设置 cmd 配置。要查看它支持的工具列表,请尝试以下操作:

$ git mergetool --tool-help
'git mergetool --tool=<tool>' may be set to one of the following:
        emerge
        gvimdiff
        gvimdiff2
        opendiff
        p4merge
        vimdiff
        vimdiff2

The following tools are valid, but not currently available:
        araxis
        bc3
        codecompare
        deltawalker
        diffmerge
        diffuse
        ecmerge
        kdiff3
        meld
        tkdiff
        tortoisemerge
        xxdiff

Some of the tools listed above only work in a windowed
environment. If run in a terminal-only session, they will fail.

如果您不想使用 KDiff3 进行差异,而是只想将其用于合并解决,并且kdiff3命令在您的路径中,那么您可以运行:

$ git config --global merge.tool kdiff3

如果您运行此命令而不是设置extMergeextDiff文件,Git 将使用 KDiff3 进行合并解决,并使用正常的 Git diff 工具进行差异。

格式和空格

格式和空格问题是许多开发人员在协作(尤其是在跨平台协作)时遇到的更令人沮丧和微妙的问题之一。修补程序或其他协作工作很容易引入细微的空格更改,因为编辑器会静默地引入它们,并且如果您的文件曾经接触过 Windows 系统,则其行尾可能会被替换。Git 有几个配置选项可以帮助解决这些问题。

core.autocrlf

如果您在 Windows 上进行编程并与不在 Windows 上工作的人员合作(反之亦然),您可能会在某些时候遇到行尾问题。这是因为 Windows 在其文件中的换行符使用回车符和换行符,而 macOS 和 Linux 系统仅使用换行符。这是一个微妙但令人难以置信地令人烦恼的跨平台工作事实;Windows 上的许多编辑器会静默地将现有的 LF 样式行尾替换为 CRLF,或者在用户按下 Enter 键时插入两个行尾字符。

Git 可以通过在您将文件添加到索引时自动将 CRLF 行尾转换为 LF 来处理此问题,反之亦然,当它将代码检出到您的文件系统时也是如此。您可以使用core.autocrlf设置打开此功能。如果您在 Windows 机器上,请将其设置为true——这会在您检出代码时将 LF 结尾转换为 CRLF。

$ git config --global core.autocrlf true

如果您在使用 LF 行尾的 Linux 或 macOS 系统上,则不希望 Git 在您检出文件时自动转换它们;但是,如果意外引入了带有 CRLF 结尾的文件,则您可能希望 Git 修复它。您可以告诉 Git 在提交时将 CRLF 转换为 LF,但不要反过来,方法是将core.autocrlf设置为input

$ git config --global core.autocrlf input

此设置应该使您在 Windows 检出中保留 CRLF 结尾,但在 macOS 和 Linux 系统以及存储库中保留 LF 结尾。

如果您是 Windows 程序员并且正在进行仅限 Windows 的项目,则可以关闭此功能,通过将配置值设置为false来在存储库中记录回车符。

$ git config --global core.autocrlf false

core.whitespace

Git 预设检测和修复某些空格问题。它可以查找六个主要的空格问题——其中三个默认启用并且可以关闭,三个默认禁用但可以激活。

默认情况下开启的三个是blank-at-eol,它查找行尾的空格;blank-at-eof,它注意到文件末尾的空行;以及space-before-tab,它查找行首制表符前的空格。

默认禁用但可以开启的三个选项是 indent-with-non-tab(查找以空格而不是制表符开头的行,由 tabwidth 选项控制);tab-in-indent(监视行缩进部分中的制表符);以及 cr-at-eol(告诉 Git 行尾的回车符是可以接受的)。

你可以通过将 core.whitespace 设置为你希望开启或关闭的值(用逗号分隔)来告诉 Git 你想要启用哪些选项。可以通过在选项名称前添加 - 来禁用它,或者完全不包含在设置字符串中来使用默认值。例如,如果你希望除了 space-before-tab 之外的所有选项都被设置,你可以这样做(其中 trailing-spaceblank-at-eolblank-at-eof 的简写)

$ git config --global core.whitespace \
    trailing-space,-space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol

或者你可以只指定自定义的部分

$ git config --global core.whitespace \
    -space-before-tab,indent-with-non-tab,tab-in-indent,cr-at-eol

当你运行 git diff 命令时,Git 会检测到这些问题,并尝试对它们进行着色,以便你可以在提交之前修复它们。它还会在你使用 git apply 应用补丁时使用这些值来帮助你。当你应用补丁时,你可以要求 Git 在应用包含指定空白问题的补丁时发出警告。

$ git apply --whitespace=warn <patch>

或者你可以让 Git 尝试在应用补丁之前自动修复问题。

$ git apply --whitespace=fix <patch>

这些选项也适用于 git rebase 命令。如果你已经提交了空白问题但还没有推送到上游,你可以运行 git rebase --whitespace=fix 让 Git 在重写补丁时自动修复空白问题。

服务器配置

Git 服务器端可用的配置选项并不多,但有一些有趣的选项你可能需要注意。

receive.fsckObjects

Git 能够确保在推送过程中接收到的每个对象仍然与其 SHA-1 校验和匹配,并指向有效的对象。但是,它默认情况下不会这样做;这是一个相当昂贵的操作,可能会减慢操作速度,尤其是在大型仓库或推送时。如果你希望 Git 在每次推送时都检查对象的一致性,你可以强制它这样做,方法是将 receive.fsckObjects 设置为 true。

$ git config --system receive.fsckObjects true

现在,Git 会在每次推送被接受之前检查你的仓库的完整性,以确保有故障(或恶意的)客户端不会引入损坏的数据。

receive.denyNonFastForwards

如果你对已经推送的提交进行变基,然后尝试再次推送,或者以其他方式尝试将提交推送到不包含远程分支当前指向的提交的远程分支,你将被拒绝。这通常是一个好的策略;但在变基的情况下,你可能确定你知道自己在做什么,并且可以使用 -f 标志强制更新远程分支到你的推送命令。

要告诉 Git 拒绝强制推送,请设置 receive.denyNonFastForwards

$ git config --system receive.denyNonFastForwards true

另一种方法是通过服务器端接收钩子来实现,我们稍后会介绍。这种方法允许你执行更复杂的操作,例如拒绝对某些用户的非快进推送。

receive.denyDeletes

denyNonFastForwards 策略的一种解决方法是用户删除分支,然后将它重新推送到服务器。为了避免这种情况,将 receive.denyDeletes 设置为 true。

$ git config --system receive.denyDeletes true

这会拒绝任何分支或标签的删除——任何用户都无法执行此操作。要删除远程分支,必须手动从服务器上删除 ref 文件。还有更多有趣的方法可以通过 ACL 在每个用户的基础上执行此操作,你将在 Git 强制策略示例 中了解到。

scroll-to-top