b0rk,
@b0rk@jvns.ca avatar

today I'm thinking about the tradeoffs of using git rebase a bit. I think the goal of rebase is to have a nice linear commit history, which is something I like.

but what are the costs of using rebase? what problems has it caused for you in practice? I'm really only interested in specific bad experiences you've had here -- not opinions or general statements like “rewriting history is bad”

chrysn,
@chrysn@chaos.social avatar
b0rk, (edited )
@b0rk@jvns.ca avatar

deleted_by_author

kboyd,
@kboyd@phpc.social avatar

@b0rk some people have made a habit of using rebase instead of merge. And when they try to do that on a PR, they have to force push.

kf,
@kf@666.glitchwit.ch avatar
kboyd,
@kboyd@phpc.social avatar

@kf @b0rk I think I went a few years without rebasing, until I had to do it twice last month. On PRs that were themselves a few years old. (it was a way better experience than merge for bringing things up-to-date)

b0rk,
@b0rk@jvns.ca avatar

@kboyd @kf yeah I do that too, to me a PR isn't really a "shared branch" in the same way (nobody's going to git pull from it for example)

kboyd,
@kboyd@phpc.social avatar

@b0rk @kf ... that was another thing I did last month, git pull from the PRs of coworkers for performing a more thorough review.

But with no intention of pushing, so a rebase wouldn't matter.

And I have pushed to someone else's PR before, but it was eons ago.

matthieu,
@matthieu@weber.fi.eu.org avatar

@b0rk @kboyd @kf my policy is that if a branch is public (i.e. accessible to anyone else than me), then I don't rewrite history (and I would use a merge instead of a rebase). So the source branch of a PR could be public or not, depending on whether the repository containing it is public or not (e.g. at work we have our own, private clones of the main repo and make PRs from branch X of that clone to branch X of the main repo).

xdetant,

@b0rk would a good experience going the opposite way (TCR not rebased) be helpful to you to discover not so obvious costs?

b0rk,
@b0rk@jvns.ca avatar

@xdetant what’s TCR?

xdetant,

@b0rk https://medium.com/
Test && commit || revert
A side effect is that you start to have really small commits so if you want "nice linear history" you'll probably have to do some serious rebase.

drearytown,

@b0rk for me, it was that it does not work with uncommitted changes. I don’t really like stash, don’t know why, I just never was comfortable doing it.

Nowadays it tends to be more of a feature, as it pushes me to commit frequently and make changes smaller.

SurprisingEdge,

@b0rk the most common costs I encounter with rebases happens even when everyone involved knows how to perform a rebase.
One cost is somewhat GitHub specific: comments made prior to the rebase (and force push) no longer link to the commit. While the few lines of code shown with the comment stay, trying to navigate to see the code around that no longer works. (Unless something’s been fixed since I last did this, in GitHub enterprise.)

thirtycats,

@b0rk In my experience, rebasing can lead to situations where people sharing a branch accidentally blow away each others' changes, because it requires a force-push to update remote. Rebasing can also get messy if you need to change the base branch (for example, you branch B off of A, and then C off of B; B merged into A, now you need to rebase C onto A). Interactive rebase is invaluable for those situations, but sounds intimidating (it's easier than it sounds! Highly recommend!).

pmdj,
@pmdj@mstdn.social avatar

@b0rk Disclaimer: I tend to avoid merge commits for all the usual reasons and do a lot of rebasing.
I think the main problem is really poor tooling more than anything else. Part of it is that ‘rebase’ is really one operation for achieving a bunch of different subtly different goals, e.g.:

  1. A mass cherry-pick for advancing a feature branch past upstream progress.
  2. Attempting to reconcile different variants of a feature branch.
  3. Actively rewriting history to tidy up commits, etc
pmdj,
@pmdj@mstdn.social avatar

@b0rk The “cost” is (a) training the team to use it effectively despite the horrendous UX (b) dealing with the fallout when it nevertheless goes wrong. (I should mention that merge isn’t much better in this regard; our intern got 2 feature branches into a horrible knot of merge commits some months ago.)

