GitoxideLabs/gitoxide
GitHub: GitoxideLabs/gitoxide
Gitoxide 是一个用纯 Rust 实现的高性能 Git,旨在提供安全、快速且易于集成的 Git 操作能力,可作为库或命令行工具使用。
Stars: 11208 | Forks: 456
[](https://github.com/GitoxideLabs/gitoxide/actions)
[](https://crates.io/crates/gitoxide)
`gitoxide` 是一个用 Rust 编写的 `git` 实现,旨在开发追求正确性和性能的面向未来的应用程序,同时提供愉悦且符合预期的开发者体验。
使用 `gitoxide` 主要有两种方式:
1. **作为 Rust 库**:使用 [`gix`](https://docs.rs/gix) crate 作为 Cargo 依赖项以获取 API 访问权限。
2. **作为命令行工具**:`gix` 二进制文件作为开发工具,帮助在真实的代码库中测试 API,
以及带有工作流增强工具的 `ein` 二进制文件。这两个二进制文件可能永远是不稳定的,
*不要在脚本中依赖它们*。
[](https://asciinema.org/a/542159)
## 开发状态
命令行工具以及每个 crate 的状态在
[crate 状态文档](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md)中进行了描述。
用于应用程序时,请查找 [`gix`](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix) crate,
它作为各种低级底层 crate(例如 [`gix-config`](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-config))所提供功能的入口点。
### 功能探索
上述问题可能很难回答,本段落旨在帮助您进行功能探索。
请查看 [`crate-status.md`](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md),这是一份相当详尽的文档,其中包含
已实现和计划中的功能。
此外,[带有 `git2` 搜索词的 `gix` crate 文档](https://docs.rs/gix/latest/gix?search=git2)有助于找到所有目前
已知的 `git2` 等效方法调用。请注意,此列表绝对尚未详尽,但如果您是从 `git2` 转型而来,它可能会有所帮助。
以下是一个高级别的功能列表以及计划中的功能:
* [x] clone
* [x] fetch
* [ ] push
* [x] blame (*底层管道*)
* [x] status
* [x] blob 和 tree-diff
* [ ] merge
- [x] blobs
- [x] trees
- [ ] commits
* [x] commit
- [ ] hooks
* [x] commit-graph 遍历
* [ ] rebase
* [x] worktree checkout 和 worktree stream
* [ ] reset
* [x] 对象的读写
* [x] refs 的读写
* [x] `.git/index` 的读写
* [x] git 配置的读写
* [x] pathspecs
* [x] revspecs
* [x] `.gitignore` 和 `.gitattributes`
### Crates
点击链接的 crate 名称以查看详细状态。请注意,所有 crate 均遵循 [semver] 以及 [稳定性指南]。
### 生产级别
* **稳定性等级 1**
- [gix-lock](https://github.com/GitoxideLabs/gitoxide/blob/main/gix-lock/README.md)
* **稳定性等级 2**
- [gix-tempfile](https://github.com/GitoxideLabs/gitoxide/blob/main/gix-tempfile/README.md)
### 候选稳定版
这些 crate 似乎已功能完整,但需要更多的使用考验才能发布为 1.0 版本。
文档已完整且至少经过了一次审查。
* [gix-mailmap](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-mailmap)
* [gix-chunk](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-chunk)
* [gix-ref](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-ref)
* [gix-config](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-config)
* [gix-config-value](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-config-value)
* [gix-glob](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-glob)
* [gix-actor](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-actor)
* [gix-hash](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-hash)
### 初始开发阶段
这些 crate 可能缺少某些功能,因此略有欠缺,但现有部分
在某种程度上是可用的。
* **可用** _(具备粗略但完整的文档,功能可能不完整)_
* [gix](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix) (**⬅ 入口点**)
* [gix-object](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-object)
* [gix-validate](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-validate)
* [gix-url](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-url)
* [gix-packetline](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-packetline)
* [gix-packetline_blocking](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-packetline)
* [gix-transport](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-transport)
* [gix-protocol](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-protocol)
* [gix-pack](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-pack)
* [gix-odb](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-odb)
* [gix-commitgraph](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-commitgraph)
* [gix-diff](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-diff)
* [gix-traverse](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-traverse)
* [gix-features](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-features)
* [gix-credentials](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-credentials)
* [gix-sec](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-sec)
* [gix-quote](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-quote)
* [gix-discover](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-discover)
* [gix-path](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-path)
* [gix-attributes](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-attributes)
* [gix-ignore](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-ignore)
* [gix-pathspec](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-pathspec)
* [gix-index](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-index)
* [gix-revision](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-revision)
* [gix-revwalk](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-revwalk)
* [gix-command](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-command)
* [gix-prompt](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-prompt)
* [gix-refspec](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-refspec)
* [gix-fs](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-fs)
* [gix-utils](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-utils)
* [gix-hashtable](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-hashtable)
* [gix-worktree](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-worktree)
* [gix-bitmap](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-bitmap)
* [gix-negotiate](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-negotiate)
* [gix-filter](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-filter)
* [gix-worktree-stream](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-worktree-stream)
* [gix-archive](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-archive)
* [gix-submodule](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-submodule)
* [gix-status](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-status)
* [gix-worktree-state](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-worktree-state)
* [gix-date](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-date)
* [gix-dir](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-dir)
* [gix-merge](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-merge)
* [gix-shallow](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-shallow)
* [gix-error](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-error)
* `gitoxide-core`
* **非常早期** _(可能没有任何文档且有许多粗糙之处)_
* [gix-blame](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-blame)
* **构思** _(仅作为名称占位符)_
* [gix-note](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-note)
* [gix-fetchhead](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-fetchhead)
* [gix-lfs](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-lfs)
* [gix-rebase](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-rebase)
* [gix-sequencer](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-sequencer)
* [gix-tui](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-tui)
* [gix-tix](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-tix)
* [gix-bundle](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-bundle)
* [gix-fsck](https://github.com/GitoxideLabs/gitoxide/blob/main/crate-status.md#gix-fsck)
### 压力测试
* [x] 验证巨大的 pack
* [x] 将 pack 解包到磁盘
* [x] 生成并验证大型 commit graph
* [ ] 从大量松散对象生成巨大的 pack
### 稳定性和 MSRV
我们的[稳定性指南]有助于判断依赖此工作区中的 crate 时可能预期会有多少变动。
## 安装
### 下载二进制发行版
使用 `cargo binstall`,您可以获取[二进制发行版][releases]。假设已安装
[rust 工具链][rustup],您可以通过 `cargo install cargo-binstall` 来安装它。
然后使用 `cargo binstall gitoxide` 安装 gitoxide。
有关手动安装以及根据您的需求(适用于 _Linux_、_MacOS_ 和 _Windows_)提供的各种
_更精简_ 或 _更小巧_ 的替代构建版本,请参阅 [releases 部分][releases]。
### 从 Arch Linux 仓库下载
对于 Arch Linux,您可以从 `community` 仓库下载 `gitoxide`:
```
pacman -S gitoxide
```
### 从 Exherbo Linux Rust 仓库下载
对于 Exherbo Linux,您可以从 [Rust](https://gitlab.exherbo.org/exherbo/rust/-/tree/master/packages/dev-scm/gitoxide) 仓库下载 `gitoxide`:
```
cave resolve -x repository/rust
cave resolve -x gitoxide
```
### 通过 Cargo 从源码构建
`cargo` 是 Rust 的包管理器,可以通过 [rustup] 轻松获取。有了它,您可以毫不费力地为您的特定 CPU
构建自己的二进制文件,以获得额外的性能提升。
最低支持的 Rust 版本[已记录在 Cargo 包中](https://github.com/GitoxideLabs/gitoxide/blob/main/gix/Cargo.toml#L12-L14),
最新稳定版也同样适用。
有多种构建配置,它们均已[记录在此处](https://docs.rs/crate/gitoxide/latest)。该文档对于
需要调整外部依赖的打包者也应有所帮助。
```
# 一种在仅安装 Rust 和 C 编译器的情况下安装 `gitoxide` 的方法。
# 如果在 Clone 期间遇到 SSL 证书问题,请尝试省略 `--locked`。
cargo install gitoxide --locked --no-default-features --features max-pure
# 默认安装 'max' 速度最快,但也需要 `cmake` 才能成功构建。
# 安装过程取决于平台。
cargo install gitoxide
# 若要以牺牲不太出色的 CLI 实现为代价来换取更小的 Binaries 和更快的构建时间,
# 请使用 `lean` feature。
cargo install gitoxide --locked --no-default-features --features lean
```
以下命令可直接从 git 安装最新未发布的 `max` 版本:
```
cargo install --git https://github.com/GitoxideLabs/gitoxide gitoxide
```
#### 如何处理构建失败
在某些平台上,由于缺少 *C* 工具链所需的工具,安装可能会失败。通常可以通过以下安装方式来避免这种情况:
```
cargo install gitoxide --no-default-features --features max-pure
```
以下是已知失败的列表。
- 在 Fedora 上,需要安装 `perl` 才能使 `OpenSSL` 正确构建。这可以通过以下命令完成(参见 [issue #592](https://github.com/GitoxideLabs/gitoxide/issues/592)):
dnf install perl
### 使用 Docker
某些 CI/CD 流水线会利用代码库克隆。以下是一个可复制粘贴的示例,用于为此类工作流构建 Docker 镜像。
由于(目前)不存在官方镜像,因此必须首先构建一个镜像。
#### 构建最具兼容性的基础镜像
```
docker build -f etc/docker/Dockerfile.alpine -t gitoxide:latest --compress . --target=pipeline
```
#### 流水线中的基本用法
例如,如果一个 `Dockerfile` 当前使用类似 `RUN git clone https://github.com/GitoxideLabs/gitoxide` 的内容,首先构建该镜像:
```
docker build -f etc/docker/Dockerfile.alpine -t gitoxide:latest --compress .
```
然后将二进制文件复制到您的镜像中,并将 `git` 指令替换为等效的 `gix` 指令。
```
COPY --from gitoxide:latest /bin/gix /usr/local/bin/
COPY --from gitoxide:latest /bin/ein /usr/local/bin/
RUN /usr/local/bin/gix clone --depth 1 https://github.com/GitoxideLabs/gitoxide gitoxide
```
## 使用方法
安装后,有两个二进制文件可用:
* **ein**
* 高级命令,即 _porcelain_,供日常使用,旨在优化用户体验
* **gix**
* 低级命令,即 _plumbing_,用于更专业的情况,并在真实场景中验证新编写的代码
## 项目目标
随着我们了解的深入,项目目标可能会发生变化,并且它们是可以接受挑战的。
* **纯 Rust 实现的 git**
* 包括 *transport*(传输)、*object database*(对象数据库)、*references*(引用)、*cli* 和 *tui*
* 为最常见的 git 操作提供了一个简单的命令行界面,针对
用户体验进行了优化。如果你愿意的话,可以称之为一个 *simple-git*。
* 成为任何想要解决 git 相关问题的人的首选实现,并在此过程中成为
`GitPython` 和 *libgit2* 的*那个*替代品。
* 成为 GitHub 分布式替代方案的基础,甚至可能在 GitHub 内部使用
* **向最优秀者学习,以编写出尽可能符合惯用法的最佳 Rust 代码**
* *libgit2* 是观察哪些抽象有效的绝佳资源,我们将利用它们
* 利用 Rust 的类型系统使误用成为不可能
* **成为性能最佳的实现**
* 利用 Rust 的类型系统来优化未完成的工作,同时不使其难以使用
* 从一开始就利用并行性
* 第一天起便支持 _sparse checkout_(稀疏检出)
* **保证磁盘一致性**
* 确保读取永远不会干扰并发的写入
* 确保多个并发写入不会引起问题
* **走捷径,但绝不牺牲质量**
* 二进制文件可以穷尽地使用 `anyhow::Error`,因为知道这些错误仅面向用户。
* 库使用通过 `quick-error` 或 `thiserror` 实现的轻量级自定义错误。
* 国际化目前不是我们关注的问题。
* 由于打开的文件句柄数量不足而导致的 IO 错误并不总是会导致操作失败
* **跨平台支持,包括 Windows**
* 凭借此处可用的工具和经验,没有理由不支持 Windows。
* [Windows 会在 CI 中进行测试](https://github.com/GitoxideLabs/gitoxide/blob/df66d74aa2a8cb62d8a03383135f08c8e8c579a8/.github/workflows/rust.yml#L34)
并且失败确实会阻止发布。
## 非目标
随着我们了解的深入,项目非目标可能会发生变化,并且它们是可以接受挑战。
* **完美复制 `git` 命令的功能**
* `git` 就是 `git`,没有理由不使用它。我们的道路是简洁之路,让
git 的入门变得简单。
* **与 git 不兼容**
* 磁盘上的格式必须保持兼容,我们永远不会与其发生冲突。
* **到处使用 async IO**
* 在大多数情况下,git 操作严重依赖于内存映射的 IO 以及用于解压数据的 CPU,
这天然不适合开箱即用的 async IO。
* 使用 `blocking` 以及 `gix-features::interrupt` 将操作引入异步世界并控制
长时间运行的操作。
* 当通过 TCP 连接进行连接或式传输时,尤其是在服务器端接收数据时,async 似乎是
必不可少的,但需放在 feature flag 之后。
## 贡献
如果到目前为止您所看到的内容激发了您贡献的兴趣,那么让我们说:我们很高兴您的加入,并将帮助您入门。
我们建议在开发过程中运行 `just test`,以确保在推送前 CI 是绿灯状态。
可供认领的工作积压[可在项目的看板中找到][project-board],其中包含有关如何
认领任务的说明。如果看板是空的,或者您有其他问题,请随时[发起讨论][discussions]或通过 [keybase][keybase] 私下联系 @Byron。
有关更多详细信息,另请参阅[协作指南]。
### 通过视频教程入门
- [通过 Gitoxide 学习 Rust](https://youtube.com/playlist?list=PLMHbQxe1e9Mk5kOHrm9v20-umkE2ck_gE)
- 在 17 集的内容中,您可以学到有意义地为 `gitoxide` 做贡献所需的一切。
- [走进 Gitoxide](https://youtube.com/playlist?list=PLMHbQxe1e9MkEmuj9csczEK1O06l0Npy5)
- 获得 `gitoxide` 本身的介绍,这应该为任何贡献打下良好的基础,但也不是做出贡献的硬性要求。
- [赠予 Gitoxide](https://www.youtube.com/playlist?list=PLMHbQxe1e9MlhyyZQXPi_dc-bKudE-WUw)
- 了解 PR 是如何被审查的,以及大量的内心独白。
#### 其他媒体
- [Rustacean Station 播客](https://rustacean-station.org/episode/055-sebastian-thiel/)
## 路线图
### 1.0 版本的功能
为最基本的用户旅程提供一个 CLI:
* [x] 初始化代码库
* [x] fetch
* [ ] 以及更新工作区
* clone 一个代码库
- [ ] bare(裸仓库)
- [ ] 带有工作树
* [ ] 在添加工作区文件后创建一个 commit
* [x] 添加一个 remote
* [ ] push
* [x] 创建(thin)pack
### 示例想法
* [ ] `gix tool open-remote` 打开 remote 的 URL,可能在应用已知转换(从 `ssh` 转到 `https`)之后。
* [ ] `tix` 作为 `tig` 的示例实现,显示一版 commit graph,有助于练习如何制作高度响应的 GUI。
* [ ] 类似于 [`git-sizer`](https://github.com/github/git-sizer) 的工具,但利用索引 pack 的极限解压速度。
* [ ] 使用 [sqlite virtual tables](https://github.com/rusqlite/rusqlite/blob/master/tests/vtab.rs) 为 git 开启 SQL 支持。也可以查看 gitqlite。
MVP 会是什么样子?甚至可能是可以随 gitoxide 一起发布的东西。请参阅[这个 go 实现作为示例](https://github.com/filhodanuvem/gitql)。
* [ ] 一个真正出色的历史重写工具,它使理解发生的事情变得容易,同时避免所有陷阱。想象一下 BFG,但更棒,如果可能的话。
* [ ] `gix-tui` 应该在数据展示方面从 [fossil-scm] 那里学到很多东西。也许 [这个](https://github.com/Lutetium-Vanadium/requestty/) 可以用于提示。很可能 [magit] 也有很多值得借鉴的地方。
### 衍生项目想法
* [ ] 一个与 `gix-lfs` 紧密集成的系统,以允许多层架构,从而将资产存储在 git 中并可通过内网位置快速访问
(例如,通过网络以只读方式访问存储),同时服务器会立即将更改推送到其他边缘位置,如 _云_ 或备份。稀疏检出以及资源管理器/Finder 集成
使得仅在本地处理一小部分文件变得方便。克隆可以包含某人在其所在位置高效工作所需的所有配置,
并且针对 git 历史以及 LFS 资源的认证使系统安全。可以想象在 _云_ 中不受信任的位置提供加密支持,
尽管需要进行更多研究才能使其真正安全。
* [ ] 一个类似 [syncthing] 的客户端/服务器应用程序。这是为了展示如何将底层 crate 组合到自定义应用程序中,使其仅使用
部分 git 技术来实现它们自己的目标。注意对大文件的支持、多设备交叉同步、对
不受信任目的地使用全加密的可能性、大小写不敏感与敏感的文件系统,以及扩展文件属性和忽略文件。
* 一个基于事件的数据库,使用 commit 消息来存储增量,同时偶尔在 tree 中聚合实际状态。当然,它天然是分布式的,允许
人们离线工作。
- 它被抽象为完全隐藏其背后的实际数据模型,允许在其之上实现各种功能。
- commits 可能需要为时间戳提供一个纳秒部分,这可以通过自定义 header 字段添加。
- 记录所有更改使得完美的合并成为可能,无论是在客户端还是在服务器上,同时保留自然的审计日志,这使其对于业务中
关键任务的数据库非常有用。
* **应用**
- Markdown 可以用作数据库吗,这样问题跟踪器连同元数据就可以仅仅是大部分可由人类编辑的 markdown 文件吗?用户界面
可以感知元数据并仅隐藏那些现在可以在 GUI 本身中编辑的元数据块吗?这样做将使冲突的解决比 `sqlite`
数据库更容易。
- 一个时间追踪器 - 数据简单,天然无冲突,看到团队或公司使用它并以可能由 GitHub 支持认证的方式运作会很有趣。
- 支持多个不同的追踪器怎么样,比如不同的 remote?
## 缺陷与限制
请查看 [`SHORTCOMINGS.md` 文件](https://github.com/GitoxideLabs/gitoxide/blob/main/SHORTCOMINGS.md) 以获取详细信息。
## 🙏 特别感谢 🙏
至少目前,这一部分专门用来重点介绍 [Josh Triplett](https://github.com/joshtriplett) 为我提供的令人难以置信的支持,
形式包括建议、赞助以及无数其他极具意义的帮助。如果没有他的参与,全职投入 `gitoxide` 几乎不可能
实现,我无比感激 😌。
## 许可证
该项目遵循以下任一许可证:
* Apache 许可证 2.0 版,([LICENSE-APACHE](LICENSE-APACHE) 或
http://www.apache.org/licenses/LICENSE-2.0)
* MIT 许可证 ([LICENSE-MIT](LICENSE-MIT) 或
http://opensource.org/licenses/MIT)
任您选择。
## 趣事
* 最初 @Byron 真的非常着迷于[这个问题](https://github.com/gitpython-developers/GitPython/issues/765#issuecomment-396072153)
并相信有了 `gitoxide`,就能为它提供最快的解决方案。
* @Byron 从 13 多年前第一次体验 `git` 开始,就被它彻底震撼了,并且
尝试以[各种形态](https://github.com/gitpython-developers/GitPython/pull/1028)和[形式](https://github.com/byron/gogit)多次
[实现](
标签:DNS解析, DNS 解析, Git, git2替代, gitoxide, gix, Rust, 代码库, 内存安全, 可视化界面, 安全可观测性, 安全测试工具, 底层库, 开发框架, 开源项目, 版本控制, 网络流量审计, 通知系统