Show HN:GWZ – Git 工作区(多仓库,体验如原生 Git)
2 分•作者: owebeeone•3 个月前
作为一名曾经在单体仓库(mono-repo)环境中工作过的谷歌人,我决定拥抱多仓库(multi-repo)的纯 Git 风格。我曾想:“嘿,子模块(submodules),能出什么问题呢?” 结果是,几乎所有问题都出现了:分离式 HEAD(detached HEADs)、极其繁琐的提交管理,以及其他各种各样的问题。我心想:“好吧”,一个简单的 Python 脚本应该就够了吧?结果是,不行。事实证明这比想象中要复杂得多。于是我想到:“其他人肯定已经解决了这个问题,对吧?我在单体仓库里待了很久,肯定有人会找到解决方案。”——嗯,事实并非如此。我不想让你们感到厌烦(更长、更枯燥的对比分析在文档中有),但我尝试过的所有方法都有其局限性。我想要的只是一个工具,它能不干扰我的工作流程,让我的多仓库在我想的时候看起来像单体仓库,在我想的时候又恢复成多仓库。我想要鱼与熊掌兼得,而且要立刻实现。
我曾对“claude, codex and gemini”说:“让我来创建一个 gwz,并且让它的使用方式与 Git 本身非常相似。”——它们似乎忽略了我的要求,但在经过多次尝试后,它们最终创造了一个在实现目标方面非常出色的产品。我不得不承认,这些小家伙们发挥了一些创意,让它比我最初的要求做得更好。
那么,gwz 到底做了什么?
* 成员仓库仍然是普通的 Git 仓库。不会出现子模块意外分离(除非你要求将其具体化到某个标签/快照)。
* “快照”(Snapshots)和“提交标记”(commit markers)可以恢复工作区状态。这些状态保存在根仓库中。
* 相似之处不止于 gwz 是一个以“g”开头的三个字母的命令,不,gwz 拥有 status、diff、add、pull、push、commit、tag、stash、clone、init 等命令,它们的作用与各自的 Git 命令类似(但不完全相同)。
* 额外的命令用于管理成员:`gwz repo create / clone / add / sync / detach / attach`。
* 一个“forall”命令,可以在选定的成员仓库中运行任何命令。
此外,成员仓库对根仓库的 Git 是隐藏的(通过 `.git/info/exclude`),这样你就无法从根仓库弄乱成员仓库。
对于我的日常工作流程来说,gwz 非常棒,现在它已经成为我的首选——我几乎不再使用原始的 Git 命令了。但是,gwz 和任何艺术形式一样,永远不会完成。总有更多可以改进的地方,但现在是时候揭开面纱,让它大放异彩,或者大声宣告它的存在了。
需要注意的事项:它用 Rust 编写,而我目前还无法熟练地使用 Rust。那么为什么选择 Rust 而不是 Python 或 C++(我通常的首选)呢?我有一个需要管理仓库的另一个项目,这意味着 gwz 必须被分解成一个 CLI 和一个“核心”(core)的 crate,它们之间通过一个类型化的协议进行通信——这样引擎就可以被嵌入并且易于网络传输,而不是仅仅局限于终端。那个项目的目标也是 Rust,而且(悬念)它还没有准备好公布,所以:敬请期待。
那些小型 LLM 助手生成了大量非常出色的文档(真的),我邀请您在此查阅:https://owebeeone.github.io/gwz-cli/
一个有趣的 LLM 主导的功能(我并没有要求它,但听起来不错,而且它作为 gwz-core 协议的一部分也顺理成章)是“--json / jsonl”输出,这似乎能让 LLM 更好地理解响应的上下文。谁能想到,一个 LLM 会创造出自己的“语言”。
诚实的现状:
* 它有一些粗糙的用户体验细节,但没有到令人作呕的地步。
* 在 gwz-core、gwz-cli 和 gwz-py 中,gwz 目前有 764 个测试,行覆盖率约为 82%。
* 对于我的工作流程来说,gwz 非常棒。您的体验可能会有所不同(请告诉我——好、坏或无所谓,不,算了,只告诉我好的)。
* gwz-dev——根 gwz 仓库是一个“gwz 管理”的仓库。自己使用自己开发的产品。
* CLI 有 Rust 和 Python 两种版本。我每天都使用 Rust 版本的 gwz;Python 版本的 gwz-py 应该也能工作,但使用较少,所以可能存在 bug——它最初是为了验证核心的消息协议在从第二种语言驱动时是否可靠而设计的。
* 它目前是 v0.9.2 版本,处于 1.0 版本之前:协议和一些命令界面可能仍会发生变化。
* 采用 GPL-2.0-only 许可证,与 Git 属于同一许可证家族。
查看原文
Coming from the land of the mono-repo (ex-googler), I decided to embrace the multi-repo, plain-git style. Methought, “hey, submodules, what could possibly go wrong”. Well, how about everything: detached HEADs, impossibly tedious commit management, and just about everything else. "OKAY" I said, a simple Python script should be fine, right? Well, NO. It turns out to be more complex. So I thought "others have got this, right? My time in mono-repo land was long and someone will have solved this" — well, yeah NAH. I won't bore you (the longer, boring comparison is in the docs) but everything I tried had baggage. All I want is a tool that gets out of my way and makes my multi-repo look like a mono-repo when I want, and a multi-repo when I want. I want my cake and I want it now.<p>"claude, codex and gemini, make me gwz" I said, "and make it work much like using git itself" I said — which they proceeded to ignore, but after many rounds in the rink, they produced a product which is delightfully good at the goal. I have to admit, the little beasties did take some creative license and made it better than I asked.<p>So what does gwz do?<p>- Member repositories remain ordinary Git repositories. No submodules unexpectedly detaching (unless you ask to materialize to a tag/snapshot).
- “Snapshots” and “commit markers” can recover workspace state. That state lives in the root repo.
- The similarities don't end at gwz being 3 letters starting with "g", no, gwz has status, diff, add, pull, push, commit, tag, stash, clone, init all play similar (not exact) roles to their git namesakes.
- Extra commands to manage members: gwz repo create / clone / add / sync / detach / attach.
- A “forall” command that runs anything across selected member repos.<p>Also, the member repos are hidden from the root repo's git (via .git/info/exclude), so you can't mess up the members from the root.<p>For my daily workflow gwz is great, and it's now my goto — I hardly use raw git anymore. But gwz, like any form of art, will never be finished. There's always more, but; it's now time to lift the veil, shine the light or yell from the rafters.<p>Caveats: it's written in Rust and I can't yet write Rust if my life depended on it. So why Rust and not Python or C++ (my usual gotos)? I have another project that needs to manage repos, which meant gwz had to be carved up into a CLI and a "core" crate with a typed protocol between them — so the engine is embeddable and wire-friendly, not fused to a terminal. That other project's target is also Rust, and (suspense) it's not ready to reveal, so: stay tuned.<p>The little LLM helpers created copious amounts of very fine documentation (seriously), which I invite you to peruse at: <a href="https://owebeeone.github.io/gwz-cli/" rel="nofollow">https://owebeeone.github.io/gwz-cli/</a><p>One interesting LLM initiated feature (I did not ask for it but it sounded good and it falls out as part of the gwz-core protocol anyway) is the “--json/jsonl” output which seems to give LLMs much better context of the response. Who woulda thunk, an LLM making its own lingo.<p>Honest state:<p>- It has a few rough UX edges, nothing so egregious it'll make you chunder.
- Across gwz-core, gwz-cli and gwz-py, gwz currently has 764 tests, with roughly 82% line coverage.
- For my workflow gwz is great. YMMV (tell me about it - good, bad or indifferent, Nah, scratch that, only the good).
- gwz-dev - the root gwz repo is a “gwz managed” repo. Eat your own fishfood.
- The CLI comes in Rust and Python variants. I use the Rust gwz daily; the Python gwz-py should work but gets less use, so it probably has bugs — it started life as a validation harness proving the core's message protocol holds up when driven from a second language.
- It's v0.9.2 and pre-1.0: the protocol and some command surfaces may still move.
- GPL-2.0-only, the same license family as git.