Git Is Not Fine(billjings.com) |
Git Is Not Fine(billjings.com) |
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.
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.
Hopefully you have perfect CI coverage since you didn't bother to compile your PR even.
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.
For everyone else it's a net loss.
I've used Gerrit years ago, I thought it was great being able to shape my diffs into stacked chunks that reviewers could effortlessly navigate in a coherent story I'm telling.
Then I joined a company that wanted you to build and ship it in the same day. Now I dread the idea of going back to week long review cycles.
Ick.
> 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.
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/...
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?
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
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.
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].
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 stacked[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."
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.
Each individual PR gets tested and merged the same way they would if you’d authored them one by one in the first place.
The combination is merged in your tree well in advance of a PR ever being made. When the ancestor PRs are merged, you just pull and your descendent merge commit is rebased automatically.
At no point are you pushing untested code that you wouldn’t have pushed in a similar git workflow.
If I am pushing a PR with a working combination and rebasing after upstream merges how is jj changing the flow?
And it required at least twenty diagrams.
What do I want from you? Maybe a little less high-and-mighty a tone when dismissing a tool for being so complicated someone decided to use diagrams to explain it, when the very thing being replaced is so complicated that one of the best beginner resources needed to use diagrams to explain it.
Meanwhile, that article is inarguably the thing that made git “click” for an enormous number of people regardless of your disapproval of how some people prefer to learn.
Maybe be less judgmental.
You're talking about Git and jj. Surely, then, you must be a programmer, or at the very least have a passing understanding of programming. Perhaps you would like a refresher on control flow?
"If it takes 20 diagrams to make your case for why jj is better... Git is fine"
if (jjArticle.Diagrams.Count >= 20) Git = Fine;
else if (jjArticle.Case == Compelling) Git = NotFine;
else Git = Fine;
I made an if statement. If the condition of my if statement isn't true, then a different branch is followed.The article is extremely presumptuous, asserting that the software the reader currently uses is not good enough. I find the article strongly fails to make that case, and a part of why is because anything that takes 20 diagrams to explain is more convoluted than I need, ergo, Git is fine. That doesn't mean jj isn't good. Maybe jj is even better than Git. But the premise of the article isn't convincing the reader that jj is better than Git, but rather than Git is not good enough and that the reader should explicitly go out of their way to stop using it in favour of jj, which is a much stronger case to have to argue. You suggested I'm being judgmental but if anything it is the article that is judgmental.