Git Rebase for the Terrified

brethorsting.com

212 points by aaronbrethorst 6 days ago


game_the0ry - 7 hours ago

I have been contributing code for 10+ years, and I have worked on teams that did rebase and others that did not.

Not once have a ever debugged a problem that benefited from rebase vs merge. Fundamentally, I do not debug off git history. Not once has git history helped debug outside of looking at the blame + offending PR and diff.

Can someone tell me when they were fixing a problem and they were glad that they rebased? Bc I can't.

xlii - 12 hours ago

Allow me (today) to be that person to propose checking out Jujutsu instead [0]. Not only it has a superpower of atomic commits (reviewers will love you, peers will hate 8 small PRs that are chained together ;-)) but it's also more consistent than git and works perfectly well as a drop-in replacement.

In fact, I've been using Jujutsu for ~2 years as a drop-in and nobody complained (outside of the 8 small PRs chained together). Git is great as a backend, but Jujutsu shines as a frontend.

[0]: https://www.jj-vcs.dev/latest/

throwaway7783 - 4 hours ago

I avoid rebase like plague (perhaps because of my early experiences with it). I used to get continuous conflicts for the same commits again and again, and the store and replay kinda helped with it but not always. Merge always worked for me (once I resolve conflicts, thats the end of it). Now I always merge main into my feature branch and then merge it back to main when ready. Does it pollute the history? Maybe, but Ive never looked. It does not matter to our team.

coffeebeqn - 13 hours ago

I wish rebase was taught as the default - I blame the older inferior version control software. It’s honestly easier to reason about a rebase than a merge since it’s so linear.

Understanding of local versus origin branch is also missing or mystical to a lot of people and it’s what gives you confidence to mess around and find things out

ratchetclank - 12 hours ago

I never understood why rebase is such a staple in the git world. For me "loosing" historical data, like on which branch my work was done is a real issue.

In the same class, for commit to not have on which branch they were created as a metadata is a rel painpoint. It always a mess to find what commit were done for what global feature/bugfix in a global gitflow process...

I'll probably be looking into adding an commit auto suffix message with the current branch in the text, but it will only work for me, not any contributors...

aib - 2 hours ago

My default pull is ff-only. I don't like merging or rebasing by default.

When working in a short-lived branch, I like to rebase. I usually get no or simply easy-to-solve conflicts. I like my small and numerous commits stacked on top of the current develop. Regardless or whether we squash or not.

