Git Is Not Fine
billjings.com55 points by steveklabnik a day ago
55 points by steveklabnik a day ago
I continue not to understand much of the point of this. I don't recognize the git workflow the author is talking about, and neither do I see the point of stacked PRs. Commits are fine as a unit of isolating work, and rebasing to keep that neat is not difficult.
How many PR's do y'all tend to have in flight at once? I sometimes think being a native (C++) developer makes me have a different take on some of this. Maybe if I was a JS dev making quick changes with 5 PR's a day I'd care more about this.
Very often when writing a new feature, I have to fix a bug in another subsystem (and write tests for it), add a small capability to another subsystem, fix documentation elsewhere, and so on.
Those could be separate commits in one PR, and that’s the way I’ve historically worked. But in jj it’s trivial to make them separate branches and continue working on the merge of all of them, even if they haven’t been merged upstream yet.
The benefit is that my coworkers have absolutely trivial PRs to review, rather than one omnibus. If there’s some debate about one of them, not only can we still make progress by merging the others, but I can continue plugging away on my main feature branch while we decide on the best path forward. If one of those PRs needed a bugfix or changes, fixing them typically m requires quite literally zero VCS shuffling to incorporate into the work downstream.
My pace of and ability to work on features is no longer bottlenecked by reviews. My coworkers no longer have to review giant PRs that touch seven subsystems. I don’t have to wait until an entire feature is finished before coworkers can start merging smaller preparatory bits for it.
You can do some of this stuff in git. But it’s excruciating and so nobody does it except in rare circumstances.
But that means you haven't actually done anything with the PR, it is a hypothetical thing.
Hopefully you have perfect CI coverage since you didn't bother to compile your PR even.
I totally agree. I've never understood the push back against clean "railroad tracks" (i.e. rebasing instead of merge commits). It's simple, scales nicely and gives you a lot of options. Once you start allowing merge commits in the tree, things can get messy but with a bit of discipline, it elegantly solves every version control use-case I can think of, or have encountered, including at scale.
If you have a large PR with multiple nontrivial commits I think you should merge it so the intermediate states are the same ones that were originally tested. Otherwise you could break bisects, among other issues.
I work primarily in c++ and fully agree with the author. I think it makes more sense in the context of larger teams, possibly also monorepos. Review speed (both latency of feedback and how thorough your reviewers are), presubmit test runtime, flake rate, etc can lead to it taking a few days to get work submitted. In some cases you don't want to land work until you've finished a milestone of some sort. If others work on similar files to you, you will end up with several rounds of rebase conflicts to deal with too.
Do stacked PRs do something to avoid rebase conflicts if two people touched the same file?
I feel like parent was referring to a culture of shipping small changes frequently, which tends to result in stacked PRs.
Stacked PRs is mostly a way to avoid thousand- or tens-of-thousands- LOC branches, which makes each PR meaningfully reviewable. You need a good code review process for it to become useful. It’s very pleasant once you are accustomed to it.
I’ve seen successful teams that regularly do reviews of massive PRs and feel this serves them well enough. I suspect it just places a lot more trust on the developers to get the details right so reviewers only look at larger design issues.
The language of choice is not relevant. Even before AI, one can accumulate thousands of lines of c++ easily.
I've also seen teams struggling to review massive PRs as a single diff, but when I've seen that it's always because they aren't structuring commits to be individually reviewable.
Nothing to understand. It's the JJ spam post of the week.
A piece of software looking for a problem to solve.
Do you remember the TV ads where people were acting like imbeciles to sell you their junk products for 3 easy payments of 19.99?
If you like a thing, it feels natural to tell others about it so that they can also benefit from it. There is no ulterior motive here. Sure everyone in the community will benefit if jj becomes more popular, but it's not like they are trying to sell you something for money. If you don't like it, that's fine, but if someone is facing similar problems to the OP then they will benefit. Almost everyone I've shown jj to at work has converted because it solves the same problems for them as it did for myself. Of course, not everyone has those problems.
> There is no ulterior motive here.
I just want to point out that it is known that one of the biggest jj proponents on HN does have financial incentive to do so.
Steve Klabnik (the person that submitted this post) comments and posts about jj here often and works for https://ersc.io (startup mentioned in the post).
So don't be so sure that all of the PR here comes from a pure selfless act. Some of them have income tied to the solution they are preaching.
Git is fine, just automate your workflow. I usually have 5-50 parallel branches which need to be rebased on every master/main update, and several branches are nested.
So I have a rb.sh script for every major project which does the (partially stacked) rebases. When my magit fixups didn't catch it. And of course a lb.sh script (alias for pull --rebase) for the other machines to import the updated branches
I admit the diagrams and struggles the author describes are far past my own usage of git. And like they identify at the end of the article, for truly complex git operations today I use AI. I haven’t rebased manually for a while. Forget rewriting commit messages!
> Companies like Meta have enjoyed in-house systems that run circles around it for almost a decade.
Based on Mercurial… the VCS I enjoyed using.
There is an open source & git compatible version of Meta's VCS: https://sapling-scm.com/
I use AI prolifically for coding, but I haven't crossed the chasm of letting it do mutable operations on my vcs. It tends to revert changes too eagerly. Commit messages written by it usually miss the point of the commit and end up too verbose and need to be modified or completely rewritten in many cases. I feel like prose needs to capture style which is unique per individual which makes it difficult to do well.
I agree on the commit messages not being ideal, though a bit of by-hand rewording goes a long way.
Recently let Claude Code handle some commit history clean up: split a couple commits, reordered some, and identified some that could/should have been fixups, and reduced the number of commits from ~70 down to ~40. Very happy with the results and time savings.
FWIW, here’s my interactive rebase skill: https://github.com/cstrahan/claude-plugins/blob/main/skills/...
> There is No C
Well yes because git was supposed to be completely distributed. You can design a system which has this feature but then it wouldn't be as distributed as git, making unrelated forks second class citizens. It might still be a good idea for tool to have it but it is not strictly a better/worse scenario.
> Mutability
I think i can mostly agree to this. I do wonder if people never work in a scenario where they are only committing partial state and not complete state. Nevertheless being able to track and not losing uncommitted state is a strict improvement.
> workflows
Aren't worktrees enough here?
Working in growing monorepo I find git tragically annoying and lacking. On regular basis I stumble upon situations where I work on one thing, but it causes changes in other package and I have no clear no way to say: this changes go to branch #1, this other set of changes to branch #2, and another small fix to branch #3. Branch #1 depends on the others and once #2 and #3 get merged it should merge to master cleanly with no ceremony.
Switching branches is not a solution, cause all of this changes develop at the same time.
Neither worktrees nor stashes are even nearby being a viable solution. Unless someone enlightens me and explains how to achieve this flow easily in git I’ll be looking for better solutions. I just installed jj and I do hope it will bring some relief.
To be fair, before working in monorepo I did not have this kind of issues, or at least not that annoying. And yes, LLMs made the issue even bigger, cause it happens more often that while I’m coding on main feature I’ll write to Codex: „btw, fix this one thing while I’m busy with main tasks”, so my workstream is actually more tree-shaped than stream shaped.
You should look into `update-refs` functionality. By default git treats each branch independently, but with update-refs, git tracks pointers to branches and creates a dependency chain.
Thanks for sharing this pearl of knowledge! This is brilliant. I found this page which explains using this function well: https://andrewlock.net/working-with-stacked-branches-in-git-...
I don't mean to suggest you're doing something wrong, but it's not clear to me why you need three separate branches for this? Why not have these related changes as individual commits on a single branch?
Fair question.
First: even though the logic is connected the work happens in different packages, with different test suites and logically it’s seperate. I want the ability to traverse history of each feature separately even though they’re connected and I develop them at the same time. So package #1 has moved forward but I actually changed my mind about API for package #2 and want to roll it back. If all work happened on one branch I don’t see a simple way to do it, without rewriting history and cherry picking particular changes.
Secondly: I want to push changes separately for ease of review. Big PRs wait longer for reviews and the longer they wait the more conflicts I can get because something else has been merged while I was waiting for review.
Gradle (instead of maven) or jj (instead of git) considered harmful. Fix your overengineering and stick with the basics. If you end up at a point where you are fighting with maven and git and need to reach for more tools, you already failed and should turn around.
[dead]
This has pretty pictures but its verbosity and frankly made-up complexity is making me not take it as seriously as I perhaps should.
The way I'd handle rebasing stacked PRs/branches is to rebase the very last one. Then simply `git branch -f a-branch <logical same point on rebased>` for each of the others, done.
I worked on a project that had weekly releases. We had git submodules, and submodules of that, and on rare occasions a 4th repo. I would manually keep those all up to date with rebases pinning each submodule to the logical new points. It all became muscle memory. The lesson I learned is don't use submodules unless you really need to. (All the repos were our own.)
JJ may be great but a stawman isn't going to sell it to me.
Now I can tell an AI to rebase a stack and as long as there weren't any conflicts easily check the results.
Everyone has things that bug them, git isn't one of mine (today :-). Instead I have a custom keyboard layout that no one else uses that makes me feel better, but I don't go around telling everyone they should switch--unless you're curious[0].
> Then simply `git branch -f a-branch <logical same point on rebased>` for each of the others, done.
Yep, and after 2022 you can do this with --update-refs.
Situation 1: main has moved ahead, pull it and move whole stack (say feat1..N) on top of that
git switch main
git tag old main
git pull --rebase
git rebase --onto main old featN --update-refs
nvim app/config.py # fix conflicts if necessary
git add $_
git rebase --continue
git push origin feat{1..N}
Situation 2: adding a commit based on PR review on feat1 git switch feat1
nvim app/models.py
git add app/models.py
git commit -m 'make username unique'
git rebase feat{1,N} --update-refs
git push origin feat{1..N}
replace N above with how many ever PRs you have stackedIf it takes 20 diagrams (I counted!) to make your case for why jj is better... Git is fine. I don't need software that takes 20 diagrams to convey why I should consider it. (That includes a lot of the black magic Git wizardry too, of course. The extent of my Git usage does not require anywhere near 20 diagrams to explain either.)
Are we talking about the same git where—notoriously—one of the best ways to become proficient was to read Git From the Inside Out[1] replete with over 20 diagrams showing how various commands perform tree manipulations?
What do you want from me? I literally specifically called that kind of thing out in my comment[1], which was four sentences long of which half were about Git, so I'm not really sure how you missed it. Even that article assumes you already know how to use Git[2], in other words the premise of that article is not teaching you how to use Git or convincing you to use Git, but rather expanding knowledge you already have (and in reality probably don't need).
[1] "That includes a lot of the black magic Git wizardry too, of course. The extent of my Git usage does not require anywhere near 20 diagrams to explain either."
[2] "It assumes you understand Git well enough to use it to version control your projects."