- 开发工具
【免费下载链接】isomorphic-git
A pure JavaScript implementation of git for node and browsers!
isomorphic-git 是一套纯 JavaScript 实现的 Git 库,可在 Node.js 与浏览器中运行。当各类 git 操作(clone、fetch、push、checkout、commit 等)失败时,它会抛出带有稳定code标识的错误对象。本文以仓库中 errors.md(version-0.70.7) 的 Error Codes 索引为骨架,结合 src/errors 目录下的真实实现与 test-GitError.js 测试用例,系统梳理每个错误码的触发场景、参数占位符含义与常见处置方案,帮助你在业务代码中按错误码精确分支处理,快速定位故障根因。
一、错误码机制:stable code、data 与序列化
错误对象从哪来
在isomorphic-git中,所有 API 命令抛出的错误都继承自 src/errors/BaseError.js 中的BaseError,它扩展了原生Error:
export class BaseError extends Error { constructor(message) { super(message) this.caller = '' } toJSON() { return { code: this.code, data: this.data, caller: this.caller, message: this.message, stack: this.stack, } } get isIsomorphicGitError() { return true } }每个具体错误类都遵循同一套模式:构造函数接收若干语义化参数,拼装出人类可读的message,同时把结构化信息写入this.data,并通过静态属性声明稳定错误码,例如 CheckoutConflictError.js:
CheckoutConflictError.code = 'CheckoutConflictError'因此,每个错误类都有三个可靠的信息来源:
err.code:与类名一致的稳定字符串,是程序分支判定的首选依据;err.data:携带触发错误的上下文数据(如冲突文件列表、HTTP 状态码、OID 等);err.message:面向人类阅读的完整描述文本;err.isIsomorphicGitError:恒为true,用于区分库自身错误与其他异常。
为什么用 code 而不是 message 做判断
错误消息文本在版本演进中可能调整措辞(对比本页 version-0.70.7 与 当前 docs 中的 alphabetic 索引 可见部分消息已变化),而code作为契约保持稳定。这一点也被测试明确守护:tests/test-GitError.js 遍历所有错误类,断言「类名 === 静态 code」,确保不会出现错配。
错误如何跨进程/跨请求传递
BaseError提供了toJSON()与fromJSON(),将错误序列化为{ code, data, caller, message, stack }结构,再反序列化为BaseError实例。这意味着在浏览器 Worker、Node 子进程或服务端日志之间传递错误时,可以保留code与data而不丢失关键诊断信息。
二、按功能域速查:错误码总览与触发场景
version-0.70.7 的 errors.md 共列出 68 个错误码。为便于检索,本文按触发域将其归类如下(消息中的{占位符}为实际注入的动态值)。
1. 锁文件与并发安全
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
AcquireLockFileFail | Unable to acquire lockfile "{ filename }". Exhausted tries. | 多次尝试后仍无法获取.git/index.lock等锁文件,常见于多个进程并发写仓库 |
DoubleReleaseLockFileFail | Cannot double-release lockfile "{ filename }". | 对同一锁文件重复释放,说明锁管理逻辑被调用了两次 |
从仓库结构看,锁机制封装在 src/utils/lock.js,由 src/managers/GitIndexManager.js 等管理器在读写 index 时调用,用于保证对同一仓库的写操作串行化。如果你的程序用 worker 并发执行写操作,需要注意同一仓库目录不能同时被两个进程写入。
2. 参数校验与调用契约
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
MissingRequiredParameterError | The function "{ function }" requires a "{ parameter }" parameter but none was provided. | 调用 API 时缺少必需参数(如未传fs、dir、ref)。对应实现见 MissingParameterError.js,data.parameter指出缺的是哪个参数 |
InvalidParameterCombinationError | The function "{ function }" doesn't take these parameters simultaneously: { parameters } | 同时传入了互斥参数,如username/password与oauth2format混用 |
DirectorySeparatorsError | "filepath" parameter should not include leading or trailing directory separators ... | 文件路径参数含首尾/或\,在某些平台会导致解析异常 |
InvalidDepthParameterError | Invalid value for depth parameter: { depth } | depth参数不是合法数值(应为正整数) |
MissingUsernameError/MissingPasswordTokenError/MissingTokenError | Missing username / Missing password or token / Missing token | 认证所需字段缺失 |
参数校验的通用逻辑集中在 src/utils/assertParameter.js,各 API 入口(src/api)在调用底层命令前先做参数断言。
3. 引用(Ref)操作
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
RefExistsError | Failed to create { noun } "{ ref }" because { noun } "{ ref }" already exists. | 创建分支/标签时目标 ref 已存在 |
RefNotExistsError | Failed to { verb } { noun } "{ ref }" because { noun } "{ ref }" does not exists. | 删除/重命名不存在的 ref |
InvalidRefNameError | Failed to { verb } { noun } "{ ref }" because that name would not be a valid git reference. A valid alternative would be "{ suggestion }". | ref 名不合法,错误还附带了合法替代名建议,对应实现见 InvalidRefNameError.js |
MismatchRefValueError | Provided oldValue doesn't match the actual value of "{ ref }". | writeRef传入oldValue校验失败(CAS 语义) |
ResolveRefError | Could not resolve reference "{ ref }". | 无法把 ref 解析为 OID |
ExpandRefError | Could not expand reference "{ ref }". | 缩写 ref(如main)无法唯一展开 |
BranchDeleteError | Failed to delete branch "{ ref }" because branch "{ ref }" checked out now. | 尝试删除当前已检出的分支 |
NoHeadCommitError | Failed to create { noun } "{ ref }" because the HEAD ref could not be resolved to a commit. | HEAD 无法解析到提交,创建分支等操作失败 |
ref 解析的底层实现在 src/managers/GitRefManager.js,它同时处理 loose refs 与 packed-refs(GitPackedRefs.js)。
4. 对象存储(Object 读写)
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
ReadObjectFail | Failed to read git object with oid { oid } | 按 OID 读取对象失败 |
NotAnOidFail | Expected a 40-char hex object id but saw "{ value }". | 传入的 OID 不是 40 位十六进制字符串 |
ShortOidNotFound | Could not find an object matching "{ short }". | 缩写 OID 找不到对应对象 |
AmbiguousShortOid | Found multiple oids matching "{ short }" ({ matches }). Use a longer abbreviation length to disambiguate them. | 缩写 OID 命中多个对象,需要更长缩写;实现见 AmbiguousError.js |
CorruptShallowOidFail | non-40 character shallow oid: { oid } | shallow 文件中出现非法 OID |
ObjectTypeUnknownFail | Object { oid } has unknown type "{ type }". | 对象类型非法(非 blob/commit/tree/tag) |
ObjectTypeAssertionFail | Object { oid } was anticipated to be a { expected } but it is a { type }. This is probably a bug deep in isomorphic-git! | 对象类型与预期不符;实现见 ObjectTypeError.js |
ObjectTypeAssertionInPathFail | Found a blob { oid } in the path "{ path }" where a tree was expected. | 路径遍历时遇到 blob 而非 tree |
ObjectTypeAssertionInRefFail | { ref } is not pointing to a "{ expected }" object but a "{ type }" object. | ref 指向的对象类型与命令预期不符 |
ObjectTypeAssertionInTreeFail | Object { oid } in tree for "{ entrypath }" was an unexpected object type "{ type }". | tree 条目中的对象类型异常 |
对象读取链路从 src/storage/readObject.js 进入,先查 loose objects(readObjectLoose.js)再查 packfile(readObjectPacked.js)。
5. 路径与工作区文件
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
FileReadError | Could not read file "{ filepath }". | 工作区文件读取失败 |
GitRootNotFoundError | Unable to find git root for { filepath }. | 向上查找.git目录失败 |
TreeOrBlobNotFoundError | No file or directory found at "{ oid }:{ filepath }". | 指定 OID 与路径下不存在文件或目录 |
DirectoryIsAFileError | Unable to read "{ oid }:{ filepath }" because encountered a file where a directory was expected. | 遍历时文件与目录冲突 |
文件系统抽象层由 src/models/FileSystem.js 提供,git root查找逻辑在 src/utils/discoverGitdir.js。
6. 网络、HTTP 与传输协议
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
HTTPError | HTTP Error: { statusCode } { statusMessage } | 服务器返回非 200 状态;data中会携带statusCode、statusMessage与response响应体,实现见 HttpError.js |
EmptyServerResponseFail | Empty response from git server. | 服务器返回空响应 |
UnparseableServerResponseFail | Unparsable response from server! Expected "unpack ok" or "unpack [error message]" but received "{ line }". | push 响应中unpack行无法解析 |
AssertServerResponseFail | Expected "{ expected }" but got "{ actual }". | 服务器响应内容与协议预期不符 |
RemoteDoesNotSupportSmartHTTP | Remote did not reply using the "smart" HTTP protocol. Expected "001e# service=git-upload-pack" but received: { preview } | 远端不支持 smart HTTP 协议(如纯 dumb HTTP 服务器) |
RemoteDoesNotSupportShallowFail/RemoteDoesNotSupportDeepenSinceFail/RemoteDoesNotSupportDeepenRelativeFail/RemoteDoesNotSupportDeepenNotFail | Remote does not support shallow fetches / by date / relative ... | 远端能力不支持对应的浅克隆(shallow fetch)类型 |
RemoteUrlParseError | Cannot parse remote URL: "{ url }" | 远端 URL 无法解析;对应实现为 UrlParseError.js |
UnknownTransportError | Git remote "{ url }" uses an unrecognized transport protocol: "{ transport }" | 传输协议不受支持;实现见 UnknownTransportError.js |
网络层实现在 src/managers/GitRemoteHTTP.js,它负责 HTTP 传输、smart 协议握手(# service=git-upload-pack应答)与 pkt-line 解析。
7. 认证与凭据
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
MissingUsernameError | Missing username | 需要用户名但未提供 |
MissingTokenError | Missing token | 需要 token 但未提供 |
MissingPasswordTokenError | Missing password or token | 密码与 token 均未提供 |
MixUsernamePasswordTokenError | Cannot mix "username" and "password" with "token" | 同时传了username/password与token |
MixPasswordTokenError | Cannot mix "password" with "token" | 同时传了password与token |
MixPasswordOauth2formatMissingTokenError/MixPasswordOauth2formatTokenError | Cannot mix "password" with "oauth2format". Missing token. / ... and "token" | password与oauth2format混用 |
MixUsernameOauth2formatMissingTokenError/MixUsernameOauth2formatTokenError | Cannot mix "username" with "oauth2format". ... | username与oauth2format混用 |
MixUsernamePasswordOauth2formatMissingTokenError/MixUsernamePasswordOauth2formatTokenError | Cannot mix "username" and "password" with "oauth2format". ... | 用户名密码与oauth2format混用 |
UnknownOauth2Format | I do not know how { company } expects its Basic Auth headers to be formatted for OAuth2 usage. ... | 未知的 OAuth2 服务商格式 |
这组错误提示了一个重要设计:username/password、token、oauth2format三套认证参数互相排斥。使用指南可参考 authentication.md(version-0.70.7) 与 docs/onAuth.md,推荐用onAuth回调动态返回认证凭据。
8. 推送(Push)服务端拒绝
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
PushRejectedNonFastForward | Push rejected because it was not a simple fast-forward. Use "force: true" to override. | 推送被拒,非快进合并;可用force: true强制覆盖 |
PushRejectedTagExists | Push rejected because tag already exists. Use "force: true" to override. | 推送的标签已存在;同样可用force: true覆盖 |
两个错误对应 PushRejectedError.js 中的'not-fast-forward'与'tag-exists'两种reason。注意:强制推送会改写远端历史,仅应在确认安全时使用。
9. 合并、检出与提交状态
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
CheckoutConflictError | Your local changes to the following files would be overwritten by checkout: { filepaths } | 检出会覆盖本地未提交修改;data.filepaths为冲突文件列表,见 CheckoutConflictError.js |
CommitNotFetchedError | Failed to checkout "{ ref }" because commit { oid } is not available locally. Do a git fetch ... | 目标提交本地不存在,需先 fetch |
FastForwardFail | A simple fast-forward merge was not possible. | 无法进行快进合并(如fastForwardOnly: true时) |
MergeNotSupportedFail | Merges with conflicts are not supported yet. | 产生冲突的合并暂不支持(0.70.x 时代的能力边界) |
NoRefspecConfiguredError | Could not find a fetch refspec for remote "{ remote }". ... | 远端缺少 fetch refspec 配置;消息中会给出应补充的 config 片段示例 |
MaxSearchDepthExceeded | Maximum search depth of { depth } exceeded. | 递归搜索(如 findRoot 向上遍历)超出最大深度 |
其中NoRefspecConfiguredError的提示信息非常实用——它会直接建议你在 config 中补充:
[remote "{ remote }"] fetch = +refs/heads/*:refs/remotes/origin/*10. 插件系统
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
CoreNotFound | No plugin core with the name "{ core }" is registered. | 未注册指定名称的 core |
PluginUndefined | A command required the "{ plugin }" plugin but it was undefined. | 命令依赖的插件(fs/http/credentialManager等)未提供 |
PluginUnrecognized | Unrecognized plugin type "{ plugin }" | 插件类型无法识别 |
PluginSchemaViolation | Schema check failed for "{ plugin }" plugin; missing { method } method. | 插件缺少必需的方法,不满足插件接口契约 |
插件机制通过 src/managers/index.js 注册与校验,浏览器端必须显式提供fs与http插件,详见 guide-fs.md(version-0.70.7)。
11. 其他内部与通用错误
| 错误码 | 消息模板 | 触发场景 |
|---|---|---|
InternalFail | An internal error caused this command to fail. Please file a bug report at ... | 库内部异常,通常伴随 bug,需要上报 |
NotImplementedFail | TODO: { thing } still needs to be implemented! | 调用了尚未实现的功能 |
AddingRemoteWouldOverwrite | Adding remote { remote } would overwrite the existing remote. Use "force: true" to override. | addRemote覆盖已有远端;用force: true覆盖 |
ResolveCommitError | Could not resolve { oid } to a commit. | OID 无法解析为 commit 对象 |
ResolveTreeError | Could not resolve { oid } to a tree. | OID 无法解析为 tree 对象 |
三、实战:按错误码编写分支处理代码
1. 通过Errors命名空间导入错误类
isomorphic-git 从顶层导出Errors命名空间(src/index.js),可以直接导入并按类判断:
import git, { Errors } from 'isomorphic-git' try { await git.checkout({ fs, dir, ref: 'feature-branch' }) } catch (err) { if (err instanceof Errors.CheckoutConflictError) { console.error('以下文件有本地修改,将被覆盖:', err.data.filepaths) } else if (err instanceof Errors.CommitNotFetchedError) { console.error('提交不存在,请先 fetch:', err.data.oid) } else if (err instanceof Errors.HttpError) { console.error(`HTTP ${err.data.statusCode} ${err.data.statusMessage}`) } else { throw err } }注意 errors/index.js(当前源码) 与 0.70.7 的错误类集合并不完全一一对应——如CheckoutConflictError、CommitNotFetchedError、HttpError、PushRejectedError等核心类在两条版本线上都存在,而部分*Fail风格的旧错误名在后续版本中已被重构为*Error命名。以当前安装版本实际导出的Errors为准。
2. 兜底记录完整错误信息
无法精确匹配时,应记录序列化后的完整错误,避免丢失code与data:
} catch (err) { if (err.isIsomorphicGitError && err.toJSON) { console.error(JSON.stringify(err.toJSON(), null, 2)) } else { console.error(err) } }toJSON()输出形如:
{ "code": "NotFoundError", "data": { "what": "foobar.txt" }, "caller": "", "message": "Could not find foobar.txt.", "stack": "..." }这正是 test-GitError.js 中断言的序列化结构。
四、常见故障排查速查表
| 报错场景 | 典型错误码 | 首要排查动作 |
|---|---|---|
| 检出时本地修改将被覆盖 | CheckoutConflictError | 查看data.filepaths,提交或丢弃对应修改 |
| 目标提交本地没有 | CommitNotFetchedError | 先执行fetch再checkout |
| 推送被拒绝 | PushRejectedNonFastForward/PushRejectedTagExists | 先pull合并;确需覆盖时显式传force: true |
| HTTP 层失败 | HTTPError | 检查data.statusCode、statusMessage与response,排查 URL、鉴权与网络 |
| 远端不支持 smart HTTP | RemoteDoesNotSupportSmartHTTP | 确认服务器(如 gogs/gitea 等)开启 git smart HTTP 支持 |
| 缺少必需参数 | MissingRequiredParameterError | 依据data.parameter补传参数 |
| 缩写 OID 不唯一 | AmbiguousShortOid | 加长 OID 缩写长度 |
| ref 名非法 | InvalidRefNameError | 按data.suggestion使用合法替代名 |
| 认证参数混用 | Mix*系列 | 只保留username/password、token、oauth2format三者之一 |
五、写在最后:错误码的演进与使用建议
- 以
code为程序判据:消息文本可能随版本变化,code才是稳定契约(test-GitError.js 保证类名与 code 一致)。 - 充分读取
data:多数错误把结构化上下文放入data(如冲突文件、HTTP 状态、OID、ref 名),比解析message更可靠。 - 0.70.7 属于较旧版本线:部分
*Fail命名(如AcquireLockFileFail、ReadObjectFail)在后续版本中已更名或合并,迁移到新版时需按新导出的Errors重新适配。 - 区分错误等级:
InternalFail与ObjectTypeAssertionFail提示库内部缺陷,应升级库或上报 issue;CheckoutConflictError、PushRejectedNonFastForward等则是业务可恢复错误,应在应用层友好处理。
如果需要在浏览器环境使用,请先配置fs与http插件并阅读 guide-quickstart.md(version-0.70.7) 与 guide-fs.md(version-0.70.7);命令行场景可参考 guide-cli.md(version-0.70.7)。掌握这套错误码体系,你的 isomorphic-git 应用就能做到"报错即定位、分支即处理"。
- 开发工具
【免费下载链接】isomorphic-git
A pure JavaScript implementation of git for node and browsers!
相关推荐
StarRocks 错误码(Error Codes)完整参考与排查指南
StarRocks 错误码(Error Codes)完整参考与排查指南 StarRocks 对外通过 MySQL 兼容协议提供查询服务,因此查询请求失败时会返回
数据库OLAP数据仓库大数据湖仓一体数据分析InspireFace 错误反馈码(Error Feedback Codes)完整指南:错误码表、数值结构与跨语言排查实践
InspireFace 错误反馈码(Error Feedback Codes)完整指南:错误码表、数值结构与跨语言排查实践 本文以 Error Feedback
人工智能计算机视觉深度学习CANN Runtime Profiling 错误码(EK 系列)排查指南:从错误信息到源码级定位
CANN Runtime Profiling 错误码(EK 系列)排查指南:从错误信息到源码级定位 导读 本文聚焦 CANN Runtime 中 Profili
CANNAscend人工智能性能剖析系统编程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考