
Don't use Git rebase - aslakhellesoy
https://medium.com/@fredrikmorken/why-you-should-stop-using-git-rebase-5552bee4fed1
======
andrewaylett
`git rebase --exec {rebuild project}` solves the issue of invisible errors in
commits. I'm a big fan of Gerrit's review workflow, which requires every
commit to build in isolation. I also usually try to squash my changes into
logical independent commits before review.

I like rebase because it's prettier, but I also think there's an issue with
the non-rebase case that the OP has missed: unless you rebase, you're setting
yourself up for failure in the `git bisect` case: when you step back to find
the source of an bug you're tracking down, the worst possible case is that you
find it's introduced by a merge and not present in either of the parents.
That's much more likely if your merge commits contain fix-ups of their own,
which in turn is much more likely if you've got overlapping branches. If you
rebase-and-merge then the merge won't have any extra changes, and if you
rebase-and-fast-forward then you won't have any merge commits at all.

~~~
golergka
But that's exactly why I prefer merges - seeing that the problem wasn't in any
individual branch, but resulted from the combination of changes in both is the
most honest result that I would've wanted to see. Why do you label this as a
'failure'?

~~~
Ballantara
It sounds like rebasing this way ensures branches will not overlap at merge
time. This presumably pushes the "combination of changes" into the rebased-
before-merging branch, which (if nothing else) makes sure that one committer
owns the bug, not two.

~~~
lostmsu
In case of merge that would be merge commit author.

------
ddevault
There's a more nuanced approach to git rebase. You should use it the other way
around - switch to your feature branch and `git rebase master` to update your
branch and resolve conflicts. Then test it and `git merge`. I also use git
rebase to tidy up the branch's history - generally not entirely squashing it,
though.

~~~
gutnor
Or well, simply use both. Feature branch, use merge - the feature is an
important artefact, and there it is important for the history to show it.

Bug Fix branch, working on a shared branch, use rebase. The branching in those
case is a side effect the exact time two colleague committed on the same
branch. There is no information you gather from that, it is just a technical
blip in the history.

Not quite sure the obsession people have in using only 50% of the tool they
have because the other 50% could be misused.

Similarly, digging for a bug in several hundred commits is going to be shit.
Hindsight is very deceptive with bug hunting - they always hide in plain
sight, if you know where it is, it is easy to imagine "oh, I would have seen
it immediately with a merge". Maybe, probably not.

You see that of that kind of overreaction in Management. There is a bug in
production, we must introduce more testing, or more testing phase, or change
the way we design the around that single experience. But sometimes, bugs just
happen.

~~~
keeperofdakeys
Rebases and merges don't work well together. By default, git rebase will get
rid of merge commits. While there is an option to preserve merges (-p), it can
lead to some strange behaviour while doing an interactive rebase - see BUGS
section in git-rebase man page for more details.

I'd also argue that merge and rebase represent fundamental differences in what
commits mean. The former being commits are history, and the latter being
commits are features.

~~~
oddlyaromatic
I'm a pretty basic got user, just wanted to say this was a really useful
distinction for me to read.

------
fulafel
What's even the point of using rebase? Merging the development branch into
your feature branch periodically is the obvious history preserving thing.

Git already has merge commits, that can be used to label and describe bigger
sets of changes in retrospect. There is no need to rewrite the commit history
with the benefit of hindsight, it only erases the record of how changes were
arrived at, thus losing the opportunity to revisit conclusions from debugging
or experiments.

You can also use merge commits to describe sub-units of work in your feature
branch. Just rename your branch to some subtask and merge that into your
feature branch.

edit: towards the middle of the article, the author also opines "What
motivates people to rebase branches? ... I’ve come to the conclusion that it’s
about vanity. Rebasing is a purely aesthetic operation. The apparently clean
history appeals to us as developers, but it can’t be justified, from a
technical nor functional standpoint."

~~~
Vinnl
There's no such thing as "real" history - you don't commit every line of code
you add or remove, or even every character. Rather, you choose some points in
time to commit.

For me, those are often arbitrary - I can't get something to work at a certain
point, so I make a WIP commit with the buggy work at that point, and will come
back to it the next day.

Before I merge my branch back into master, though, I want my commit history to
be useful. "This is the point where I went home or was disturbed that day" is
not useful to future developers. "This is the work I did on this individual
feature and everything that's needed to run it and to have the tests succeed
is in this commit, and this was the reasoning behind what I did", however, is.

In other words, I rebase to divide my codebase into non-arbitrary units of
code, not based on chronology, but on what is useful together.

