arxanas

Joined 14 years ago

Karma
1,033
Submissions
245
Member since
Aug 1
I'm Waleed Khan, a software engineer working on highly-scalable developer tooling. You can contact me at [email protected] or see my resume at https://resume.waleedkhan.name.
View on Hacker News

Recent submissions

Comment · 20 days ago
> A big part of the theses of git and, even more so, jujitsu, is that you can build up a history entirely locally, making it reasonable to make tiny commits locally and then rework them, push them, or throw them away.

Jujutsu actually doesn't take a strong stance here. I've personally implemented a centralized cloud-based backend for Jujutsu, while preserving the local commit manipulation workflows. It's a choice for the deploying organization to make.

Comment · 20 days ago
The patch-based model in the article is much closer to Git than Pijul. For example, Pijul tracks operations on byte ranges, while this model appears to just list each changed file hash (not even the diff from its parent!).
Comment · 20 days ago
This is very important for large enterprises using Git (and especially GitHub) and who are hitting the scaling limits. It gives a pre-validated recipe to write a source control that works at scale. I'd personally been awaiting this report from Anthropic.
Comment · 1 year ago
Ah, yes, but I think Ascent also doesn't index ADTs. In this case, based on some other information, it seems like Soufflé _can_ plan the queries better if it has profiling data. It seems like Ascent just happened to pick a better query plan in my case without the profiling data.

Thanks for the link to the paper!

Comment · 1 year ago
It's quite possible that I have different, smaller-scale problems than you have! So my feedback might not be as relevant

I wrote detailed commentary here: https://github.com/s-arash/ascent/discussions/72

Re Rust bindings and your specific comment:

- Deploying Soufflé and doing FFI is much more difficult for me in practice, just in terms of the overhead to set up a working build. (I'm not going to be able to justify setting up a Soufflé ruleset for Bazel, and then adding Rust-Soufflé binding generation, etc. at my workplace.)

- User-defined functors, or integrating normal data structures/functions/libraries into your Soufflé program, seems painful. If you're doing integrations with random existing systems, then reducing the friction here is essential. (In slide 16 of the talk, you can see how I embedded a constructive `Trace` type and a `GlobSet` into an actual Ascent value+lattice.)

- On the other hand, you might need Soufflé's component system for structuring larger programs whereas I might not (see above GitHub discussion).

Non-specifically:

- Several features like generative clauses, user-defined aggregations, lattices, etc. seem convenient in practice.

- I had worse performance with Soufflé than Ascent for my program for some query-planning reason that I couldn't figure out. I don't really know why; see https://github.com/souffle-lang/souffle/discussions/2557

Comment · 1 year ago
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

Comment · 1 year ago
Comment · 1 year ago
> To me it still all seems confusing. I don't have a good mental model for it. > > How does it handle things like `git rebase -x 'make fmt'` which might edit each rebased commit automatically, or `git rebase -x 'make lint'` which might fail but not leave a conflict marker. I didn't see any docs for exec in jj rebase so I guess this feature doesn't work

As a mental model, you can pretend that a commit with a conflict in it has suspended the subsequent rebase operation for descendant commits. When you resolve the conflicts in that commit, it's as if jj automatically resumed the rebase operation for the descendant commits. This process repeats until you've applied all of the rebased commits and resolved all of the conflicts (or not, if you decide to not resolve all of the conflicts).

Today, you can write something like

    for commit in "$(jj log -T ...)"; do jj edit "$commit" && make fmt; done
which would also edit the commits automatically. It's probably not too hard to break out of the loop when the first conflict is detected to match the Git workflow more directly. (I can figure it out if you end up being interested.)

> There's also no examples for how you work out which commit has a conflict marker. It's probably obvious in jj status but it would be nice to document, as I'm not yet interested in spending the time to test it.

Does this overview help? https://jj-vcs.github.io/jj/v0.26.0/tutorial/#conflicts

> And I imagine it all breaks in colocated repos too (I need submodule support, and I want to use gh cli etc)

It depends on the exact subset of features you need.

- jj can't update submodules, which works for some workflows but not others.

- Generally speaking, you can use the `gh` CLI reasonably well alongside jj. In jj, it's common to create commits not addressed by any branch, but `gh` doesn't support those well. You can either try to adopt your Git workflows directly and always use branches, or else you'll need to make sure to create the branch just-in-time before performing a `gh` invocation that would need a branch.

Comment · 1 year ago
It's certainly true that jj's features won't appeal to everyone. I think a lot of its features are quality-of-life features (consistent commands and concepts, general undo), and a lot of its features don't help a certain class of users (flexible commit rewriting/rebasing), so it's not surprising that some seasoned Git users won't find it that helpful.

I think it's unfair to call it a "thin UI layer". My own project git-branchless https://github.com/arxanas/git-branchless might more legitimately be called a "thin UI layer", since it really is a wrapper around Git.

jj involves features like first-class conflicts, which are actually fairly hard to backport to Git in a useful way. But the presence of first-class conflicts also converts certain workflows from "untenable" to "usable".

Another comment also points out that it was originally a side-project, rather than a top-down Google mandate.

Comment · 1 year ago
Comment · 1 year ago
Comment · 1 year ago
Merges can be undone. Either you can manually remediate by `jj abandon`ing the merge commit so that it's not visible anymore, or you can restore the entire repo state to a previous point in time with `jj undo` or `jj op restore`, or you can do some remediation in between those two extremes.

Off of the top of my head, `jj new` and occasionally `jj rebase` can create merge commits; I don't recall any others.

Comment · 1 year ago
jj is pretty much just safer than Git in terms of the core architecture.

There's several things Git can't undo, such as if you delete a ref (in particular, for commits not observed by `HEAD`), or if you want to determine a global ordering between events from different reflogs: https://github.com/arxanas/git-branchless/wiki/Architecture#...

In contrast, jj snapshots the entire repo after each operation (including the assignment of refs to commits), so the above issues are naturally handled as part of the design. You can check the historical repo states with the operation log: https://jj-vcs.github.io/jj/latest/operation-log/ (That being said, there may be bugs in jj itself.)

Comment · 1 year ago
It's a bit unfortunate because most of the listed commands are indeed equivalent to Git commands. To give an example of new capabilities, in Git, you can't do the equivalent of

    jj rebase -r 'mine() & diff_contains("TODO")' -d 'heads(@::)'
in any reasonable number of commands, which will

1) find all of the commits I authored with the string `TODO` in the diff

2) extract them from their locations in the commit graph

3) rebase all non-matching descendant commits onto their nearest unaffected ancestor commits

4) find the most recent work I'm doing on the current branch (topologically, the descendant commit of the current commit which has no descendants of its own, called a "head")

5) rebase all extracted commits onto that commit, while preserving the relative topological order and moving any branches.

Furthermore, any merge conflicts produced during the process are stored for later resolution; I don't have to resolve them until I'm ready to do so. (That kind of VCS workflow is not useful for some people, but it's incredibly useful for me.)

Comment · 1 year ago
I believe `jj abandon` indeed operates on edges rather than nodes. It looks the diagram is updated now.

I believe that `jj squash` and `jj backout` also operate on edges rather than nodes, but the examples here don't make it clear. `jj squash` ought to combine the edge `r -> q` with the edge for `q -> parent(q)` (not depicted) and ultimately leave the `r -> q` edge as "empty", and `jj backout` ought to create an edge that has the inverse diff of another edge (which, in this case, is indistinguishable from `s`'s node changing to be equivalent to `q`'s node).

Live from the official Hacker News API

A modern reader for Hacker News · SvelteKit + Skeleton