关注了就能看到更多这么棒的文章哦~
Daroc Alden
Gemini translation
原文链接:https://lwn.net/Articles/1060024/
Jujutsu (一种兼容 Git 的版本控制系统) 是一款日益流行的版本控制系统(VCS)。它专注于简化 Git 的概念模型,以提供更流畅、更清晰的命令行体验。不过,有些用户已经有了自己偏爱的 Git 常规命令行界面替代方案: Magit (一个用于 Git 仓库的 Emacs 软件包) ,它是一个旨在让接口更具易探索性(Discoverable)的 Emacs 软件包。现在,少数开发者正在努力为 Jujutsu 实现一套 Magit 风格的接口: Majutsu 。
Magit 由 Marius Vollmer 于 2008 年发起;随着时间的推移,该项目有机地成长,以满足用户对直观 Git 接口的需求。当前版本为 v4.5.0 ,每隔几个月就会发布新版本。该项目的 统计页面 显示,目前大部分代码是由 Jonas Bernoulli 编写的,但许多作者也为满足其特定工作流和用例贡献了改进。其结果是拥有惊人全面的功能集,Bernoulli 称之 为“基本完备”,涵盖了“使用 git 可以完成的操作的 90%”。
Majutsu 则年轻得多:它由 Brandon Olivier 于 2025 年 11 月发起,目前已有 6 位贡献者,并于 2 月 12 日发布了 0.6.0 版本 。然而,得益于 Jujutsu 较少的极端情况(corner cases)以及为 Magit 编写的库,它的界面已经相当全面。这两个项目都采用 GPL 第三版协议授权,Majutsu 复用了 Magit 的界面设计以及用于处理临时窗口(Transient windows)的库。(Emacs 的诞生早于大多数图形界面,它将其他人称为窗口的东西称为“frames”;而将细分 frame 的面板称为“windows”。)
易于探索的设计
Magit 的临时窗口是其半图形界面的核心,使得该软件包能够将键盘驱动的操作与基于文本的状态显示结合起来。当第一次启动 Magit 时(通过输入 C-x g 或 M-x magit ,具体取决于你对那些晦涩的 Emacs 指令的记忆程度),它会显示一个状态摘要屏幕:
在该状态屏幕中,可以使用许多键盘快捷键来执行 Git 操作。例如,按下 d 会弹出用于差异比较(diff)的临时窗口,其中列出了在 Magit 中可以对 diff 执行的所有各种操作:
继续输入以绿色(至少在我的主题中是绿色)显示的字符可以应用相应的命令行参数——这些参数会被保存直到被重置。例如,我的 --stat 和 --no-ext-diff 参数(分别用于生成差异统计和关闭外部差异程序)已经开启,并且将应用于我之后使用的所有与 diff 相关的命令,直到我再次关闭它们。实际上,选择要执行的操作需要输入临时窗口底部显示的未带前缀的字母(图中未显示,因为它们已经滚出屏幕)。然而,再次输入相同的字母总是被绑定到“按我说的做”(dwim, do what I mean),它会根据状态缓冲区中当前光标的位置执行一个合理的动作。因此,再次按下 d (此时我的光标在状态缓冲区列出的某个最近提交上)会在一个新窗口中打开该选定提交相关的差异:
输入 q 将关闭 Magit 的任何临时窗口并返回到状态缓冲区。输入 ? 会列出所有最初弹出临时窗口的键,尽管它们大多是助记符,例如 l 代表日志(logs)或 c 代表提交(commit)。
像这样的 Magit 命令是上下文相关的。如果状态缓冲区中的光标位于提交标识符(分支、标签或哈希)上,按下 d d 会显示与该提交相关的差异。如果光标位于具有未暂存更改的文件上,按下 d d 会显示该文件相对于暂存区(Staging area)的差异。在差异视图中,将光标放在特定的代码块(hunk)上并输入 s 即可将其暂存。普通的 Emacs 导航操作(如点击或方向键)足以导航到任何 Git 对象,如文件、提交、代码块或树。一旦光标落在对象上,默认的上下文命令就会执行一些有用的操作。
当使用 Emacs 更新 Git 状态时(例如暂存或取消暂存一个代码块),Magit 的所有缓冲区都会自动保持同步。这包括在 Emacs 中编辑仓库中的文件——保存编辑后的文件将使 Magit 更新已在另一个窗口中打开的差异。如果仓库是在 Magit 之外更新的,输入 g 即可强制手动刷新。
这种设计使得 Magit 的使用具有令人愉悦的易探索性——执行简单操作非常直观,状态屏幕上的所有文本都可以交互。执行更复杂的操作则涉及打开相应的临时窗口,然后开启或关闭选项并选择适当的操作。这不需要查阅 Magit 手册 或 Git 手册 ,因为 Emacs 中就有一个方便的快速参考指南。同理,尽管 Magit 自称为另一种 Git 表面工具(Porcelain),但你现有的 Git 命令行知识并不会过时:Magit 命令几乎可以使用与普通命令行界面完全相同的参数和 Git 子命令。
Majutsu
尽管运行在不同的版本控制系统之上,Majutsu 乍一看与之相当相似:
主要区别在于 Jujutsu 摒弃了暂存区的概念:总有一个特定的工作提交(Working commit,简写为 @ ),用户只需原地编辑该提交,而不是暂存更改并在完成后才提交。因此,Majutsu 将最近提交的图表放在顶部,并在下方显示当前工作提交状态的详细信息。
该界面与 Magit 的工作方式完全相同,这并不奇怪,因为它复用了 Magit 的库:开始输入,就会弹出一个临时窗口显示命令的各种可能补全。Majutsu 的临时窗口确实较少(25 个对 Magit 的 37 个),但这部分是因为 Jujutsu 的命令比 Git 少。 Majutsu 手册 详细介绍了可用的临时窗口。总体而言,它比 Magit 感觉更简陋一些,考虑到其贡献年份要少得多,这也是意料之中的。
主状态窗口中的图表显示了与 Git 模型的一些差异——例如,它显示的是提交标识符(在左侧,以粉红色或紫色字母开头),而不是提交哈希。Jujutsu 的提交标识符在变基(Rebase)和其他历史修改操作中是稳定的,因此即使在变基过程中,它们也可以用来明确地引用某个提交。开头的彩色字母突出了明确引用它们所需的最短前缀:Jujutsu 会理解 r 指代提交 rkrmpkzv ,至少在仓库出现另一个以 r 开头的提交 ID 之前是这样。Jujutsu 提交仍然拥有加密哈希——用于签名以及与 Git 的互操作性——这些哈希可以在状态窗口底部看到,以蓝色字母开头。虽然这些名称在 Jujutsu 命令行中通常很有帮助,但在 Majutsu 中作用较小,因为通常通过将光标移动到提交上来引用它们,而不是通过名称。
Majutsu 的变基接口就是一个例子,它比 Magit 的接口更简化。在 Magit 中,使用 r r 开始变基,之后必须选择一个起始版本,并经历 Git 正常的交互式变基流程。在 Majutsu 中,体验更加直观。变基以 r 开始,然后可以直接在主状态窗口或详细日志窗口中选择应该选取(pick)、压缩(squash)或直接变基到哪些版本。选好正确的提交后,按下回车键即可实际执行变基。与 Magit 相比,这一过程大大简化了,这也很合理,因为 Jujutsu 的设计鼓励比 Git 更频繁地进行变基。
Majutsu 也有一些不尽如人意之处。使用它克隆一个新的 Git 仓库(通过 M-x majutsu-git-clone )时有点让人困惑——它警告我正在 Jujutsu 仓库之外使用,并询问是否要创建一个。当我这样做并克隆了目标仓库后,它将其检出到了一个子目录中,导致我得到了两个嵌套的仓库。不过,这只是一个相当小的细节。
更令人恼火的是,Jujutsu 的日志命令(以及 Majutsu 的状态缓冲区)不会显示导入 Git 仓库之前的提交。尽管 Jujutsu 支持与 Git 共存(colocated),即在同一个仓库中使用两者。在共存仓库中使用 Git 进行的后续提交是可以显示的,但这造成了一种尴尬的过渡。其他操作,如提交和移动书签(Bookmarks,相当于 Git 的标签)则进行得很顺利。
Jujutsu 是构建具有简化设计的版本控制系统的一次有趣尝试。在使用 Git 多年之后,它可能会让人感到不习惯——但 Majutsu 让探索它变得容易。对于一个必须与 Git 的统治地位抗衡的版本控制系统来说,拥有一个易于探索的界面感觉是让资深 Git 用户更容易迁移的重要一步。Majutsu 要达到 Magit 的精致程度还有很长一段路要走,但它已经完全准备好帮助那些对 Jujutsu 好奇的人在不离开 Emacs 舒适怀抱的情况下进行尝试。
LWN 评论概述:
[一位用户认为相比 Magit 解决 Git 界面糟糕的问题,Majutsu 的必要性可能没那么高,因为 Jujutsu (JJ) 本身的设计就已经解决了很多 UI 痛点,命令行非常易用且自动化程度高,但他也承认 Magit 类接口对吸引 Git 用户迁移有帮助。另一位评论者则在思考为什么不能将这些功能整合到 Emacs 内置的、与具体 SCM 无关的 vc 工具中,并对行业重复构建相同接口的现状表示担忧。还有评论提到了 Git 通过别名实现的扩展,指出 JJ 的某些功能如 jj absorb 对应了 Git 的一些复杂操作。]
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~




546



被折叠的 条评论
为什么被折叠?