The UX for when things go wrong is far from ideal, and to some extent could be improved by behaving differently depending on what you’re using the rebase for.

b0rk,
@b0rk@jvns.ca avatar

@pmdj thanks, I've been thinking along the same lines ("rebase actually does 3 totally different things”) and this framing is really good

huxley,
@huxley@furry.engineer avatar

@b0rk I have been on projects that always squash/rebase, and a particular big project that never does. In practice, I prefer squash/rebase. The hypothetical advantage of keeping full history (you can see how an engineer arrived at a solution) has never paid off. Instead, unsquashed history creates problems for git bisect and generally following how development actually happened. Clean commits ftw.

On occasion, a PR gets so big and old that it is unrebaseable. In those cases we either merge as is or, brace yourself, I generate a single big diff and apply it cleanly :-).

vmaurin,
@vmaurin@fosstodon.org avatar

@b0rk Previous week in my team : we do rebase before merging to main so while we still have merge commit, we always merge 1 commit. Dev A create a branch, do many commits. Dev B do a branch from Dev A branch (here was a mistake). Dev A rebase and merge, Dev B branch is a bit "lost" from main because it is based on a gone history. We ended up checkout individual files into a brand new branch

MikeStok,

@b0rk @talexb sometimes I run into trouble when using git rebase -i to rewrite history, usually because a single file has undergone several distinct changes which I muddled up during conflict resolution.

I think problems with the rebase indicate that my working practice can be improved (more smaller steps, do one thing in each commit, better planning, all easy to say with hindsight).

Often I’ll reset the branch and git add -p to create an untainted history rather than use git rebase -i

thatandromeda,
@thatandromeda@ohai.social avatar

@b0rk On further reading it’s possible I use rebase all the time - I love rewriting my messy work-in-progress history to something that tells a clean story for review - but I do that through a GUI because I need it to literally see what I’m doing. Maybe that’s rebase under the hood? Very different use case from alternative-to-post-PR-merge, though.

b0rk,
@b0rk@jvns.ca avatar

@thatandromeda ooh what GUI do you use for it?

thatandromeda,
@thatandromeda@ohai.social avatar

@b0rk gitup! It is the actual best.

b0rk,
@b0rk@jvns.ca avatar

@thatandromeda ooh yes i’ve been looking at it and i’ve been SO impressed (even though I don’t use GUIs for git), love hearing about how people are using it

gvwilson,
@gvwilson@mastodon.social avatar

@thatandromeda @b0rk I frequently rebase on feature branches, but have learned the hard way to never do it if I've merged anything from another branch - it's just too hard (at least for me).

doekman,
@doekman@mastodon.nl avatar

@b0rk What is even a “linear commit history”. I just commit my changes to git, and the history is a reflection of that. Never wanted rewrite history, but I would be interested in the why…

OdyX,
@OdyX@framapiaf.org avatar

@b0rk It's by definition a solitary process: good in pre-push situations; bad (or worse) after a history has been pushed.

thibault,
@thibault@mastodon.online avatar

@b0rk When using rebase on a branch a to merge commits from a diverging branch b, it replays all commits from b on top of a, which is nice but it checks/resolves conflicts one commit at a time, without telling you explicitly.

I've had numerous times where I forgot this is the expected behaviour, was suprised not all my changes were replayed on top of a (since I hadn't reached the HEAD of b), got scared I messed something up and aborted the rebase to merge my changes another way.

santry,
@santry@hachyderm.io avatar

@b0rk While I love rebase, it can make it confusing to find things in the reflog. If you rebase the same commit a few times, you end up polluting the reflog with multiple entries for that commit, each with the same commit message but a different hash. So if you’re trying to use the reflog to find the “good” commit, you have to wade through all those identical commit messages and be sure to find the right hash.

malwareminigun,

