Jujutsu是一个新的版本控制系统,看起来很不错!
在我尝试的前几次,我从文档中跳了出来,根据我的口味,在我了解全局之前,文档中包含了太多细节。其他人可能有类似的经历并编写了替代教程,但它的博客风格杂乱无章,对我来说也过于关注命令。
我怀疑,就像编写 monad 教程一样,理解之路实际上就是把它写下来。这是我在介绍/教程中的尝试。
也许与其他人不同的是,我的目标是,这是足够高水平的阅读和思考,而不是提供太多的细节,让你不知所措。不要试图记住这里的命令或任何东西,它们只是在这里传达想法。最后,如果您想尝试一下,我推荐在他们的网站上找到的文档。
概述
省略细节,您可以将 Jujustu(以下简称“jj”)视为一个新的 Git 前端。底层数据仍然存储在Git中。区别在于您如何使用不同的概念模型和不同的命令集在本地与文件交互。
Git 测验:提交是文件状态的快照还是差异?技术答案很微妙——作为用户,您通常将它们作为差异进行交互,虽然从概念上讲它们是快照,但具体而言它们存储为增量。更有用的答案是,考虑细节会混淆概念模型。同样,用 Git 中发生的事情来描述 jj 很诱人,但我认为最终会掩盖解释。
在实践中,这意味着尝试暂时搁置您对 Git 的了解,但也要注意您可以使用 jj 并继续与更大的 Git 生态系统进行互操作,包括推送到 GitHub。
伟大的想法:一切都是承诺
版本控制系统的目的是跟踪代码的历史记录。但有趣的是,在大多数情况下,一旦您在工作副本中本地编辑文件,新历史记录(“我已从版本 Y 开始编辑文件 X”)就处于系统外部的某种不确定状态并单独管理。
这种现象如此普遍,几乎很难看到。但请考虑像git diff
这样的命令如何具有一种需要两次提交 diff 的模式,然后是一堆其他模式和标志来对其跟踪的其他类型的事物进行操作。您可以获得与工作副本的差异,但无法在 diff 命令中命名“工作副本”。 (Git 特别添加了索引的额外非完全提交状态,以及更多风格的附带命令。终极 Git 测验: git reset
有哪些不同的软/硬/混合行为?)
另一个例子:考虑一下,如果您有工作副本更改,并且想要查看其他代码,则必须将其放在新位置( git stash
,与其他位置分开的第四个位置)或进行临时提交。或者,如果您有一个工作副本更改想要移植到其他地方,您可以git checkout -m
,但要移动已提交的更改,则可以使用git rebase
。
相反,在 jj 中,您的工作副本状态始终是提交。当进行新的更改时,这是一个新的(无描述的)提交。您在磁盘上所做的任何编辑都会立即反映在当前提交中。
这个简单的决定会带来很多事情!
-
jj diff
显示提交的差异。没有参数,它是当前提交的差异,即当前工作副本的差异;否则您可以指定您想要的历史记录。许多其他 jj 命令同样具有令人愉快的对称性,就像这样。 -
您可以在完成之前起草正在进行的提交的提交消息,使用与编辑任何其他提交消息相同的命令。没有最终的
jj commit
命令,提交是隐式的。 (相反,你jj new
完成后开始一个新的空提交。) -
您永远不需要“隐藏”当前的工作去做其他事情,它已经存储在当前提交中,并且很容易跳回。
-
在 Git 中,要修复旧提交中的拼写错误,您可以进行新提交,然后
git rebase -i
来移动补丁。在 jj 中,您直接签出旧的提交(因为工作副本 == 提交)并编辑文件,无需进一步的命令。 (这篇博文将介绍 Git 和 jj 并行的实际操作。)
从 Git 的角度来看,jj 非常“rebasey”。编辑文件就像git commit --amend
,并且在“修复拼写错误”中,在编辑上方移动会隐式地重新设置任何下游提交的基础。为了实现这一目标,围绕冲突处理和分支还有一些其他概念上的飞跃,这些将在基础知识之后进行。
基本工作流程
在 Git 存储库中:
$ jj git init --colocate
这将创建一个与 Git 存储库一起使用的.jj
目录。 Git 命令仍然有效,但可能会令人困惑。
简单的jj
命令运行jj log
,显示最近的提交。这是来自此博客的存储库:
$ jj @ zyqszntn [email protected] 2024-12-12 11:58:52 21b06db8 │ (no description set) ○ pmnzyyru [email protected] 2024-12-12 11:58:48 86355427 │ unfinished drafts ◆ szzpmvlz [email protected] 2024-09-18 09:08:15 fcb1507d │ syscalls ~
最左边的字母字符串是“change id”,它是您用来引用diff
等命令中的更改的标识符。与右侧的 Git 哈希不同,它们在编辑过程中保持稳定。在终端中,更改 ID 被着色以显示在命令中唯一引用它们(单个字母)所需的前缀。
最上面的提交zyqszntn
是当前提交,包含我撰写的这篇博文。正如您所期望的,如果我运行jj status
它会显示已编辑文件的列表,如果我运行jj diff
,它会显示差异。
我可以现在或完成后对其进行描述:
$ jj desc -m 'post about jujutsu'
然后为下一个更改创建一个新的提交:
$ jj new
迭代更改
对于微不足道的更改来说这已经足够了,但我经常会进行更重大的更改,而我可能会在几天内失去上下文。根据您的工作方式,您可以通过两种方法来执行此操作。
第一个是如上所述描述您的更改并继续编辑它,而不运行jj new
。每次后续编辑都会随时更新更改。这操作起来很简单,但这意味着jj diff
将始终显示整个差异。在 Git 中,这类似于在工作副本中保留大量编辑。
另一个选项在教程书中称为“ squash 工作流程”。在这种情况下,当您做新工作时,您jj new
从现有工作中创建一个新的不同提交,当您对此感到满意时(例如通过检查jj diff
,它只显示工作副本的新更改),您运行jj squash
将这些新更改刷新到之前的提交中。对我来说,这感觉非常类似于使用 Git 索引作为复杂更改的暂存区域,或者可能重复使用git commit --amend
。
移动和编辑历史记录
jj diff
和jj desc
等命令适用于当前提交(或通过-r flag
明确请求的任何命令)。
要将工作副本切换到现有更改,请使用jj edit <changeid>
。同样,您在此处对文件或描述所做的任何更改,或者通过进行新更改并压缩它们,都会直接作用于您正在编辑的历史提交。我重复这一点是因为回想起来这既奇怪又明显。
冲突
对历史记录的任何操作都会导致默默发生的隐式变基。变基可能会发生冲突。 jj 对它的工作原理有有趣的处理。
在 Git 中,变基解析是通过工作副本进行的,因此围绕“变基进行中”和git rebase --continue
再次有额外的状态。相反,在 jj 中,冲突的提交仅被记录为冲突并在历史记录中标记为冲突,因此即使生成一串冲突的提交,变基也始终“成功”。
如果您要修复冲突的提交(通过上面的jj edit
),您可以照常编辑文件,一旦冲突标记被删除,它就不再被视为冲突。
与往常一样,一旦您进行历史记录编辑,下游更改将再次重新定位,可能会在编辑后解决其冲突状态。同样,“所有相关信息都在提交中建模”的 jj 模式,没有带有状态等的单独变基模式,是一个反复出现的强大主题。
我对此还没有太多经验,所以我无法评论它的效果如何,除了我遇到它的时候我感到惊喜。 jj 文档似乎对这里的建模和行为感到自豪,这让我认为它似乎很复杂。
分支机构
jj 没有命名分支,而只跟踪提交。由于 jj 处理提交的方式,在历史上的随机点开始添加提交很简单,因此分支名称没有那么有用。根据我迄今为止的经验,有用的提交描述足以跟踪我正在做的事情。来自 Git 的命名分支的缺乏令人惊讶,但我相信这对于 Mercurial 用户来说很舒服,并且 Monotone 的工作原理类似(我认为?)。
值得强调的是没有分支,因为特别是在与 Git 互操作时,即使只是为了推送,您仍然需要分支。 jj 对此提供支持(其中“书签”是指向特定提交的指针),但感觉有点笨拙。另一方面,我可能对git push
语法有斯德哥尔摩综合症。
缺少什么:VSCode
与 jj 一起工作让我意识到我在查看差异和合并方面有多么依赖 VSCode 的 Git 支持。
当在 jj 中编辑给定的提交时,Git 认为该提交中的所有文件都在工作树中,而不是在索引中。换句话说,在 VSCode UI 中,当前差异显示为待处理的更改,就像在 Git 中一样。这工作得很好,几乎是我所期望的。我还没有碰过与 Git 索引交互的按钮,担心 jj 会用它做什么。
出于技术原因,我不太明白——可能 VSCode 只进行三向文件合并,而 jj 需要三向目录合并? ——两人在解决冲突方面不太合作。 jj 文档推荐 meld,我过去也使用过 meld,但我并没有完全意识到 VSCode 是如何吸引我的,直到我错过了使用它进行合并的机会。
未来
jj 的作者在 Google 工作,可能正在为 Google 内部版本控制系统制作它。 (上面我写到 jj 是一个 Git 前端,但正式它有可插入的后端;我只是不太可能看到非 Git 的后端。)
三年前我离开 Google时,我记得他们正在试图弄清楚如何扩大 Git 规模,或者采用 Mercurial,或者其他什么。我记得与参与该领域的人交谈并思考“实际上,您的用户必须使用 Git 才能与更广阔的世界合作,因此您所做的任何其他事情都是纯粹的成本”。我发现Mercurial 粉丝写的关于 jj 的这篇文章很有趣,其中讨论了它修复的 Mercurial 缺点。
总而言之,jj 看起来相当精致,已经存在了很多年,并且在出现问题时有一个非常简单的退出策略 – 只需退出到 Git 存储库即可。我的目标是继续使用它。
原文: https://neugierig.org/software/blog/2024/12/jujutsu.html