Waleed Khan, a software engineer who writes about Git tooling, Rust, and query languages, and built git-branchless.
HN commenters cite his git undo post as evidence Git needs better UX, and point to his commit-stack formatting and SQL talk posts.
> So jj calls commits "changes", and this is less confusing?
Sort of. It has both changes and commits, actually. (and sometimes commits are called revisions.)
jj log @ muzrswxs steve@steveklabnik.com 2025-02-12 10:23:11 85b41b31 │ (empty) (no description set) ○ wotxrwpp steve@steveklabnik.com 2025-02-12 10:23:09 24ce0a16 │ (empty) (no description set) ○ ztxxskuu steve@steveklabnik.com 2025-02-11 18:20:56 1b3e12ac │ run sqlx migrate as part of deploy process ◆ qwovsnvt steve@steveklabnik.com 2025-02-11 17:45:24 trunk b224ca8b │ <redacted> Okay, so muzrswxs is a change ID. It's true that we're connecting changes in a graph, and that that forms history. So in that sense, it's like a git commit. But because changes are mutable (well, the ○ ones and @ are, the ◆ there is not), they are implemented as a sequence of commits. So if you look on the far right there, you'll see 85b41b31 and then below it, 24ce0a16. Below that, 1b3e12ac. These are commit IDs.
The first two changes are empty, so what happens if we modify a file?
jj log @ muzrswxs steve@steveklabnik.com 2025-02-12 10:28:18 404a73b1 │ (no description set) ○ wotxrwpp steve@steveklabnik.com 2025-02-12 10:23:09 24ce0a16 │ (empty) (no description set) ○ ztxxskuu steve@steveklabnik.com 2025-02-11 18:20:56 1b3e12ac │ run sqlx migrate as part of deploy process ◆ qwovsnvt steve@steveklabnik.com 2025-02-11 17:45:24 trunk b224ca8b │ …
I think the crux is that any complex data structure f1 using glyphs would not need to be updated explicitly in an imperative program through a function like updateFontInGlyph; the runtime would do it as part of its semantics. Of course that's a double-edged sword, as you may get undesired side effects as well as the desired ones like this.
There are ways to achieve such "automatic updating" of items in a functional data structure, but you need to build them explicitly instead of relying on the runtime, which gives you more responsibility but also more control. The most direct approach as compared to imperative code would be to build the data structure on top of mutable state-based streams, though there are other possibilities like monotonic or immutable structures.
https://blog.waleedkhan.name/monotonicity/
IMO git would be way better with different naming and some UX improvements. Like a git undo[1] command, or renaming git reflog (git usage or git cmdlog), git blame (git author), and so on. Also stuff like the index, while great for experienced developers, leads to a lot of confusion early on.
I'd love a command pallet where you could search for basic behavior in plain text like "reset my branch to GitHub's copy" or "only rebase two commits" and have it find the magic incantation.
[1]: https://blog.waleedkhan.name/git-undo/
Just gave a talk about this: https://blog.waleedkhan.name/what-if-sql-were-good/
- Recommend Ascent (Rust only, but supports targeting WASM)
- Soufflé: good, but too hard to integrate into existing systems; lots of ergonomic problems in comparison to Ascent (can elaborate)
- CozoDB: really cool but seems to be abandoned
- Logica: have not tried it yet
You want to rewrite each commit snapshot in isolation? Like fix the formatting for each?
Sounds like `git test fix` from git-branchless.
https://blog.waleedkhan.name/formatting-a-commit-stack/
If it was that easy, https://blog.waleedkhan.name/git-undo/ wouldn't be a thing.