=== 环境变量

Git 总是在一个 `bash` shell 中运行，并借助一些 shell 环境变量来决定它的运行方式。
有时候，知道它们是什么以及它们如何让 Git 按照你想要的方式去运行会很有用。
这里不会列出所有的 Git 环境变量，但我们会涉及最有的那部分。


==== 全局行为

像通常的程序一样，Git 的常规行为依赖于环境变量。

*`GIT_EXEC_PATH`* 决定 Git 到哪找它的子程序 （像 `git-commit`, `git-diff` 等等）。
  你可以用 `git --exec-path` 来查看当前设置。

通常不会考虑修改 *`HOME`* 这个变量（太多其它东西都依赖它），这是 Git 查找全局配置文件的地方。
  如果你想要一个包括全局配置的真正的便携版 Git， 你可以在便携版 Git 的 shell 配置中覆盖 `HOME` 设置。

*`PREFIX`* 也类似，除了用于系统级别的配置。
  Git 在 `$PREFIX/etc/gitconfig` 查找此文件。

如果设置了 *`GIT_CONFIG_NOSYSTEM`*，就禁用系统级别的配置文件。
  这在系统配置影响了你的命令，而你又无权限修改的时候很有用。

*`GIT_PAGER`* 控制在命令行上显示多页输出的程序。
如果这个没有设置，就会用 `PAGER` 。

*`GIT_EDITOR`* 当用户需要编辑一些文本（比如提交信息）时， Git 会启动这个编辑器。
如果没设置，就会用 `EDITOR` 。


==== 版本库位置

Git 用了几个变量来确定它如何与当前版本库交互。

*`GIT_DIR`* 是 `.git` 目录的位置。
如果这个没有设置， Git 会按照目录树逐层向上查找 `.git` 目录，直到到达 `~` 或 `/`。

*`GIT_CEILING_DIRECTORIES`* 控制查找 `.git` 目录的行为。
如果你访问加载很慢的目录（如那些磁带机上的或通过网络连接访问的），你可能会想让 Git 早点停止尝试，尤其是 shell 构建时调用了 Git 。

*`GIT_WORK_TREE`* 是非空版本库的工作目录的根路径。
如果没指定，就使用 `$GIT_DIR` 的父目录。

*`GIT_INDEX_FILE`* 是索引文件的路径（只有非空版本库有）。

*`GIT_OBJECT_DIRECTORY`* 用来指定 `.git/objects` 目录的位置。

*`GIT_ALTERNATE_OBJECT_DIRECTORIES`* 一个冒号分割的列表 (格式类似 `/dir/one:/dir/two:…`) 用来告诉 Git 到哪里去找不在 `GIT_OBJECT_DIRECTORY` 目录中的对象。
如果你有很多项目有相同内容的大文件，这个可以用来避免存储过多备份。


==== 路径规则

所谓 ``pathspec'' 是指你在 Git 中如何指定路径， 包括通配符的使用。
它们会在 `.gitignore` 文件中用到，命令行里也会用到 （`git add *.c`）。

*`GIT_GLOB_PATHSPECS` and `GIT_NOGLOB_PATHSPECS`* 控制通配符在路径规则中的默认行为。
如果 `GIT_GLOB_PATHSPECS` 设置为 1, 通配符表现为通配符（这是默认设置）; 如果 `GIT_NOGLOB_PATHSPECS` 设置为 1,通配符仅匹配字面。意思是 `*.c` 只会匹配 _文件名是_ ``*.c'' 的文件， 而不是以 `.c` 结尾的文件。
你可以在各个路径规格中用 `:(glob)` 或 `:(literal)` 开头来覆盖这个配置，如 `:(glob)*.c` 。

*`GIT_LITERAL_PATHSPECS`* 禁用上面的两种行为；通配符将不能用，前缀覆盖也不能用。

*`GIT_ICASE_PATHSPECS`* 让所有的路径规格忽略大小写。


==== 提交

Git 提交对象的创建通常最后是由 `git-commit-tree` 来完成， `git-commit-tree` 用这些环境变量作主要的信息源。 仅当这些值不存在才回退到预置的值。

*`GIT_AUTHOR_NAME`* 是 ``author'' 字段的可读的名字。

*`GIT_AUTHOR_EMAIL`* 是 ``author'' 字段的邮件。

*`GIT_AUTHOR_DATE`* 是 ``author'' 字段的时间戳。

*`GIT_COMMITTER_NAME`* 是 ``committer'' 字段的可读的名字。

*`GIT_COMMITTER_EMAIL`* 是 ``committer'' 字段的邮件。

*`GIT_COMMITTER_DATE`* 是 ``committer'' 字段的时间戳。

