Git 故障排除
使用 Git 时,有时事情不会按预期工作。这里有一些关于排查和解决 Git 问题的技巧。
调试
在排查 Git 问题时,尝试以下调试技巧。
为 Git 命令使用自定义 SSH 密钥
GIT_SSH_COMMAND="ssh -i ~/.ssh/gitlabadmin" git <command>调试克隆问题
对于 SSH 上的 Git:
GIT_SSH_COMMAND="ssh -vvv" git clone <git@url>对于 HTTPS 上的 Git:
GIT_TRACE_PACKET=1 GIT_TRACE=2 GIT_CURL_VERBOSE=1 git clone <url>使用跟踪调试 Git
Git 包含一套完整的 调试 Git 命令的跟踪,例如:
GIT_TRACE_PERFORMANCE=1:启用性能数据跟踪,显示每次git调用所需的时间。GIT_TRACE_SETUP=1:启用git正在发现关于其交互的仓库和环境的信息的跟踪。GIT_TRACE_PACKET=1:启用网络操作的包级别跟踪。GIT_CURL_VERBOSE=1:启用curl的详细输出,可能包含凭据。
git push 时的管道错误
尝试推送到远程仓库时,可能会出现"管道错误"。推送时通常看到:
Write failed: Broken pipe
fatal: The remote end hung up unexpectedly要解决此问题,这里有一些可能的解决方案。
增加 Git 中的 POST 缓冲区大小
当通过 HTTPS 使用 Git 推送大型仓库时,可能会收到类似以下的错误消息:
fatal: pack has bad object at offset XXXXXXXXX: inflate returned -5要解决此问题:
-
在本地 Git 配置中增加 http.postBuffer 值。默认值为 1 MB。例如,如果
git clone在克隆 500 MB 仓库时失败,请执行以下操作:-
打开终端或命令提示符。
-
增加
http.postBuffer值:# 设置 http.postBuffer 大小(字节) git config http.postBuffer 524288000
-
如果本地配置不能解决问题,您可能需要修改服务器配置。 这应该谨慎操作,并且仅在您有服务器访问权限时进行。
-
在服务器端增加
http.postBuffer:-
打开终端或命令提示符。
-
修改 GitLab 实例的
gitlab.rb文件:gitaly['configuration'] = { # ... git: { # ... config: [ # 设置 http.postBuffer 大小(字节) {key: "http.postBuffer", value: "524288000"}, ], }, } -
应用配置更改:
sudo gitlab-ctl reconfigure
-
流程 0 未正确关闭
如果您看到此错误,可能是由于网络连接缓慢造成的:
RPC failed; curl 92 HTTP/2 stream 0 was not closed cleanly: INTERNAL_ERROR (err 2)如果您使用 HTTP 而不是 SSH 使用 Git,请尝试以下修复方法:
- 使用
git config http.postBuffer 52428800增加 Git 配置中的 POST 缓冲区大小。 - 使用
git config http.version HTTP/1.1切换到HTTP/1.1协议。
如果这两种方法都不能解决错误,您可能需要更换互联网服务提供商。
检查您的 SSH 配置
如果通过 SSH 推送,首先检查您的 SSH 配置,因为"管道错误" 有时可能是由 SSH 的潜在问题(如身份验证)引起的。 请按照 SSH 故障排除 文档中的说明确保 SSH 配置正确。
如果您是有服务器访问权限的 GitLab 管理员,您还可以通过在客户端或服务器上配置 SSH keep-alive 来防止会话超时。
同时配置客户端和服务器是不必要的。
要在客户端配置 SSH:
-
在 UNIX 系统上,编辑
~/.ssh/config(如果文件不存在则创建它)并 添加或编辑:Host your-gitlab-instance-url.com ServerAliveInterval 60 ServerAliveCountMax 5 -
在 Windows 上,如果您使用 PuTTY,请转到您的会话属性,然后 转到"Connection"并在"Sending of null packets to keep session active"下,将
Seconds between keepalives (0 to turn off)设置为60。
要在服务器端配置 SSH,请编辑 /etc/ssh/sshd_config 并添加:
ClientAliveInterval 60
ClientAliveCountMax 5运行 git repack
如果还显示"pack-objects"类型的错误,您可以尝试在
再次尝试推送到远程仓库之前运行 git repack:
git repack
git push升级您的 Git 客户端
如果您运行的是旧版本的 Git(< 2.9),请考虑升级 到 >= 2.9(参见 推送到 Git 仓库时的管道错误)。
ssh_exchange_identification 错误
用户在使用 SSH 通过 Git 尝试推送或拉取时可能会遇到以下错误:
Please make sure you have the correct access rights
and the repository exists.
...
ssh_exchange_identification: read: Connection reset by peer
fatal: Could not read from remote repository.或
ssh_exchange_identification: Connection closed by remote host
fatal: The remote end hung up unexpectedly或
kex_exchange_identification: Connection closed by remote host
Connection closed by x.x.x.x port 22此错误通常表示 SSH 守护进程的 MaxStartups 值正在限制
SSH 连接。此设置指定到 SSH 守护进程的并发未认证
连接的最大数量。这会影响具有正确身份验证
凭据(SSH 密钥)的用户,因为每个连接在开始时都是"未认证"的。默认值 为 10。
可以通过检查主机的 sshd
日志来验证这一点。对于 Debian 系统的发行版,请参考 /var/log/auth.log,对于 RHEL 衍生版,
检查 /var/log/secure 是否有以下错误:
sshd[17242]: error: beginning MaxStartups throttling
sshd[17242]: drop connection #1 from [CLIENT_IP]:52114 on [CLIENT_IP]:22 past MaxStartups如果没有此错误,表示 SSH 守护进程没有限制连接, 表明潜在问题可能与网络相关。
增加未认证并发 SSH 连接的数量
通过在 /etc/ssh/sshd_config 中添加或修改值来增加 GitLab 服务器上的 MaxStartups:
MaxStartups 100:30:200100:30:200 表示最多允许 100 个 SSH 会话不受限制,
之后 30% 的连接将被丢弃,直到达到绝对最大值 200。
修改 MaxStartups 的值后,检查配置中是否有任何错误。
sudo sshd -t -f /etc/ssh/sshd_config如果配置检查运行没有错误,则可以安全地重启 SSH 守护进程以使更改生效。
# Debian/Ubuntu
sudo systemctl restart ssh
# CentOS/RHEL
sudo service sshd restartgit push / git pull 期间超时
如果从/向您的仓库拉取/推送耗时超过 50 秒, 则会发出超时。它包含执行的操作数量及其各自时间的日志, 如下例所示:
remote: Running checks for branch: master
remote: Scanning for LFS objects... (153ms)
remote: Calculating new repository size... (cancelled after 729ms)这可用于进一步调查哪个操作执行不佳, 并向 GitLab 提供有关如何改进服务的更多信息。
错误:操作超时
如果您在使用 Git 时遇到此类错误,通常表示存在网络问题:
ssh: connect to host gitlab.com port 22: Operation timed out
fatal: Could not read from remote repository要帮助识别潜在问题:
- 通过不同的网络连接(例如,从 Wi-Fi 切换到蜂窝数据)以排除 本地网络或防火墙问题。
- 运行此 bash 命令收集
traceroute和ping信息:mtr -T -P 22 <gitlab_server>.com。 要了解 MTR 及如何读取其输出,请参阅 Cloudflare 文章 什么是 My Traceroute (MTR)?。
错误:传输关闭时仍有未读取的数据剩余
有时,当通过 HTTP 克隆旧仓库或大型仓库时,运行 git clone 时会显示以下错误:
error: RPC failed; curl 18 transfer closed with outstanding read data remaining
fatal: The remote end hung up unexpectedly
fatal: early EOF
fatal: index-pack failed这个问题在 Git 本身中很常见,因为它无法处理大文件或大量文件。 Git LFS 的创建是为了解决这个问题;然而,即使它也有局限性。这通常是由于以下原因之一:
- 仓库中的文件数量。
- 历史记录中的修订数量。
- 仓库中存在大文件。
如果在克隆大型仓库时发生此错误,您可以
减少克隆深度 到 1 的值。例如:
这种方法不能解决根本原因,但您可以成功克隆仓库。
要将克隆深度减少到 1,请运行:
variables:
GIT_DEPTH: 1LDAP 用户通过 SSH 进行 Git fetch 时密码过期错误
如果在 GitLab 自托管版上 git fetch 返回此 HTTP 403 Forbidden 错误,
GitLab 数据库中此用户的密码过期日期(users.password_expires_at)是一个过去的日期:
Your password expired. Please access GitLab from a web browser to update your password.使用 SSO 账户且 password_expires_at 不为 null 的请求会返回此错误:
"403 Forbidden - Your password expired. Please access GitLab from a web browser to update your password."要解决此问题,您可以通过以下方式更新密码过期日期:
-
使用 GitLab Rails 控制台 检查和更新用户数据:
user = User.find_by_username('<USERNAME>') user.password_expired? user.password_expires_at user.update!(password_expires_at: nil) -
使用
gitlab-psql:# gitlab-psql UPDATE users SET password_expires_at = null WHERE username='<USERNAME>';
此错误在 此问题 中报告。
Git fetch 错误:“HTTP Basic: Access Denied”
如果您在使用 HTTP(S) 通过 Git 时收到 HTTP Basic: Access denied 错误,
请参考 双因素身份验证故障排除指南。
此错误也可能在使用 Git for Windows 2.46.0 及更高版本时发生,当指定空用户名时。 使用令牌进行身份验证时,用户名可以是任何值,但空值 可能会触发身份验证错误。要解决此问题,请指定用户名字符串。
成功 git clone 期间记录的 401 错误
使用 HTTP 克隆仓库时,
production_json.log 文件
可能会显示初始状态为 401(未授权),随后快速变为 200。
{
"method":"GET",
"path":"/group/project.git/info/refs",
"format":"*/*",
"controller":"Repositories::GitHttpController",
"action":"info_refs",
"status":401,
"time":"2023-04-18T22:55:15.371Z",
"remote_ip":"x.x.x.x",
"ua":"git/2.39.2",
"correlation_id":"01GYB98MBM28T981DJDGAD98WZ",
"duration_s":0.03585
}
{
"method":"GET",
"path":"/group/project.git/info/refs",
"format":"*/*",
"controller":"Repositories::GitHttpController",
"action":"info_refs",
"status":200,
"time":"2023-04-18T22:55:15.714Z",
"remote_ip":"x.x.x.x",
"user_id":1,
"username":"root",
"ua":"git/2.39.2",
"correlation_id":"01GYB98MJ0CA3G9K8WDH7HWMQX",
"duration_s":0.17111
}对于通过 HTTP 执行的每个 Git 操作,您应该期望此初始 401 日志条目,
这是由于 HTTP Basic 身份验证 的工作方式。
当 Git 客户端启动克隆时,发送到 GitLab 的初始请求不提供
任何身份验证详细信息。GitLab 为该请求返回 401 Unauthorized 结果。
几毫秒后,Git 客户端发送包含身份验证详细信息的后续请求。
第二个请求应该成功,并产生 200 OK 日志条目。
如果 401 日志条目缺少相应的 200 日志条目,Git 客户端可能正在使用:
- 错误的密码。
- 过期或被撤销的令牌。
如果不纠正,您可能会遇到
403(禁止)错误。
通过 HTTP 执行 Git 操作时的 403 错误
通过 HTTP 执行 Git 操作时,403(禁止)错误表示
您的 IP 地址已被身份验证失败禁止:
fatal: unable to access 'https://gitlab.com/group/project.git/': The requested URL returned error: 403可以在 production_json.log 中看到 403:
{
"method":"GET",
"path":"/group/project.git/info/refs",
"format":"*/*",
"controller":"Repositories::GitHttpController",
"action":"info_refs",
"status":403,
"time":"2023-04-19T22:14:25.894Z",
"remote_ip":"x.x.x.x",
"user_id":1,
"username":"root",
"ua":"git/2.39.2",
"correlation_id":"01GYDSAKAN2SPZPAMJNRWW5H8S",
"duration_s":0.00875
}如果您的 IP 地址被阻止,auth_json.log 中存在相应的日志条目:
{
"severity":"ERROR",
"time":"2023-04-19T22:14:25.893Z",
"correlation_id":"01GYDSAKAN2SPZPAMJNRWW5H8S",
"message":"Rack_Attack",
"env":"blocklist",
"remote_ip":"x.x.x.x",
"request_method":"GET",
"path":"/group/project.git/info/refs?service=git-upload-pack"}身份验证失败限制根据您使用的是 GitLab 自托管版 还是 GitLab SaaS 而有所不同。