~~~
he0001
Well, assuming that you are adding features in parallel you have an history.
You have a branch with feature A and are about to build feature B, which is
now based on A, someone else is building feature C which is also based on A.
Building B and C might require different or equal changes to A.

There's no guarantee that any of these features will be built in order since
they might have different priorities, difficulties or level of acceptance so
it's hard to tell which one must or will be done in what order. Rebasing
pretty much settles that while merging is much more sane to that workflow.
It's harder to keep it functional yes, but it's enabling parallel development.
Using rebasing and/or merge isn't a source control problem but a feature
management problem.

~~~
Vinnl
Yeah I think my point was more that a blanket ban on rebasing is too rigorous.
I agree that once you want to integrate B and C (or both into A), a merge is
usually the best way to do it - and I think that's what TFA was actually
referring to.

It fails to consider the case, however, of rewriting B's history internally,
not as a way of integrating with A or C, but as a way of making its commits
clear. Afterwards, you'd still do a merge of A into B and then merging B back
once you see that's successful.

------
format71
I like rebase. Because to me, git is more about communicating changes to other
people than finding bugs. Just like testing is as much communicating intent to
other developers as preventing new bugs.

So we rebase, and we merge with merge commits. This way, the developer are
forced to resolve conflicts one by one on their own branch, instead of sorting
out a huge pile in one go on a shared branch.

What I like about git, though, is that you can choose different approaches.
Discuss in your team what you find important and use git to support that. If
finding bugs with bisect is your main thing, use git in a way that makes that
as easy as possible. If your have other needs, you'll have to find other ways
of using the tool.

Learning and understanding the tool to use it in the best way to satisfy your
needs.

------
reledi
This seems like a knee jerk reaction because a co-worker's sloppy rebase
caused you to waste a day.

This highlights a bigger issue, many people don't learn their tools well
enough.

I've been teaching my fellow senior engineers how to use git the last six
months because they've only been using git GUIs until then. They're terrified
of merge conflicts and they often make mistakes fixing them.

I'd rather educate people and let them make their own decisions once they can
understand and justify the tradeoffs.

~~~
plicense
My thoughts precisely. I mostly use rebase, except when I know multiple
commits in my feature branch will cause merge conflict with master - in that
case, I save myself the trouble, do a merge and be done with resolving all
conflicts in one go.

My ideology is - prefer rebase first, resort to merge if it will let you do
the gnarly merge fast. Of course this is because of the development
environment I work in where we just don't use bisect and the workflow is
different. I also keep in mind that if I work on a different repository with
differing testing/development processes this ideology will change.

The first few days I work on any new project(due to a job/project transition),
I figure out how I can iterate as fast as I can and see what my time saving
points are. How to best use the git I know, on the current repo, is also a
minor part of this poking process.

------
singron
Doesn't squash and rebase eliminate this problem? It removes all those
possibly broken intermediate commits once it's in master.

I'll add that another annoying thing about rebasing is that if you make
multiple changes to the same piece of code that conflict with changes on
master, when you rebase, you have to resolve each change independently instead
of only the last snapshot. However, if the changes are in different places, I
like the incremental conflict resolution process of rebasing instead of the
one-shot merge commit.

~~~
jmiserez
You can have git remember the previous conflict resolutions and automatically
apply them the next time you rebase the same code by setting git config
--global rerere.enabled true

It’s a builtin feature, see the documentation [https://git-scm.com/docs/git-
rerere](https://git-scm.com/docs/git-rerere) and a description here:
[https://git-scm.com/blog/2010/03/08/rerere.html](https://git-
scm.com/blog/2010/03/08/rerere.html)

Very handy if you use rebase with multiple commits to the same code.

------
thibran
There is a third option nobody seems to talk about `git merge --squash` (a
squashed commit bundles commits into one commit). Which produces like `rebase`
a linear commit history, but preserves the single commits.

~~~
rout39574
I would think squash a poor default policy; it destroys information in the
granularity of commit, and in the commit messages.

~~~
baq
Nothing is lost if there's no information there in the first place.

~~~
rout39574
I agree; if your commits are poorly planned and poorly commented, then I don't
see any particular reason to avoid squashing them.

But if your commits are poorly planned and commented, I would recommend trying
to improve them, rather than reveling in the fact. ;)

------
narsil
In addition to squashing commits, you can merge with `--no-ff` to create s
merge commit and semi-linear history showing when new code arrived.

~~~
humanrebar
This should be getting more attention. From the perspective of the master
branch, it has the benefits of squashed merges without losing your commit
history.

I'll often have a patch that has a few things going on:

1\. Refactor code in one file