如果 `user.email` 没有配置， 就会用到 *`EMAIL`* 指定的邮件地址。
如果 _这个_ 也没有设置， Git 继续回退使用系统用户和主机名。


==== 网络

Git 使用 `curl` 库通过 HTTP来完成网络操作， 所以 *`GIT_CURL_VERBOSE`* 告诉 Git 显示所有由那个库产生的消息。
这跟在命令行执行 `curl -v` 差不多。

*`GIT_SSL_NO_VERIFY`* 告诉 Git 不用验证 SSL 证书。
这在有些时候是需要的， 例如你用一个自己签名的证书通过 HTTPS 来提供 Git 服务， 或者你正在搭建 Git 服务器，还没有安装完全的证书。


如果 Git 操作在网速低于 *`GIT_HTTP_LOW_SPEED_LIMIT`* 字节／秒，并且持续 *`GIT_HTTP_LOW_SPEED_TIME`* 秒以上的时间，Git 会终止那个操作。
这些值会覆盖 `http.lowSpeedLimit` 和 `http.lowSpeedTime` 配置的值。

*`GIT_HTTP_USER_AGENT`* 设置 Git 在通过 HTTP 通讯时用到的 user-agent。
默认值类似于 `git/2.0.0` 。


==== 比较和合并

*`GIT_DIFF_OPTS`* 这个有点起错名字了。
有效值仅支持 `-u<n>` 或 `--unified=<n>`，用来控制在 `git diff` 命令中显示的内容行数。

*`GIT_EXTERNAL_DIFF`* 用来覆盖 `diff.external` 配置的值。
如果设置了这个值， 当执行 `git diff` 时，Git 会调用该程序。

*`GIT_DIFF_PATH_COUNTER`* 和 *`GIT_DIFF_PATH_TOTAL`* 对于 `GIT_EXTERNAL_DIFF` 或 `diff.external` 指定的程序有用。
前者表示在一系列文件中哪个是被比较的（从 1 开始），后者表示每批文件的总数。

*`GIT_MERGE_VERBOSITY`* 控制递归合并策略的输出。
允许的值有下面这些：

* 0 什么都不输出，除了可能会有一个错误信息。
* 1 只显示冲突。
* 2 还显示文件改变。
* 3 显示因为没有改变被跳过的文件。
* 4 显示处理的所有路径。
* 5 显示详细的调试信息。

默认值是 2。

==== 调试

想 _真正地_ 知道 Git 正在做什么?
Git 内置了相当完整的跟踪信息，你需要做的就是把它们打开。
这些变量的可用值如下：

* ``true'', ``1'', 或 ``2'' – 跟踪类别写到标准错误输出。
* 以 `/` 开头的绝对路径 – 跟踪输出会被写到那个文件。

*`GIT_TRACE`* 控制常规跟踪，它并不适用于特殊情况。
它跟踪的范围包括别名的展开和其他子程序的委托。

[source,console]
----
$ GIT_TRACE=true git lga
20:12:49.877982 git.c:554               trace: exec: 'git-lga'
20:12:49.878369 run-command.c:341       trace: run_command: 'git-lga'
20:12:49.879529 git.c:282               trace: alias expansion: lga => 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.879885 git.c:349               trace: built-in: git 'log' '--graph' '--pretty=oneline' '--abbrev-commit' '--decorate' '--all'
20:12:49.899217 run-command.c:341       trace: run_command: 'less'
20:12:49.899675 run-command.c:192       trace: exec: 'less'
----

*`GIT_TRACE_PACK_ACCESS`* 控制访问打包文件的跟踪信息。
第一个字段是被访问的打包文件，第二个是文件的偏移量：

[source,console]
----
$ GIT_TRACE_PACK_ACCESS=true git status
20:10:12.081397 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 12
20:10:12.081886 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 34662
20:10:12.082115 sha1_file.c:2088        .git/objects/pack/pack-c3fa...291e.pack 35175
# […]
20:10:12.087398 sha1_file.c:2088        .git/objects/pack/pack-e80e...e3d2.pack 56914983
20:10:12.087419 sha1_file.c:2088        .git/objects/pack/pack-e80e...e3d2.pack 14303666
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
----

*`GIT_TRACE_PACKET`* 打开网络操作包级别的跟踪信息。

