章节 ▾ 第二版

10.8 Git 内部原理 - 环境变量

环境变量

Git 始终运行在 bash shell 中,并使用许多 shell 环境变量来确定其行为。了解这些变量及其用途,有助于根据需要自定义 Git 的行为。以下并非 Git 所关注的所有环境变量的详尽列表,但涵盖了最常用的部分。

全局行为

Git 作为计算机程序的某些通用行为取决于环境变量。

GIT_EXEC_PATH 决定了 Git 到哪里寻找其子程序(如 git-commitgit-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-dirGIT_DIR,但没有指定 --work-treeGIT_WORK_TREEcore.worktree,则当前工作目录被视为工作树的顶层。

GIT_INDEX_FILE 是索引文件的路径(仅适用于非裸仓库)。

GIT_OBJECT_DIRECTORY 可用于指定通常位于 .git/objects 的目录位置。

GIT_ALTERNATE_OBJECT_DIRECTORIES 是一个冒号分隔的列表(格式如 /dir/one:/dir/two:…),用于告诉 Git 如果对象不在 GIT_OBJECT_DIRECTORY 中,应到哪里查找。如果你有大量包含相同内容大文件的项目,可以使用此变量避免存储过多的重复副本。

路径规范 (Pathspecs)

“路径规范”(pathspec)指在 Git 中指定路径的方式,包括通配符的使用。它们不仅用于 .gitignore 文件,也用于命令行(例如 git add *.c)。

GIT_GLOB_PATHSPECSGIT_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_AUTHOR_NAME 是 “author”(作者)字段中可读的名字。

GIT_AUTHOR_EMAIL 是 “author”(作者)字段的电子邮件地址。

GIT_AUTHOR_DATE 是用于 “author”(作者)字段的时间戳。

GIT_COMMITTER_NAME 设置 “committer”(提交者)字段的名字。

GIT_COMMITTER_EMAIL 是 “committer”(提交者)字段的电子邮件地址。

GIT_COMMITTER_DATE 用于 “committer”(提交者)字段的时间戳。

EMAIL 是在未设置 user.email 配置值时的回退电子邮件地址。如果连此变量也未设置,Git 将回退使用系统用户和主机名。

网络

Git 使用 curl 库执行 HTTP 网络操作,因此 GIT_CURL_VERBOSE 会告诉 Git 输出该库生成的所有消息。这类似于在命令行执行 curl -v

GIT_SSL_NO_VERIFY 告诉 Git 不要验证 SSL 证书。如果你使用自签名证书通过 HTTPS 提供 Git 仓库,或者在尚未安装完整证书的情况下搭建 Git 服务器,这有时是必要的。

如果 HTTP 操作的数据速率低于 GIT_HTTP_LOW_SPEED_LIMIT 字节/秒的时间超过 GIT_HTTP_LOW_SPEED_TIME 秒,Git 将中止该操作。这些值会覆盖 http.lowSpeedLimithttp.lowSpeedTime 配置值。

GIT_HTTP_USER_AGENT 设置 Git 在通过 HTTP 通信时使用的用户代理字符串。默认值类似于 git#2.0.0

差异比较与合并

GIT_DIFF_OPTS 这个名称有点误导。唯一有效的取值是 -u<n>--unified=<n>,用于控制 git diff 命令中显示的上下文行数。

GIT_EXTERNAL_DIFF 用作 diff.external 配置值的覆盖项。如果已设置,当执行 git diff 时,Git 将调用该程序。

GIT_DIFF_PATH_COUNTERGIT_DIFF_PATH_TOTALGIT_EXTERNAL_DIFFdiff.external 指定的程序内部非常有用。前者表示当前正在比较的是序列中的第几个文件(从 1 开始),后者是该批次中的文件总数。

GIT_MERGE_VERBOSITY 控制递归合并策略的输出。允许的值如下:

  • 0 不输出任何内容,可能除了一条错误消息。

  • 1 仅显示冲突。

  • 2 同时显示文件更改。

  • 3 显示因未更改而被跳过的文件。

  • 4 显示处理过程中的所有路径。

  • 5 及以上显示详细的调试信息。

默认值为 2。

调试

真正了解 Git 的运行细节吗?Git 内置了一套相当完整的追踪系统,你只需要将其打开即可。这些变量的可能取值如下:

  • “true”、“1” 或 “2” —— 将追踪类别写入 stderr。

  • / 开头的绝对路径 —— 追踪输出将被写入该文件。

GIT_TRACE 控制通用追踪,不属于任何特定类别。这包括别名的扩展以及向其他子程序的委派。

$ 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 控制包文件(packfile)访问的追踪。第一个字段是被访问的包文件,第二个是文件内的偏移量。

$ 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 启用网络操作的包级别追踪。

$ 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 调用所花费的时间。

$ 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 如何发现其所交互的仓库和环境的信息。

$ 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_COMMAND,编写一个包装脚本并将 GIT_SSH 指向它,或者使用 ~/.ssh/config 文件。

GIT_SSH_COMMAND 设置 Git 尝试连接 SSH 主机时使用的 SSH 命令。该命令由 shell 解析,可以与 ssh 一起使用额外的命令行参数,例如 GIT_SSH_COMMAND="ssh -i ~/.ssh/my_key" git clone git@example.com:my/repo

GIT_ASKPASScore.askpass 配置值的覆盖项。每当 Git 需要询问用户凭据时,就会调用此程序。它将文本提示作为命令行参数,并应在 stdout 上返回答案(有关此子系统的更多信息,请参见 凭据存储)。

GIT_NAMESPACE 控制对命名空间引用的访问,等效于 --namespace 标志。这主要在服务器端有用,例如你可能希望在单个仓库中存储多个分支版本,同时保持引用分离。

GIT_FLUSH 可用于强制 Git 在增量写入 stdout 时使用无缓冲 I/O。值为 1 时 Git 会更频繁地刷新,值为 0 时所有输出都将被缓冲。默认值(如果未设置此变量)是根据活动和输出模式选择合适的缓冲方案。

GIT_REFLOG_ACTION 允许你指定写入 reflog 的描述性文本。示例如下:

$ 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