@b0rk the main risks of rebase are that git is kept out of understanding in what order changes happen, so a merge conflict resolution to a feature branch or vice versa can be lost. See https://devblogs.microsoft.com/oldnewthing/20180323-01/?p=98325

BUT: if the merging branch is going to be gone forever after the merge, none of that applies to you and squashed history is much easier to follow.

I don’t like semi-linear merge because it creates a linear history, but full of commits that were never on main, meaning bisects or blames can be more difficult.

adb,

@b0rk Anytime you have to massage a patch to fit after a different set of changes is fraught with the chance to get something wrong, but that's true with traditional manual patches, git merge, or git cherry-pick too. And a merge can have multiple changes coming down both sides and really collide in a messy way! Safer to reapply one change at a time. In the long term a linear commit history is easier to deal with, so appropriately squashing and rebasing / cherrypicking development onto mainstream and retiring a hacky dev branch is cleaner. Doing a git commit --amend to be more eloquent with the commit message is a wonderful thing too.

neko,
@neko@mastodon.cloud avatar

@b0rk The only times I've found it awkward are when I've rebased then force-pushed my branch, but a coworker already had a checkout of the old one.

I find rebase -i in general to be the best way to do things. I can squish the accidental "fixed the thing" "fixed the thing actually, this time" commits and make a cleaner history that still captures the steps I took, and it won't be squashed into one big commit at the end, I can still investigate the history months later.

trptcolin,

@b0rk yesterday I rebased mainline & force-pushed some updates to a PR branch, which caused the github ui to show “can’t find that commit” or some such when reviewer tried to show “changes since last review”

coderjoe,

@b0rk others rebasing have caused me lost commits, difficult diverged histories, complicated mega-commits, difficult PRs, etc...

I treat it as a sort of golden rule since rebasing locally impacts only me, but rebasing remote history impacts everyone else.

That's why I teach how to rebase locally but also teach "never rebase a remote".

I dislike dealing with surprise diverging remotes, so I avoid inflicting them on my peers.

All rules have exceptions of course, but this is my starting point.

snorerot13,
@snorerot13@mstdn.social avatar

@b0rk
The best part of rebase is that it gives you excuse to sing the bridge of Grandmaster Flash's "White Lines" before you hit return.

ShadSterling,

@b0rk I haven’t used rebase in years, because I found it breaks things without telling me why, whereas merge reliably shows me what all the conflicts are

(merge also lets me run tests before committing, so I can fix anything that breaks without a conflict; I don’t remember whether rebase allows that)

viraptor,
@viraptor@cyberplace.social avatar

@b0rk the only cost I know is "people get confused and resolving the situation takes time and lots of help" if a shared branch gets rebased. Many of my co-workers do not know what to do in that case and some have resorted to "just rm and clone again".
I've never seen actually-technical costs.

marshian,
@marshian@mastodon.gamedev.place avatar

@b0rk one cost of using rebase is if you have long build times, but are using a CI system that builds each commit, then you rewrite history, your build artifacts no longer match your history, so you can't do things like binary search build artifacts for where a problem was introduced.

duelinmarkers,
@duelinmarkers@hachyderm.io avatar

@b0rk the definition of "shared" is fuzzy. For some projects, any branch others could possibly see ought to be considered shared and only-force-push-in-emergency. For most work projects at most companies, any PR branch could reasonably be force-pushed to make it easier to review.

  • All
  • Subscribed
  • Moderated
  • Favorites
  • random
  • ngwrru68w68
  • DreamBathrooms
  • thenastyranch
  • magazineikmin
  • InstantRegret
  • GTA5RPClips
  • Youngstown
  • everett
  • slotface
  • rosin
  • osvaldo12
  • mdbf
  • kavyap
  • cubers
  • megavids
  • modclub
  • normalnudes
  • tester
  • khanakhh
  • Durango
  • ethstaker
  • tacticalgear
  • Leos
  • provamag3
  • anitta
  • cisconetworking
  • JUstTest
  • lostlight
  • All magazines