[source,console]
----
$ GIT_TRACE_PACKET=true git ls-remote origin
20:15:14.867043 pkt-line.c:46           packet:          git< # service=git-upload-pack
20:15:14.867071 pkt-line.c:46           packet:          git< 0000
20:15:14.867079 pkt-line.c:46           packet:          git< 97b8860c071898d9e162678ea1035a8ced2f8b1f HEAD\0multi_ack thin-pack side-band side-band-64k ofs-delta shallow no-progress include-tag multi_ack_detailed no-done symref=HEAD:refs/heads/master agent=git/2.0.4
20:15:14.867088 pkt-line.c:46           packet:          git< 0f20ae29889d61f2e93ae00fd34f1cdb53285702 refs/heads/ab/add-interactive-show-diff-func-name
20:15:14.867094 pkt-line.c:46           packet:          git< 36dc827bc9d17f80ed4f326de21247a5d1341fbc refs/heads/ah/doc-gitk-config
# […]
----

*`GIT_TRACE_PERFORMANCE`* 控制性能数据的日志打印。
输出显示了每个 Git 命令调用花费的时间。

[source,console]
----
$ GIT_TRACE_PERFORMANCE=true git gc
20:18:19.499676 trace.c:414             performance: 0.374835000 s: git command: 'git' 'pack-refs' '--all' '--prune'
20:18:19.845585 trace.c:414             performance: 0.343020000 s: git command: 'git' 'reflog' 'expire' '--all'
Counting objects: 170994, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (43413/43413), done.
Writing objects: 100% (170994/170994), done.
Total 170994 (delta 126176), reused 170524 (delta 125706)
20:18:23.567927 trace.c:414             performance: 3.715349000 s: git command: 'git' 'pack-objects' '--keep-true-parents' '--honor-pack-keep' '--non-empty' '--all' '--reflog' '--unpack-unreachable=2.weeks.ago' '--local' '--delta-base-offset' '.git/objects/pack/.tmp-49190-pack'
20:18:23.584728 trace.c:414             performance: 0.000910000 s: git command: 'git' 'prune-packed'
20:18:23.605218 trace.c:414             performance: 0.017972000 s: git command: 'git' 'update-server-info'
20:18:23.606342 trace.c:414             performance: 3.756312000 s: git command: 'git' 'repack' '-d' '-l' '-A' '--unpack-unreachable=2.weeks.ago'
Checking connectivity: 170994, done.
20:18:25.225424 trace.c:414             performance: 1.616423000 s: git command: 'git' 'prune' '--expire' '2.weeks.ago'
20:18:25.232403 trace.c:414             performance: 0.001051000 s: git command: 'git' 'rerere' 'gc'
20:18:25.233159 trace.c:414             performance: 6.112217000 s: git command: 'git' 'gc'
----

*`GIT_TRACE_SETUP`* 显示 Git 发现的关于版本库和交互环境的信息。

[source,console]
----
$ GIT_TRACE_SETUP=true git status
20:19:47.086765 trace.c:315             setup: git_dir: .git
20:19:47.087184 trace.c:316             setup: worktree: /Users/ben/src/git
20:19:47.087191 trace.c:317             setup: cwd: /Users/ben/src/git
20:19:47.087194 trace.c:318             setup: prefix: (null)
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
----

==== 其它

如果指定了 *`GIT_SSH`*， Git 连接 SSH 主机时会用指定的程序代替 `ssh` 。
它会被用 `$GIT_SSH [username@]host [-p <port>] <command>` 的命令方式调用。
这不是配置定制 `ssh` 调用方式的最简单的方法; 它不支持额外的命令行参数， 所以你必须写一个封装脚本然后让 `GIT_SSH` 指向它。
可能用 `~/.ssh/config` 会更简单。

*`GIT_ASKPASS`* 覆盖了 `core.askpass` 配置。
这是 Git 需要向用户请求验证时用到的程序，它接受一个文本提示作为命令行参数，并在 `stdout` 中返回应答。
(查看 <<ch07-git-tools#r_credential_caching>>_ 访问更多相关内容)

*`GIT_NAMESPACE`* 控制有命令空间的引用的访问，与 `--namespace` 标志是相同的。
这主要在服务器端有用， 如果你想在一个版本库中存储单个版本库的多个 fork, 只要保持引用是隔离的就可以。

*`GIT_FLUSH`* 强制 Git 在向标准输出增量写入时使用没有缓存的 I/O。
设置为 1 让 Git 刷新更多， 设置为 0 则使所有的输出被缓存。
默认值（若此变量未设置）是根据活动和输出模式的不同选择合适的缓存方案。

*`GIT_REFLOG_ACTION`* 让你可以指定描述性的文字写到 reflog 中。
这有个例子：

[source,console]
----
$ GIT_REFLOG_ACTION="my action" git commit --allow-empty -m 'my message'
[master 9e3d55a] my message
$ git reflog -1
9e3d55a HEAD@{0}: my action: my message
----
