On Mon, Oct 22, 2012 at 9:15 AM, Ian Docherty <
i...@docherty.me> wrote:
> what git work-flow do you use that keeps your history linear?
Two words: always rebase.
I actually work pretty hard to keep a linear history.
It's more effort up front but makes life much nicer
in the long run.
There's no fixed work flow, such as "topic branches"
or "development/master branch" or anything like that,
just a few rules that are all designed to avoid those
merge commits. Not necessarily at all costs, but at
many costs. (I use branches for all sorts of things
at various times, testing various alternative ways to
code something, holding work-in-progress code,
or just moving commits around and massaging history
(most of my branches are named things like "x" and
"foo" and they only live for 10 minutes). Git doesn't
ascribe any meaning to branches, which means they
can contain anything. Why constrain yourself to a
fixed work flow that prevents you from using a branch
in a particular way? Also, the code that I push often
bears little resemblance to the order in which it was
written. Rebase isn't just for avoiding merge commits,
it's for the more general task of keeping a clean
history. What matters is that someone coming back
several months later to read the history can make
sense of what's going on. So I always try to push
a sequence of commits that makes sense; not just
the end result but also every intermediate commit.)
First rule, never use the "Merge pull request" button
on github. That button uses "git merge --no-ff", which
is the opposite of the right thing to do. This means
you always have to merge code yourself using git
directly (or I suppose with some sort of GUI, but I've
never tried that).
Second, get in the habit of using "git merge --ff-only",
since the default ("git merge --ff") still produces merge
commits sometimes. With a mostly-quiet project like
beanstalkd, merely using --ff-only takes care of most
situations, since usually there's only one person
making changes at a time.
Third, sometimes we run into a case not covered by
a fast-forward merge, namely, two sets of changes
that have diverged from a common ancestor. Usually
in that case one of those change sets is mine and
hasn't yet left the comfort of my private laptop, so I
just rebase it on top of the other person's changes.
Occasionally, someone sends a pull request that's
based off an out-of-date head, probably because I
happened to push some commits after they forked
beanstalkd but before they sent the pull request. In
that case, I ask them to kindly rebase their changes
onto the current head of master. Usually that's easy
for them and they do it quickly. Then I go back to
step two above.
Note, this only works if development is centralized,
and that happens to hold true for beanstalkd. (Not
because I've ever had to insist on or even ask for it,
it's just an accident of history.) The rule of git rebasing
still applies: once your commits are "public" (that is,
someone might be doing development work based on
those commits), you shouldn't rebase them. Since
virtually all beanstalkd development happens on peoples'
laptops based on the repo at
github.com/kr/beanstalkd,
commits are "public" (by the definition above) when they
get pushed to master in that repo. If someone else were
to have a popular fork of the project, and we were pulling
changes back and forth, we'd wind up with lots of merges
because we'd be unable to rebase some things.
So, if you want a linear history, your workflow needs to
be centralized at the macro scale, but you can use any
workflow you want at the micro scale. The two rules
"always rebase" and "once your commits go 'public' you
can't rebase" combine to force you to be careful when
you make commits public.
It also really helps to break your changes into really
small, bite-sized pieces that are easy to rebase.
(Which is a good idea anyway.)
It also really helps to make sure that each bite-sized
piece is also a meaningful, self-contained change, so
you can publish them gradually instead of all at once.
(Which is a good idea anyway.)
Hope this helps!