-
A1. 附录 A:其他环境下的 Git
- A1.1 图形界面
- A1.2 Visual Studio 中的 Git
- A1.3 Visual Studio Code 中的 Git
- A1.4 IntelliJ / PyCharm / WebStorm / PhpStorm / RubyMine 中的 Git
- A1.5 Sublime Text 中的 Git
- A1.6 Bash 中的 Git
- A1.7 Zsh 中的 Git
- A1.8 PowerShell 中的 Git
- A1.9 总结
-
A2. 附录 B:在你的应用中嵌入 Git
-
A3. 附录 C: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 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 识别的配置选项分为两类:客户端和服务器端。 大多数选项都是客户端 — 配置您的个人工作偏好。 支持许多配置选项,但其中很大一部分仅在某些极端情况下才有用; 我们将在这里介绍最常见和最有用的选项。 如果您想查看 Git 版本识别的所有选项的列表,可以运行
$ man git-config
此命令以相当详细的方式列出所有可用选项。 您还可以在 https://git-scm.cn/docs/git-config 找到此参考资料。
注意
|
对于高级用例,您可能需要在上面提到的文档中查找“条件包含”。 |
core.editor
默认情况下,Git 会使用你通过 shell 环境变量 VISUAL
或 EDITOR
设置的默认文本编辑器,否则会退回到 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 分页输出(如 log
和 diff
)时使用的分页器。你可以将其设置为 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 seconds” 这句话。help.autocorrect
实际上是一个整数,表示十分之一秒。因此,如果你将其设置为 50,Git 将给你 5 秒钟的时间来改变你的想法,然后再执行自动更正的命令。
Git 中的颜色
Git 完全支持彩色终端输出,这极大地有助于快速轻松地直观解析命令输出。许多选项可以帮助你根据自己的喜好设置颜色。
color.ui
Git 会自动着色其大部分输出,但如果你不喜欢这种行为,则有一个主开关。要关闭 Git 的所有彩色终端输出,请执行以下操作
$ git config --global color.ui false
默认设置为 auto
,当输出直接发送到终端时,它会着色输出,但当输出重定向到管道或文件时,它会省略颜色控制代码。
你也可以将其设置为 always
以忽略终端和管道之间的差异。你很少会需要这个;在大多数情况下,如果你希望在重定向的输出中使用颜色代码,你可以改为将 --color
标志传递给 Git 命令,以强制它使用颜色代码。默认设置几乎总是你想要的。
color.*
如果你想更具体地了解哪些命令被着色以及如何着色,Git 提供了特定于动词的着色设置。这些设置都可以设置为 true
、false
或 always
color.branch color.diff color.interactive color.status
此外,如果你想覆盖每种颜色,这些设置中的每一个都有子设置,你可以使用它们为输出的各个部分设置特定的颜色。例如,要将 diff 输出中的元信息设置为蓝色前景、黑色背景和粗体文本,你可以运行
$ git config --global color.diff.meta "blue black bold"
你可以将颜色设置为以下任何值:normal
、black
、red
、green
、yellow
、blue
、magenta
、cyan
或 white
。如果你想要像前一个例子中的粗体这样的属性,你可以从 bold
、dim
、ul
(underline)、blink
和 reverse
(交换前景和背景) 中选择。
外部合并和差异工具
虽然 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-file
和 new-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
在完成所有这些设置后,如果你运行像这样的 diff 命令
$ git diff 32d1776b1^ 32d1776b1
Git 不会在命令行上输出差异,而是启动 P4Merge,它看起来像这样

如果你尝试合并两个分支并且随后发生合并冲突,你可以运行命令 git mergetool
;它会启动 P4Merge 让你通过该 GUI 工具解决冲突。
这个包装设置的好处在于你可以轻松地更改你的差异和合并工具。例如,要将你的 extDiff
和 extMerge
工具更改为运行 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
如果你运行此命令而不是设置 extMerge
和 extDiff
文件,Git 将使用 KDiff3 进行合并解决,并使用正常的 Git diff 工具进行差异比较。
格式化和空白
格式化和空白问题是许多开发人员在协作时遇到的一些更令人沮丧和微妙的问题,尤其是在跨平台时。补丁或其他协作工作很容易引入微妙的空白更改,因为编辑器会默默地引入它们,并且如果你的文件曾经接触过 Windows 系统,它们的行尾可能会被替换。Git 有一些配置选项可以帮助解决这些问题。
core.autocrlf
如果你在 Windows 上进行编程,并且与不在 Windows 上的人员一起工作(反之亦然),你可能会在某个时候遇到行尾问题。这是因为 Windows 使用回车符和换行符来表示文件中的换行符,而 macOS 和 Linux 系统仅使用换行符。这是一个微妙但令人难以置信的恼人的跨平台工作事实;Windows 上的许多编辑器会默默地将现有的 LF 样式的行尾替换为 CRLF,或者在用户按下回车键时插入两个行尾字符。
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-eol
和 blank-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 文件。在一个 Git 强制策略的例子中,您还将学习到更多有趣的方法,例如通过 ACL 在每个用户的基础上执行此操作。