2\. Fix a bug in another module uncovered by the newly refactored code (maybe
a code path that hasn't been hit until now)

3\. Some quick fixes made while I was looking at that code

...if I made a mistake in step 1, it's likely that step 2, step 3, or both
would be useful to keep. If it's squashed and merged, it may be difficult to
undo just step 1. And it's good communication to keep each as their own commit
because each is its own atomic change.

And I can always squash things myself as I feel the need.

------
pletnes
At least part of the arguments against rebase are arguments _for_ feature
branches. Keep master forever and rebase your feature/bug branches, I would
rather say. E.g bitbucket has features for this too - prohibit force push on
master/release branches, allow on dev branches.

------
rsp1984
_There are many magnificent tools that can analyse and visualise complex Git
history, both GUI- and CLI-based._

Just tell me one. All git tools I know do such a terrible job at this.

~~~
rout39574
Any examples of what you find terrible?

Ever tried magit? I don't know if you'd find it terrible, I find it not so
bad.

------
chrisjshull
I'm really surprised no one (article included) has brought up the "Golden Rule
of Rebase"
([https://www.google.com/search?q=golden+rule+of+rebase](https://www.google.com/search?q=golden+rule+of+rebase)),
which boils down to "never rebase a shared branch". Git is an extremely
powerful tool for collaboration, and it's frustrating when I see that
undermined.

~~~
scarlac
The rule makes a lot of sense but most of the articles I found completely
ignore if this includes systems like GitHub or Bitbucket. Technically you can
create a Pull Request based on the branch yet no-one is actually "using" it.
Would you say the rule also applies to such a branch?

~~~
chrisjshull
I would. A common thing I like to do is start working on top of work that's in
a Pull Request. For example, maybe a coworker is adding an API that I want to
use. So long as I'm confident the API won't have drastic changes, and there's
just smaller polish or testing to be added, I can branch off of their branch
and start working without delay. This also gives me a window to live on top of
the changes and give feedback from usage even faster (maybe even before it
officially lands).

------
2T1Qka0rEiPr
I tend to use rebase solely for the purposes of creating tidy commits before I
merge my changes into a staging branch.

For example when I'm working on a feature I tend to do n things at once, but I
then want to create logical commits which separate the work into logical unit
which could be reverted etc. as necessary. If in this process I notice that
I've forgotten something (or for that matter, realise later than I've
introduced a bug / broken tests) I'll tend to create a patch commit for that
logical unit and then `git rebase -i HEAD~n` and then fixup that patch into
the original commit.

Also, whenever I'm done for the day instead of stashing I: `git commit -am
"wip"; git push; git reset HEAD~1 --soft` (i.e. push my changes up to Origin
to avoid any localized mishaps with my PC resulting in a loss of work). I then
force push to my feature branch.

I know that both of these "change history", but as long as they're isolated to
my own feature branches I see no reason to avoid doing so...

------
OJFord
> Consider the case where a dependency that is still in use on feature has
> been removed on master. When featureis being rebased onto master, the first
> re-applied commit will break your build, but as long as there are no merge
> conflicts, the rebase process will continue uninterrupted. The error from
> the first commit will remain present in all subsequent commits, resulting in
> a chain of broken commits.

Easy, just fixup the commit that (re)introduced the dependency.

> You pretend that the commits were written today, when they were in fact
> written yesterday,

The author and committer dates will differ accordingly.

------
nunez
Rebase is incredibly useful for me because I commit on every save and squash
my commits before submitting for PRs (if working on a team). I commit on every
save for three reasons:

1\. I can easily undo small mistakes this way,

2\. It makes it easy for me to pick up what I've done the last time I worked
with that codebase, and

3\. It makes it easier for me to tell a comprehensive story when I'm ready to
submit my PR.

That said, I do see the authors point about rebasing onto a branch with
dependencies.

~~~
jmah
"rebase" (like many terms in git) has multiple implications. It sounds like
you're advocating for squashing your commits / cleaning up your history, which
I don't think anyone argues against. The linked post argues against re-
parenting those changes.

------
shock
> Graphs of non-linear history, “train tracks”, can be intimidating. They
> certainly felt that way to me to begin with, but there’s no reason to be
> scared of them. There are many magnificent tools that can analyse and
> visualise complex Git history, both GUI- and CLI-based.

It's a pity the author doesn't mention some of those magnificent tools. Some
tools I know/use:

    
    
      CLI: tig
      GUI: gitg, qgit (Linux)
    

Any others?

~~~
tekacs
For Mac users, there's [http://gitup.co/](http://gitup.co/) (I'm not
affiliated and it's FOSS).

GitUp is beautiful, incredibly fast and you operate directly on the (well
laid-out) graph for almost everything, so you're always acutely aware of the
commit history.

(I mostly use Windows + Linux at the moment and this is probably the piece of
software I miss the most, even though I prefer shell for absolutely everything
else)

~~~
anonred
+1 for GitUp. Only annoyance is that it can be slow when staging/unstaging
lots of files.

------
speedupmate
this is a narrow view based on someones versioning habits , the point of
rebase can also be a solid linear history that allows multiple teams to fork
and pull request features between forks. If developer chooses to play merging
inside his own repo, fine but as soon as you have large teams working on their
own you will end up in merging hell between developers and teams.

say team a does 58 commits per day has 75 team-members and team b has 126
members that are doing 187 commits per day and there's team c, d , e .... n
giving non conflicting input to your codebase.

the flow in this case would be to always rebase developer specific features on
non-conflicting codebase before you are allowed to pullrequest your changes to
central repo. Rebasing to master or to any feature branch developer needs to
work will allow them to see any conflicting changes they have made directly in
their repo (rebase conflicts and a way to solve those as they know what
conflicts, they have introduced the conflicts) instead of merging it together
and finding out that the repo they need to PR this stuff will utterly fail
cause they are lagged behind or several developers have changed the same
files.

in this case rebase flow brings the shit to developer to handle and gives them
knowledge that it will break. This mainly happens cause they are not having
the latest version of code whereas merge strategy will merge in the conflict
and send it to others to discover that thy can't merge any more cause of other
developers conflicts.

Merge strategy is not suitable in case where code is edited rapidly daily and
some features take , weeks, years, are to be included. Whereas rebase strategy
ensures that every developer will always send you changes that are not
conflicting with up to date version of whatever is versioned.

------
moogly
I vehemently disagree. A counter-argument to his `git bisect` problem is
whenever I do `git bisect` and I end up on the merge commit being the culprit.
At that point I want to cry, because merge commits tend to be ungrokkable —
there is so much noise in them.

Also, don't even get me started on `git revert`ing merge commits... Down that
road lies sadness and disillusion.

~~~
brianwawok
Indeed. Seems like a better solution to his problem is to run unit tests after
a merge before pushing it upstream. Then no more non compiling commits.

------
onedognight
If you want every commit to compile then have your CI system check this; no
need to blame a useful tool.

------
yyparm
I tend to think the problem identified by the author is more of a fundamental
problem with long-lived development branches that diverge with master - stuff
will change under you and it's not always easy to notice.

It's also kind of a problem if underlying parts of the system that you depend
on either are churning that much without that being communicated or if they
have poorly-defined interfaces and are prone to accidentally breaking things
that users depend on.

It's not entirely clear, but there may be some testing gaps too if bugs
weren't found.

Maybe merge-based workflow helps a bit but it seems like the pain would still
be there regardless.

~~~
fredrikmorken
Author of the article here. You are absolutely right, and many of the other
comments here suggest that people are struggling with problems that stem from
the fact that their branches are long-lived.

I would encourage everyone to consider adopting trunk based development
([https://trunkbaseddevelopment.com/](https://trunkbaseddevelopment.com/)). I
expect this to solve many of the problems people have. Using short-lived
feature branches that are merged every day, merges are trivial, and history
easy to read. A rebase-based workflow wouldn't be that harmful if you use
short-lived branches either, although the argument for preserving history
still stands.

------
jaeckel
I liked the style of writing, but the lack of knowledge of the author made me
create this account and adding my first hn comment.

Thanks to all others who explained technically what upset me so much.

------
blikdak
Odd, I would rebase develop onto my feature, resolve conflicts which is easier
as I'm dealing with my changes, then merge to eg develop. When time comes for
integration I'd probably squash commit changes to the integration branch just
to keep that a bit easier to track/undo, but preserve full history in my
feature and develop branches do can revert specific commits etc. As always
useful comments are a must so I disable automated merge commits.

------
TheCoreh
When using `git bisect` to find a bug, `git bisect good` and `git bisect bad`
are not the only options available, there's also `git bisect skip`. You should
only mark as bad commits that specifically manifest the bug you're looking for
and not, say, build errors or other unrelated bugs. It _is_ true however that
the type of build breakage potentially brought in by using git rebase will
require you to do more bisect steps.

~~~
ris
> It is true however that the type of build breakage potentially brought in by
> using git rebase will require you to do more bisect steps.

Or leave you with an inconclusive result if the guilty commit also happens to
be one of the _skipped_ commits

------
jibberia
I use rebase because I often have long-running feature branches (maybe for a
couple of weeks) and I want to keep up with changes on master. When I was new
to git, I used to merge master into feature branches to achieve the same
effect, but my pull requests were littered with commits already made to
master.

Is there a better way to keep feature branches updated with changes on master?

