Jujutsu comes in handy here for the same usecase:
https://www.stavros.io/posts/switch-to-jujutsu-already-a-tut...
Also found https://github.com/gitbutlerapp/gitbutler
That particular case can be solved much easier by rebasing outer-most branch with `--update-refs` flag.
I've settled on a workflow that reverses the situation. I simply commit all my work to the main branch and cherry pick commits into temporary feature branches only when submitting PRs.
This way I only need to worry about maintaining a single consistent lineage of commits. I've been using this workflow for about a year now and find it to be much easier than juggling and rebasing feature branches.
In case anyone's interested, I made a tool that automates this workflow. The worfklow and tool are described here: https://github.com/bjvanderweij/dflock/
What I would really like is a Git equivalent to Mercurial's "fold" operation. I usually make a bunch of commits as I work, just as checkpoints, which I then want to turn into a single final commit when it's done, which could be quite some time later, e.g. "started on thing", "broke it", "broke it more", "Add thing to improve foo of bar".
Mercurial's "histedit" command offers two operations to combine the commits: "fold" and "roll", where "fold" brings the earlier commit into the later commit and "roll" does the reverse. The "fold" operation does exactly what I want in this case: It brings all the changes into the final commit from when I actually finished it, using the commit date of that commit.
Git's "rebase -i" command offers "squash" and "fixup" and "fixup -c" and "fixup -C", but they all do the same thing as "roll", i.e. they keep the earliest commit's date, the date when I started working on the thing and not the date when I finished working on it. (So I then cut and paste the correct date and update the commit afterwards. This may not be the best way to do it.)
I think ‘git rebase —-update-refs’ is the better way to go for this scenario
GitButler handles all of this pretty automatically, if you don't want to deal with the Git gymnastics needed here.
I usually just `git rebase origin/main -i` after the base branch has been merged there, and this means I need to explicitly drop the merged commits, but I can inspect what's happening.
Stacked commits is awesome, but it sucks that with git you need all these workarounds, and that the servers (GitHub etc) are not designed with that workflow in mind.
I left Google a few months back to work on another project. I missed the internal version control so much that I dropped that other project and am now focused http://twigg.vc It's very similar to what's used at Meta and Google. Atomic commits, linear history, auto rebase, code review compatible with stacked commits.
This made good sense, though by the time I got to bits saying "that last step is critical. Without it, your next sync will break" and "Don't forget!" I was laughing out loud. I love git :-)
Even if `--update-refs` didn't exist, my experience is that git can identify duplicate commits produced by rebase, and knows to skip them when rebasing the same commits to the same place again. Am I imagining that?
I’ve been meaning to write this article for a long time @flexdinesh . Thanks for taking the time to share this technique for managing stacked diffs using vanilla git rebase!
I'm a heavy user of git-spice: https://abhinav.github.io/git-spice (created by a former coworker) and can't really go back to a time without it. While still not nearly as good as Facebook's Phabricator, it's probably the best workflow for small, focused stacked PRs you can achieve in a Github / Gitlab based repository.
For the example given, would merging branch 2 into branch 1 then branch 1 into main achieve the same effect?
Perhaps not an option if you need to release the work in branch 1 before the work in branch 2 is ready/reviewed/etc.
I believe the author would love stg: https://stacked-git.github.io/guides/tutorial/#patches
Fun stuff, but I'll stick to trunk based dev, small PRs... thanks!
This marker branch step feels like a workaround to a missing capability. It's something I can easily see one forgetting especially if they haven't been doing stacked diff workflows regularly.
I consider myself a shmedium experienced dev who likes to learn their tools and read source.
This seems like a house of cards whose juice isn’t worth the squeeze. But I would love to split up my PRs into smaller pieces.
I just would hate to waste time with an incomprehensibly goofed git history because I forgot a command.
Ah, I've been doing this for ages but apparently this practice has a name
Is there any reason besides merge commits ending up in history to not do this with merges instead? ie merge main into feature-1, then feature-1 into feature-2.
Sounds like using --update-refs would let you do all that in a single operation, but you still need to force-push and don't maintain an explicit merge/conflict resolution history, both of which could be considered sub-optimal for collaborative scenarios.
Instead of "stacked diffs", isn't the more "continuous integration" solution to split a big feature into small chunks that actually get merged?
Having to rebase again and again is a symptom that a dev branch is living for too long.
Eh I just use `git rebase -i` and delete the commits I don't want. Much easier to think about.
But the real problem with this workflow is that neither Github nor Gitlab support it at all. Not even Forgejo does. Which blows my mind because is such an obvious way to work.
As far as I know only Tangled actually supports it, but unfortunately Tangled is tangled up in its own weird federation ideas. There's no way to privately host it at all.
We use graphite at work to automate this workflow. The whole point is avoid this toil.
Every time I see one of these nifty git tricks or workarounds I find myself wondering, “why not just use jj?”
You get a nicer, significantly simpler interface. You don’t need any tricks. You don’t have to google how to work yourself out of a bad state, ever. And you get near-perfect git compatibility (ie you can use jj on a shared git repo, doing all the same things, and your teammates won’t know the difference).
I’ve wondered if there is a psychological thing here: someone who spent time memorizing all the git nonsense may have some pride in that (which is earned, certainly), that introduces some mental friction in walking away???