Git 并不完美:重新思考现代工作流中的版本控制

Git 并不完美:重新思考现代工作流中的版本控制

版本控制的行业标准在近二十年里基本保持不变。虽然 Git 无处不在,但越来越多的开发者发现,其为 Linux 内核设计的核心架构与现代、迭代且通常是非线性的开发流程并不完全契合。

围绕“Git 并不完美”这一论点的近期讨论表明,我们只是学会了如何应对其局限性,而不是解决了它们。从管理堆叠 PR 的挣扎到暂存区(index/staging area)带来的摩擦,我们用来追踪变更的工具正日益与我们实际编写代码的方式产生冲突。

线性思维带来的摩擦

Git 的架构从根本上是基于提交流(stream of commits)的。然而,现代开发——尤其是在大型 monorepo 中——很少是一条直线。开发者经常发现自己同时在多个功能上工作,其中一个包中的一个小修复可能需要支持另一个包中的某个功能。

正如一位开发者在最近的 Hacker News 讨论中所指出的,挑战不仅在于切换分支,而在于管理“树状”工作流:

我在做一件事,但这会导致其他包的变更,而我没有明确的方法来说:这些变更属于分支 #1,那组变更属于分支 #2,而另一个小修复属于分支 #3。分支 #1 依赖于其他分支……切换分支并不是解决方案,因为所有这些变更都是同时开发的。

在这种环境下,传统的 Git 工作流(如 stashing 或 worktrees)往往是不够的。手动追踪哪些变更属于哪个逻辑工作单元所带来的认知负荷,成为了生产力的沉重负担。

“肌肉记忆”的谬误

有一个常见的反驳观点:Git 的复杂性仅仅是学习曲线的问题。许多经验丰富的开发者认为,rebase、管理 submodules 以及重写提交历史仅仅是“肌肉记忆”的问题。

我处理堆叠 PR/分支的 rebase 方式是 rebase 最后一个。然后只需为其他每个分支执行 git branch -f a-branch <logical same point on rebased>,就完成了。这一切都变成了肌肉记忆。

然而,这种对肌肉记忆的依赖暗示了一个问题。当一个工具的主要界面要求用户记忆复杂的命令序列来执行常见任务时,该工具就不再是在辅助工作,而是在变成工作本身。AI 辅助编程的出现进一步使情况复杂化,因为开发者现在使用 LLM 来执行快速的辅助任务,同时专注于主要功能,从而创造了更加碎片化的工作流。

超越 Git:新替代方案的兴起

关于 Git 不足之处的争论并非没有先例。文章强调,像 Meta 这样的公司长期以来一直使用基于 Mercurial 的内部系统来处理其 monorepo 的规模和复杂性,这证明了更高效的追踪变更的方式是存在的。

这促使了诸如 Jujutsu (jj) 等工具的出现,其目标是解决 Git 的一些核心挫败感。通过将提交视为可变的(mutable),并重新思考如何追踪工作目录的状态,jj 试图减少与暂存区和“游离 HEAD”(detached HEAD)状态相关的摩擦。

结论:Git 真的“并不完美”吗?

无论 Git 是一个“并不完美”的版本控制系统,还是一个我们已经不再适应它的工具,结果都是一样的:工具与现代开发者的思维模型之间存在着鸿沟。虽然一些开发者发现当前的 Git 工作流对于其特定的语言或项目规模来说已经足够,但其他人——特别是那些处于大规模、分布式环境中的开发者——发现 Git 架构的局限性正成为一个无法回避的瓶颈。

Sources