章节 ▾ 第二版

8.1 自定义 Git - Git 配置

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

Git 配置

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

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

现在您将学习一些更有趣的选项,您可以通过这种方式进行设置,以自定义您的 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-scm.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

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

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

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

外部合并和差异工具

尽管 Git 具有内部的差异实现(本书中一直展示的),但您可以设置一个外部工具来代替。您还可以设置一个图形化的合并冲突解决工具,而无需手动解决冲突。我们将演示如何设置 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 $*

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

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
图 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 差异工具进行差异比较。

格式和空白符

格式和空白符问题是许多开发人员在协作时,特别是跨平台协作时,遇到的更令人沮丧和微妙的问题。补丁或其他协作工作很容易引入细微的空白符更改,因为编辑器会静默地引入它们,而且如果您的文件接触过 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 修复它。您可以通过将core.autocrlf设置为input来告诉 Git 在提交时将 CRLF 转换为 LF,而不是反过来

$ 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-space是同时涵盖blank-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

这拒绝了任何分支或标签的删除——任何用户都无法执行此操作。要删除远程分支,您必须手动从服务器中删除引用文件。还有更多有趣的方法可以按用户基于 ACL 执行此操作,您将在Git 强制策略示例中学习。

scroll-to-top