常见问题
已经有了 Git / jj-vcs,为什么还要自己造一个工具?
Git 有着悠久的历史,并且绝大多数开源代码都托管在基于 Git 的平台上。几乎不可能撼动 Git 的地位。
但是你会发现 Git 并不好用。
大多数人的工作流是单一的,而 Git 做了太多事情。很多资深的程序员一旦遇到一些相对复杂的 Git 使用场景,都要去反复查阅各种文档。Git 的命令繁杂、手册冗长。它的很多设计理念新手难以理解。
如果你感兴趣的话,这里有一篇关于 Git 的文章:关于 Git 的礼节。
jj-vcs 是一个革新性的工具,具备了很多新的理念:
- 工作副本(工作区)也是一个提交。这样不需要 stash,而且切换分支和变基永远不会失败。
- 不需要索引区(暂存区),所有变更默认被提交,也包括 Git 中的未追踪文件。
- 不再需要交互式变基,子提交会被自动变基。
- 使用函数式语言指定文件和变更,而不是使用上古时期的方式解析文本。
- 有着默认的根提交。
- ……
这些理念上的革新使得 jj 的本地版本控制非常优秀。
但是 jj 在与 Git 远程的互作性上有待进步。例如书签(分支 HEAD)并不会随着提交而推进;pull / push 的模型依然需要非常熟练才能掌握。jj 与 Git Forge(如 GitHub)的互作性也不够好。
而且 jj 是另一套工具和使用理念,不论你是否学过 Git 都有着不小的学习成本。
所以有了 hj,致力于基于 jj 的优秀理念,提供一个 90% 场景下极简的版本控制体验,降低你的学习成本(你甚至可以在不了解 Git 和 jj 的情况下上手),并且在一些特殊场景中你可以随时切换回 jj 进行操作。这符合 渐进性 的设计理念。
让我们来举几个例子说明 hj 相较于 jj 的极简性:
- 你可以一行命令开始版本控制、新建一个默认的主分支、创建一个 GitHub 仓库、并把远程仓库关联到本地:
hj init --gh
- 你可以一行命令提交指定文件,并给出提交信息:
hj commit "feat: add new feature"
- 你可以一行命令拉取当前分支的变更,并推送到远程:
hj push main --pull
hj 将不断进步!💪🏻
为什么不向 jj 贡献代码,而是直接封装 jj ?
jj 是一个有着优秀设计理念的工具,为了保持其功能的 正交性,不可避免地要提供尽量 通用 的工具,以满足所有用户的版本控制需求。
hj 的理念有所不同,「简单」是我们的第一设计理念。我们封装了许多有用的子命令使得你可以以 最小的心智负担 来完成 Git 和 jj 中复杂的操作。目前我们的工具是对多个命令行工具的组合,以可维护性极强的 Rust 脚本形式为您提供。
我们额外提供的功能中,我确信其中有很多 jj 在短期内一定不会提供,甚至永远不会提供,因为这些功能与 jj 的设计理念相悖。如果你追求简单,不妨来尝试一下我们的工具。 💪🏻
目前存在哪些已知缺陷?
hj undo
是基于jj undo
的。而 hj 的很多操作不是原子化的,例如hj switch
内部执行了两行 jj 命令,所以hj undo
不能够完全撤销一个操作。未来我们会根据hj op restore
封装一个命令。因为 hj 基于 jj,所以短期内几乎不可能实现各种 IDE 或插件的原生适配(因为 jj 的知名度远远不够)。如果你非常需要这些适配的话,可以考虑 与 Git 仓库共存。
hj 的很多改变工作副本指向的操作不会自动推进书签。这是 jj 的特意设计,hj 正在尝试解决。
hj 目前仅在 GitHub 中发布各架构的 Release。除了从 GitHub 手动下载二进制文件外,你仅能通过
cargo install --path .
来从源码编译。未来我们将会至少支持以下安装方式:
路线图
✅ 表示已经实现,🚧 表示正在实现,🤔 表示未来计划。你也可以在 Issues 里提出你的想法!
- 🤔 涉及
gh
CLI 的命令支持省略owner
,默认为当前登录的用户。 - 🤔
hj clone --fork
- 🤔
hj download
下载单个文件(夹) 时直接下载到指定的目录,而不包含远程仓库中的文件夹结构。 - 🤔
hj init
时支持下载.gitignore
。(来源) - 🤔 全面支持 GitLab。
- ✅
hj commit
和hj describe
时支持打开编辑器进行多行描述的编辑。 - 🤔
hj rollback
:交互式选择要回退的命令。 - 🤔 优化与 Git 仓库共存时的体验。
- 🤔 发布到 scoop、homebrew;编写 PowerShell script 和 bash script。
- 🤔 提供更多与
hj log
相关的简化命令。 - 🚧 提供 Hooks 支持。
hj 是如何实现的?
hj 用 Rust 语言编写的一个命令行工具。
目前多数子命令我们使用 Shell Command 的形式构建基于 jj、Git、gh 等工具的命令。
移除 jj、git、gh 依赖的计划
目前 hj 强依赖 jj 可执行文件;涉及 GitHub 的操作强依赖 gh(有些操作如下载仓库是调用的 GitHub API);涉及与 Git 仓库共存的操作强依赖 Git。
未来我们将逐步移除这些依赖。
而一些子命令(如 hj squash/split/rebase
等),直接调用 jj 来实现,不做任何命令行参数的转换和命令的封装,这是因为它们已经做得足够完善了,不需要多余的封装。