For long-lived branches (and technically for hard merges, though I've been using rerere more and more) merge is a better option.

What kills bisect, IMO, is large commits or commits with multiple subjects/goals. That's the reason I don't like squashed PRs.

jimbobimbo - 5 hours ago

Rebase is easy and not terrifying. Here's a 1k word article on how to do it correctly.

Or just do a merge and move on with your life.

thibaut_barrere - 13 hours ago

PSA: I’m not terrified of rebase, yet it’s good to know this:

https://docs.github.com/en/get-started/using-git/about-git-r...

> Warning - Because changing your commit history can make things difficult for everyone else using the repository, it's considered bad practice to rebase commits when you've already pushed to a repository.

A similar warning is in Atlassian docs.

embedding-shape - 12 hours ago

> The response is often hesitation or outright fear. I get it. Rebase has a reputation for destroying work, and the warnings you see online don’t help.

The best method for stop being terrified of destructive operations in git when I first learned it, was literally "cp -r $original-repo $new-test-repo && go-to-town". Don't know what will happen when you run `git checkout -- $file` or whatever? Copy the entire directory, run the command, look at what happens, then decide if you want to run that in your "real" repository.

Sound stupid maybe, but if it works, it works. Been using git for something like a decade now, and I'm no longer afraid of destructive git operations :)

parasti - an hour ago

Been using git since 2008, and this looks more intimidating than helpful. git rebase takes a list of patches and applies them one by one on top of a given "base" commit. And that's it. It's not all this complicated git command soup. It's just patches. No objects, no sha1s, no metadata, no branches, just literal textual diffs applied in order. It's the dumbest and also one of the most powerful things about git if you care at all about a readable history. If you don't, that's fine, but in some circles, e.g. most (if not all) open source projects, patch management and history hygiene is a very important part of good collaboration.

tomaytotomato - 12 hours ago

Github is not Git but I find the Squash and Merge functionality on Github's Pull Request system means I no longer need to worry about rebasing or squashing my commits locally before rebasing.

At work though it is still encouraged to rebase, and I have sometimes forgotten to squash and then had to abort, or just suck it up and resolve conflicts from my many local commits.

pabs3 - 12 hours ago

git rebase conflict resolution is a lot less scary with the zdiff3 merge.conflictStyle option.

Also incremental rebasing with mergify/git-imerge/git-mergify-rebase/etc is really helpful for long-lived branches that aren't merged upstream.

https://github.com/brooksdavis/mergify https://github.com/mhagger/git-imerge https://github.com/CTSRD-CHERI/git-mergify-rebase https://gist.github.com/nicowilliams/ea2fa2b445c2db50d2ee650...

I also love git-absorb for automatic fixups of a commit stack.

https://github.com/tummychow/git-absorb

quacker - 4 hours ago

Rebasing replays your commits on top of the current main branch, as if you’d just created your branch today. The result is a clean, linear history that’s easier to review and bisect when tracking down bugs.

The article discusses why contributors should rebase their feature branches (pull request).

The reason they give is for clean git history on main.

The more important reason is ensure the PR branch actually works if merged into current main. If I add my change onto main, does it then build, pass all tests, etc? What if my PR branch is old, and new commits have been added onto main that I don't have in my PR branch? Then I can merge and break main. That's why you need to update your PR branch to include the newer commits from main (and the "update" could be a rebase or a merge from main or possibly something else).

The downside of requiring contributors to rebase their PR branch is (1) people are confused about rebase and (2) if your repository has many contributors and frequent merges into main, then contributors will need to frequently rebase their PR branch, and each rebase their PR checks need to re-run, which can be time consuming.

My preference with Github is to squash merge into main[1] to keep clean git history on main. And to use merge queue[2], which effectively creates a temp branch of main+PR, runs your CI checks, and then the PR merge succeeds into main only if checks pass on the temp branch. This approach keeps super clean history on main, where every commit includes a specific PR number, and more importantly minimizes friction for contributors by reducing frequent PR rebases on large/busy repos. And it ensures main is never broken (as far as your CI checks can catch issues). There's also basically no downside for very small repos either.

1. https://docs.github.com/en/repositories/configuring-branches...

2. https://docs.github.com/en/repositories/configuring-branches...

jdthedisciple - an hour ago

Why would you rebase onto master locally in a team environment?

The way to do this are pull requests on the remote.

708145_ - 12 hours ago

I see no need to ever rebase manually, just merge on your branch and always fast-forward squash merge (only sane default) with GitHub/GitLab/whatever.

g0xA52A2A - 3 hours ago

> Before rebasing, push your current work to your remote fork. This gives you a backup you can recover from if anything goes wrong

I don't follow this. Just abort the rebase?

rich_sasha - 12 hours ago

I have lost ~irretrievably work via rebase.

I was working on a local branch, periodically rebasing it to master. All was well, my git history was beautiful etc.

Then down the line I realised something was off. Code that should have been there wasn't. In the end I concluded some automatic commit application while rebasing gobbled up my branch changes. Or frankly, I don't even entirely know what happened (this is my best guess), all I know is, suddenly it wasn't there.

No big deal, right? It's VCS. Just go back in time and get a snapshot of what the repo looked like 2 weeks ago. Ah. Except rebase.

I like a clean linear history as much as the next guy, but in the end I concluded that the only real value of a git repo is telling the truth and keeping the full history of WTF really happened.

You could say I was holding it wrong, that if you just follow this one weird old trick doctor hate, rebase is fine. Maybe. But not rebasing and having a few more squiggles in my git history is a small price to pay for the peace of mind that my code change history is really, really all there.

Nowadays, if something leaves me with a chance that I cannot recreate the repo history at any point in time, I don't bother. Squash commits and keeping the branch around forever are OK in my book, for example. And I always commit with --no-ff. If a commit was never on master, it shouldn't show up in it.

flux3125 - 12 hours ago

>the worst case scenario for a rebase gone wrong is that you delete your local clone and start over.

Wouldn't it be enough to simply back up the branch (eg, git checkout -b current-branch-backup)? Or is there still a way to mess up the backup as well?

MeteorMarc - 7 hours ago

Nice, git rerere would have saved me in the past.

aeinbu - 11 hours ago

> I always use VS Code for this step. Its merge conflict UI is the clearest I’ve found: it shows “Accept Current Change,” “Accept Incoming Change,” “Accept Both Changes,” and “Compare Changes” buttons right above each conflict.

I still get confused by vscode’s changing the terms used by Git. «Current» vs «incoming» are not clear, and can be understood to mean two different things.

- Is “current” what is on the branch I am rebasing on? Or is it my code? (It’s my code)

- Is “incoming” the code I’m adding to the repo? Or is it what i am rebasing on to? (Again, the latter is correct)

I find that many tools are trying to make Git easier to understand, but changing the terms is not so helpful. Since different tools seldom change to the same words, it just clutters any attempts to search for coherent information.

ngruhn - 12 hours ago

Maintaining linear history is arguably more work. But excessively non-linear history can be so confusing to reason over.

Linear history is like reality: One past and many potential futures. With non-linear history, your past depends on "where you are".

    ----- M -----+--- P
                /
    ----- D ---+
Say I'm at commit P (for present). I got married at commit M and got a dog at commit D. So I got married first and got a Dog later, right? But if I go back in time to commit D where I got the dog, our marriage is not in my past anymore?! Now my wife is sneezing all the time. Maybe she has a dog allergy. I go back in time to commit D but can't reproduce the issue. Guess the dog can't be the problem.
DHRicoF - 4 hours ago

I don't understand why I would push to origin my local branch. This will (potentially) require multiple push -f. I prefer to share the work in a state I considere complete.

As an alternative, just create a new branch! `git branch savepoint-pre-rebase`. That's all. This is extremely cheap (just copy a reference to a commit) and you are free to play all you want.

You are a little more paranoid? `git switch -c test-rebase` and work over the new branch.

Myrmornis - 6 hours ago

> the worst case scenario for a rebase gone wrong is that you delete your local clone and start over. That’s it. Your remote fork still exists.

This is absolute nonsense. You commit your work, and make a "backup" branch pointing at the same commit as your branch. The worst case is you reset back to your backup.

globular-toast - 2 hours ago

> Rebase has a reputation for destroying work, and the warnings you see online don’t help.

Everyone using git needs to accept the following. Say it out aloud if you have to: no command in git can ever modify or delete a commit.

After a botched rebase your old work is one simple reset away using the reflog. Then you can have another go or reach out for help.

dominicrose - 12 hours ago

When things get messy I use Sublime Merge with two tabs, one with the code that's open in VS Code and one with the same project but different branch/commit. It works well on Linux. I've managed to make it work with Windows + WSL but I don't recommend it.

jonfw - 6 hours ago

Coding agents are excellent at solving merge and rebase conflicts according to natural language instruction.

Deadron - 7 hours ago

Just do a normal merge, then squash all your commits in into one, using rebase, then a rebase onto a branch is easy.

dcre - 6 hours ago

In about 12 years of using git (jj user now) I almost never rebased through the CLI, but I found shuffling branches around in a GUI pretty intuitive. I liked GitUp[0], which gave me undo way before jj existed.

The common view that a Git GUI is a crutch is very wrong, even pernicious. To me it is the CLI that is a disruptive mediation, whereas in a GUI you can see and manipulate the DAG directly.

Obligatory jj plug: before jj, I would have agreed with the top comment[1] that rebasing was mostly unnecessary, even though I was doing it in GitUp pretty frequently — I didn't think of it as rebasing because it was so natural. Now that I use jj I see that the cost-benefit analysis around git rebase is dominated by the fact that both rebasing and conflict resolution in git are a pain in the ass, which means the benefit has to be very high to compensate. In jj they cost much less, so the neatness benefit can be quite small and still be worth it. Add on the fact that Claude Code can handle it all for you and the cost is down to zero.

[0]: https://gitup.co/

[1]: https://news.ycombinator.com/item?id=46602056

6LLvveMx2koXfwn - 6 hours ago

was fully expecting:

    mv folder folder-old
    git clone git@github/folder
phrotoma - 6 hours ago

git rebase appears to be a random number generator to me. I've got two PRs in flight, I realize that one branch requires something I did in the other branch. I go merge branch one, then rebase branch two off main. Half the time; success, get on with my day. The other half of the time; anarchy, madness, dogs and cats living together.

I remain terrified.

golemiprague - an hour ago

[dead]

sesuximo - 4 hours ago

TIL ppl are afraid of rebase lmao

skeptrune - 5 hours ago

i hope ai agents read this