
A Rebase Workflow for Git - joeyespo
http://www.randyfay.com/node/91
======
ef4
This strategy throws away some of the most powerful features of distributed
version control. It only works if you're going to work in a silo and then
suddenly share your changes, fully finished, with the world.

In any collaborative environment, or even as a solo developer working from
multiple machines, rebasing is a pain in the ass. It breaks your ability to
seamlessly synchronize your work across branches and across machines.

Don't fear merge commits. Git is built around the expectation that there will
be plenty of them, and the tools handle merge commits just fine.

The author seems to be trying to limit the damage from colleagues who don't
understand how to use git by severely restricting what parts of git they use.
I think that's an ultimately self-defeating strategy.

~~~
erso
Merge commits do so much harm, it's outrageous that anyone would think they're
any good (save for git merge --no-ff a branch that has already been rebased
onto the branch it's being merged into).

If I'm working along on a branch and someone commits something remotely, I
can:

git pull and get their changes as a merge commit

or

git rebase origin/master and get their changes below mine

The big difference here is that if I have a conflict with their changes and I
do a merge, I resolve those conflicts in the merge commit. This is terrible
for a few reasons:

* It means my commits are inherently broken. They're only made un-broken by the merge commit * When anyone else looks at my commit history, they have to look not only at the commits that I made but at the merge commit that resolved the conflicts from the prior commit, otherwise they're using a bad commit as a reference * When I do eventually merge my branch in, there will be a mess of commits from master splayed all throughout my commits, so that nobody can easily see what commits were actually mine without doing a git log origin/master..my_branch to see just what my branch is adding

Now, if I decide to use rebase instead of merge, I resolve those conflicts _at
the point in which they would have occurred on my branch_ , thereby making my
commits conflict-free. My history is also compact as it isn't spread over time
with (possibly multiple) merge commits from master.

If you happen to do merge commits you cannot easily rebase that branch without
ripping out the merges first using something like git rebase --onto
([http://pivotallabs.com/users/khicks/blog/articles/2118-git-r...](http://pivotallabs.com/users/khicks/blog/articles/2118-git-
rebase-onto)). You can have git try to replay the merges at the point they
occurred via git rebase -p (preserve merges), but that's dangerous and not
useful territory to be in.

The brunt of your argument seems to be that you'd prefer people to be
constantly pushing to master features that are incomplete or otherwise don't
work, all for the sake of having other people have your broken or incomplete
features available for them to start writing code against. This is madness.
You have to manage that mess with feature flags or other song-and-dance
nonsense that you could avoid entirely by using rebase instead of merge and
only putting your stuff on top of master (either via rebasing your commits
onto master as the OP notes or by --no-ff merging the branch, as I noted
earlier). In addition to that, you can no longer easily even tell what a
feature was. Maybe you use commit messages that have a story/card/bug ID that
you can use to track, but man, I'd hate to rely on that.

I've used the rebase strategy for multiple years now with teams of 20-60
people, distributed across countries with great success. I have yet to hear a
reasonable argument for merging other than "but, but.. you can't silo your
work!" The hell I can't. I'm going to work on the feature branch until, at
minimum, the feature is passed by QA as being feature-complete. Until the
point of me putting my work onto master I have absolute control over
squashing/rearranging commits, messages, deleting commits, and doing whatever
the hell else I want to do to make sure my commits are all green (passing all
tests), conflict-free, and sensible. Hell, I've even done talks on my rebase-
based Git workflow. Until that point, my commits aren't useful to anyone
because the work is by definition incomplete. I care more about a clean,
readable, green commit history than someone's idea that having all code pushed
to master as soon as it's written is somehow better.

~~~
j_baker
You know, I can respect people who choose to use rebase instead of merge, but
your arguments against merging borderline on hysteria. I mean, plenty of teams
of equal or larger size have dealt with merge commits that it's just silly to
say things like "Merge commits do so much harm, it's outrageous that anyone
would think they're any good".

Having code pushed to master sooner rather than later _is_ better. It means
that you have fewer developers stepping over each other to make changes. When
you have 20-60 (or more) developers working on many different things at many
different times, this is important.

Also, I think you're painting an extreme picture of merging where everyone
_always_ uses a merge commit for _everything_. It's silly to expect that with
a team of 20-60 people, _everyone_ should be doing git pull every time they
update and then pushing that back to master. We have git pull --rebase for
that. There are even options to make git do that by default.

I vastly prefer merge commits when dealing with feature branches. It makes it
much easier to see a logical grouping of merge commits, and makes it so I
don't have every commit interspersed between.

~~~
erso
The thing is, what you're saying directly contradicts reality.

You have fewer developers stepping over each other to make changes when they
aren't constantly merging in things that have a high likelihood of changing.

If someone makes a change and pushes it to master I can just as well rebase my
work on top of their commit, make any changes I might need to should there be
a conflict, and go on my way without having to merge anything. If I use merge
in that same situation I can end up with a string of useless merge commits
that contain conflict resolution practically hidden away from the real work.

Logical grouping of commits is still completely possible with merging as I
said, when you use --no-ff merging into the branch after having rebased on top
of it. For example, if I have a branch topicA, I can, having fast-forwarded
master and being on topicA, git rebase master, git checkout master, and then
git merge --no-ff topicA. This will give you the only acceptable merge commit,
with a history that shows where your branch diverged from master and what
commits it contains.

------
yonran
This is basically how people use git-svn, because svn only understands rebase
and not merge.

I'm a lone git-svn user in a svn workplace, and I've been satisfied following
this basic workflow. I have my configuration differences, personal changes,
and unfinished work in little commits on my branch. At the end of the day I
rebase -i or cherry-pick onto the upstream git-svn branch, clean up the
commits, and dcommit. At the beginning of each day I rebase yesterday's work
onto the tip of upstream and continue working.

~~~
e28eta
Same thing with git-p4, which is how I primarily use git.

You do miss out on the benefits of distributed version control, but I really
prefer it over working with Perforce directly.

------
wanderr
Having a clean, easy to read commit history in upstream is, in my opinion,
worth the few downsides of this approach. I care a lot less about when a
commit was made, I'm much more interested in when it made it in to upstream,
so having a linear history that makes that obvious is extremely valuable to
me.

------
languagehacker
Rebasing when pulling instead of merging has been a best practice for like 3
years now. Am I missing something?

------
shawnps
Rebase also helps me make less useless commits.

For example, if I commit something on a branch, and then later realize I made
a typo in that commit, I can make a commit that fixes the typo, then use git
rebase -i and make it a fixup commit. Fixup squashes the commit into another
one, and discards the message.

~~~
chrismsnz
I use 'git commit --amend' which does basically the same thing.

Both have to be done before pushing to remote, anyway.

~~~
erso
This works great but can only be used to amend HEAD. If you want to amend a
commit that's HEAD~1 or further back, you need to either use the fixup
strategy I mentioned above, or, if you really want to use --amend:

* git rebase -i SHA-to-be-amended~1 * select SHA-to-be-amended for edit * make your changes * git commit --amend -CHEAD (This takes the message from HEAD without presenting you with the editor. If you wanted to edit the message, use -cHEAD.) * git rebase --continue

It's good to know when and how to use both. The fixup strategy is much quicker
and doesn't require you to do the rebase immediately. I will sometimes stack a
few fixup commits and just do the interactive rebase (with autosquash) later.

------
mck-
In the comments section where he explains it with pictures, it's much clearer
than the actual article.

------
shin_lao
I don't understand the remark about the history. You can merge and "squash"
your history into a single commit. I don't understand what rebase brings.

~~~
merlincorey
In addition to squash merging, you can merge without fast forwarding (--no-
ff), which is a great method to make topical branches of related commits one
single atomic conflict free commit.

