Git学习-自定义Git
配置 Git
在安装 Git 后,首先要做的事就是配置 Git 的提交者的名称和邮件地址:
1 | git config --global user.name "Wray" |
现在,将会讲解除了配置 Git 提交者信息以外的其他配置信息。
首先,快速回忆下:Git 使用一系列配置文件来保存你自定义的行为。 它首先会查找系统级的 /etc/gitconfig
文件,该文件含有系统里每位用户及他们所拥有的仓库的配置值。 如果你传递 --system
选项给 git config
,它就会读写该文件。
接下来 Git 会查找每个用户的 ~/.gitconfig
文件(或者 ~/.config/git/config
文件)。 你可以传递 --global
选项让 Git 读写该文件。
最后 Git 会查找你正在操作的仓库所对应的 Git 目录下的配置文件(.git/config
)。 这个文件中的值只对该仓库有效,它对应于向 git config
传递 --local
选项。
以上三个层次中每层的配置(系统、全局、本地)都会覆盖掉上一层次的配置,所以 .git/config
中的值会覆盖掉 /etc/gitconfig
中所对应的值。
Git 的配置文件是纯文本的,所以你可以直接手动编辑这些配置文件,输入合乎语法的值。 但是运行
git config
命令会更简单些。
客户端基础配置
Git 能够识别的配置项分为两大类:客户端和服务器端。 其中大部分属于客户端配置 —— 可以依你个人的工作偏好进行配置。
如果想得到本地当前版本的 Git 支持的选项列表,可以运行:
1 | man git-config |
下面主要讲解平常实用的部分命令。
core.editor
默认情况下,Git 会调用你通过环境变量 $VISUAL
或 $EDITOR
设置的文本编辑器, 如果没有设置,默认则会调用 vi
来创建和编辑你的提交以及标签信息。 你可以使用 core.editor
选项来修改默认的编辑器:
1 | git config --global core.editor emacs |
现在,无论你定义了什么终端编辑器,Git 都会调用 Emacs 编辑信息。
commit.template
如果把此项指定为你的系统上某个文件的路径,当你提交的时候, Git 会使用该文件的内容作为提交的默认初始化信息。 创建的自定义提交模版中的值可以用来提示自己或他人适当的提交格式和风格。
core.pager
该配置项指定 Git 运行诸如 log
和 diff
等命令所使用的分页器。 你可以把它设置成用 more
或者任何你喜欢的分页器(默认用的是 less
),当然也可以设置成空字符串,关闭该选项:
1 | git config --global core.pager '' |
这样不管命令的输出量多少,Git 都会在一页显示所有内容。
user.signingkey
如果你要创建经签署的含附注的标签, 那么把你的 GPG 签署密钥设置为配置项会更好。如下设置你的密钥 ID:
1 | git config --global user.signingkey <gpg-key-id> |
现在,你每次运行 git tag
命令时,即可直接签署标签,而无需定义密钥:
1 | git tag -s <tag-name> |
core.excludesfile
你可以在你的项目的 .gitignore
文件里面规定无需纳入 Git 管理的文件的模板,这样它们既不会出现在未跟踪列表, 也不会在你运行 git add
后被暂存。
不过有些时候,你想要在你所有的版本库中忽略掉某一类文件。 如果你的操作系统是 macOS,很可能就是指 .DS_Store
。 如果你把 Emacs 或 Vim 作为首选的编辑器,你肯定知道以 ~
结尾的文件名。
这个配置允许你设置类似于全局生效的 .gitignore
文件。 如果你按照下面的内容创建一个 ~/.gitignore_global
文件:
1 | *~ |
然后运行 git config --global core.excludesfile ~/.gitignore_global
,Git 将把那些文件永远地拒之门外。
help.autocorrect
假如你打错了一条命令,会显示:
1 | git chekcout master |
Git 会尝试猜测你的意图,但是它不会越俎代庖。 如果你把 help.autocorrect
设置成 1,那么只要有一个命令被模糊匹配到了,Git 会自动运行该命令。
1 | git chekcout master |
注意提示信息中的“0.1 秒”。help.autocorrect
接受一个代表十分之一秒的整数。 所以如果你把它设置为 50, Git 将在自动执行命令前给你 5 秒的时间改变主意。
color.*
Git 会自动着色大部分输出内容,但如果你不喜欢花花绿绿,也可以关掉。 要想关掉 Git 的终端颜色输出,试一下这个:
1 | git config --global color.ui false |
这个设置的默认值是 auto
,它会着色直接输出到终端的内容;而当内容被重定向到一个管道或文件时,则忽略着色功能。
你也可以设置成 always
,来忽略掉管道和终端的不同,即在任何情况下着色输出。 你很少会这么设置,在大多数场合下,如果你想在被重定向的输出中插入颜色码,可以传递 --color
标志给 Git 命令来强制它这么做。 默认设置就已经能满足大多数情况下的需求了。
要想具体到哪些命令输出需要被着色以及怎样着色,你需要用到和具体命令有关的颜色配置选项。 它们都能被置为 true
、false
或 always
:
1 | color.branch |
另外,以上每个配置项都有子选项,它们可以被用来覆盖其父设置,以达到为输出的各个部分着色的目的。 例如,为了让 diff
的输出信息以蓝色前景、黑色背景和粗体显示,你可以运行
1 | git config --global color.diff.meta "blue black bold" |
你能设置的颜色有:normal
、black
、red
、green
、yellow
、blue
、magenta
、cyan
或 white
。 正如以上例子设置的粗体属性,想要设置字体属性的话,可以选择包括:bold
、dim
、ul
(下划线)、blink
、reverse
(交换前景色和背景色)。
core.autocrlf
假如你正在 Windows 上写程序,而你的同伴用的是其他系统(或相反),你可能会遇到 CRLF 问题。 这是因为 Windows 使用回车(CR)和换行(LF)两个字符来结束一行,而 macOS 和 Linux 只使用换行(LF)一个字符。 虽然这是小问题,但它会极大地扰乱跨平台协作。许多 Windows 上的编辑器会悄悄把行尾的换行字符转换成回车和换行, 或在用户按下 Enter 键时,插入回车和换行两个字符。
Git 可以在你提交时自动地把回车和换行转换成换行,而在检出代码时把换行转换成回车和换行。 你可以用 core.autocrlf
来打开此项功能。 如果是在 Windows 系统上,把它设置成 true
,这样在检出代码时,换行会被转换成回车和换行:
1 | git config --global core.autocrlf true |
如果使用以换行作为行结束符的 Linux 或 macOS,你不需要 Git 在检出文件时进行自动的转换; 然而当一个以回车加换行作为行结束符的文件不小心被引入时,你肯定想让 Git 修正。 你可以把 core.autocrlf
设置成 input 来告诉 Git 在提交时把回车和换行转换成换行,检出时不转换:
1 | git config --global core.autocrlf input |
这样在 Windows 上的检出文件中会保留回车和换行,而在 macOS 和 Linux 上,以及版本库中会保留换行。
如果你是 Windows 程序员,且正在开发仅运行在 Windows 上的项目,可以设置 false
取消此功能,把回车保留在版本库中:
1 | git config --global core.autocrlf false |
core.whitespace
Git 预先设置了一些选项来探测和修正多余空白字符问题。 它提供了六种处理多余空白字符的主要选项 —— 其中三个默认开启,另外三个默认关闭,不过你可以自由地设置它们。
默认被打开的三个选项是:blank-at-eol
,查找行尾的空格;blank-at-eof
,盯住文件底部的空行; space-before-tab
,警惕行头 tab 前面的空格。
默认被关闭的三个选项是:indent-with-non-tab
,揪出以空格而非 tab 开头的行(你可以用 tabwidth
选项控制它);tab-in-indent
,监视在行头表示缩进的 tab;cr-at-eol
,告诉 Git 忽略行尾的回车。
通过设置 core.whitespace
,你可以让 Git 按照你的意图来打开或关闭以逗号分割的选项。 要想关闭某个选项,你可以在输入设置选项时不指定它或在它前面加个 -
。 例如,如果你想要打开除space-before-tab
之外的所有选项,那么可以这样 ( trailing-space
涵盖了 blank-at-eol
和 blank-at-eof
):
1 | git config --global core.whitespace \ |
你也可以只指定自定义的部分:
1 | git config --global core.whitespace \ |
服务端配置
receive.fsckObjects
Git 能够确认每个对象的有效性以及 SHA-1 检验和是否保持一致。 但 Git 不会在每次推送时都这么做。这个操作很耗时间,很有可能会拖慢提交的过程,特别是当库或推送的文件很大的情况下。 如果想在每次推送时都要求 Git 检查一致性,设置 receive.fsckObjects
为 true 来强迫它这么做:
1 | git config --system receive.fsckObjects true |
现在 Git 会在每次推送生效前检查库的完整性,确保没有被有问题的客户端引入破坏性数据。
receive.denyNonFastForwards
如果你变基已经被推送的提交,继而再推送,又或者推送一个提交到远程分支,而这个远程分支当前指向的提交不在该提交的历史中,这样的推送会被拒绝。 这通常是个很好的策略,但有时在变基的过程中,你确信自己需要更新远程分支,可以在 push 命令后加 -f
标志来强制更新(force-update)。
要禁用这样的强制更新推送(force-pushes),可以设置 receive.denyNonFastForwards
:
1 | git config --system receive.denyNonFastForwards true |
稍后我们会提到,用服务器端的接收钩子也能达到同样的目的。 那种方法可以做到更细致的控制,例如禁止某一类用户做非快进(non-fast-forwards)推送。
receive.denyDeletes
有一些方法可以绕过 denyNonFastForwards
策略。其中一种是先删除某个分支,再连同新的引用一起推送回该分支。 把 receive.denyDeletes
设置为 true 可以把这个漏洞补上:
1 | git config --system receive.denyDeletes true |
这样会禁止通过推送删除分支和标签 — 没有用户可以这么做。 要删除远程分支,必须从服务器手动删除引用文件。
Git 属性
你也可以针对特定的路径配置某些设置项,这样 Git 就只对特定的子目录或子文件集运用它们。 这些基于路径的设置项被称为 Git 属性,可以在你的目录下的 .gitattributes
文件内进行设置(通常是你的项目的根目录)。如果不想让这些属性文件与其它文件一同提交,你也可以在 .git/info/attributes
文件中进行设置。
通过使用属性,你可以对项目中的文件或目录单独定义不同的合并策略,让 Git 知道怎样比较非文本文件,或者让 Git 在提交或检出前过滤内容。
Git 钩子
和其它版本控制系统一样,Git 能在特定的重要动作发生时触发自定义脚本。 有两组这样的钩子:客户端的和服务器端的。 客户端钩子由诸如提交和合并这样的操作所调用,而服务器端钩子作用于诸如接收被推送的提交这样的联网操作。 你可以随心所欲地运用这些钩子。
钩子都被存储在 Git 目录下的 hooks
子目录中。 也即绝大部分项目中的 .git/hooks
。 当你用 git init
初始化一个新版本库时,Git 默认会在这个目录中放置一些示例脚本。 这些脚本除了本身可以被调用外,它们还透露了被触发时所传入的参数。 所有的示例都是 shell 脚本,其中一些还混杂了 Perl 代码,不过,任何正确命名的可执行脚本都可以正常使用 —— 你可以用 Ruby 或 Python,或任何你熟悉的语言编写它们。 这些示例的名字都是以 .sample
结尾,如果你想启用它们,得先移除这个后缀。
把一个正确命名(不带扩展名)且可执行的文件放入 .git
目录下的 hooks
子目录中,即可激活该钩子脚本。 这样一来,它就能被 Git 调用。
需要注意的是,克隆某个版本库时,它的客户端钩子 并不 随同复制。 如果需要靠这些脚本来强制维持某种策略,建议你在服务器端实现这一功能。
总结
自定义 Git 章节中,我主要在乎的是使用 Git 客户端配置,因为它跟平常的开发息息相关。 Git 属性和 Git 钩子更偏向于自定义化,一般项目确实用不到,等到真的有需求那天,再专门整理一章实践片,现在主打一个了解,知道有这个东西就行。