
A simple git branching model - _prometheus
https://gist.github.com/jbenet/ee6c9ac48068889b0912
======
jamesrom
I still don't understand why everyone has this misguided quest for a clean
history. An accurate history is much more important.

Rebasing destroys historical information. I can't really see any advantages of
rebasing when a merge does the same thing but leaves two things rebasing does
not: 1) a point to rollback to if things don't work out, and 2) an explicit
entry of when your branch was brought up to date with master.

~~~
Ygg2
Because clean history is easier to bisect. It's easier to visually track
problems, (aha so you changed thing A in branch br12 and thing B in branch
br13 as opposed to wait so person A branched into br12, then person C branched
into br23, then it got merged with br74, which was merged with person D on
branch br84..).

Less entagled workflow is easier to untangle and consequently understand even
if it hides some stuff.

Also it's visual clutter. If your history looks like train map, your project
is probably a train wreck.

~~~
barrkel
This is an artificial problem. Git has almost all the data needed to present a
squashed view - all it's missing is an idea of what commit a branch pointed to
throughout history, so that it can merge together commits in in the "bubbles"
for presentational purposes.

It would be better to fix this, so you get nice diffs, blame etc., than deal
with all the other issues rebase causes.

I'm not convinced on the bisect issue either. If your app is trivial, sure,
but if the features are more complex, the squashed commits will be too chunky
to narrow down as usefully as a fuller history can.

~~~
stevenashley
I'm not convinced on the bisect issue either. I've personally done a bisect
spanning 10000 changesets with 50 concurrent branches at the widest point.
Found the problem right away.

We follow a similar branching model. Master is kept clean. We do all
development on feature branches and merge when complete. History is fully
preserved. History is a mess but it works well overall.

~~~
reconbot
I would argue that you want to resolve conflicts in a rebase instead of a
merge. This allows you to see where the branches diverge and fix it right
away, closer to the offending commits, Preventing more work from piling up
around the conflict making it harder to piece what's going on.

~~~
sanderjd
It _can_ mean that you fix conflicts closer to the point where they first
happened, or it can mean that you have to fix the conflict in a bunch of
different ways as it propagates through each successive commit. I find myself
trying to outsmart the conflicts: "Ok, I know I changed such-and-such in such-
and-such a way here in a few commits, so if I fix this conflict like this,
then hopefully I won't have to fix that commit later..."

------
rsanheim
Interestingly enough, most folks working on GitHub.com don't use this model.
We actually use a simpler model, and usually merge to our feature branches
rather than rebase. I'm not sure if Zach's latest talk(s) goes into this level
of detail.

I think a big part of the reasoning is because we tend to push up branches
_really_ early to open PR's and get discussion going. And of course rebasing
public branches generally leads to hell.

I know some other .com devs will rebase privately before pushing a large
branch, but I would say 80% of work is just done with merging.

~~~
wting
I think it depends on how public and how many contributors you have to a
feature branch. I think author has the assumption that there is typically one
dev per feature branch.

Once a feature branch is being worked on by multiple devs (and hence multiple
feature branches forked off), it is a public branch and should use a merge
based workflow.[0]

I personally use a rebase workflow on private branches before merging since it
makes for a cleaner history. I've seen devs merge a branch with 100+ merge
commits and it absolutely destroys git history.

[0]: [http://lwn.net/Articles/328438/](http://lwn.net/Articles/328438/)

~~~
purephase
This is exact same workflow I use. If it's a feature branch that I'm working
on locally, then rebase -i is my friend as I can squash commits. But, I rarely
stay in a local branch for longer than a day or two for fear of losing work
and no developer is an island. The second it is shared, it's merge only.

Rebase conflicts always cause more grief than it's worth.

------
shawnps
We used a very similar model to this at my last job, and I'm struggling to get
my current team on board with this type of process. I _think_ the main problem
is that people don't trust continuously deploying master because there aren't
enough tests. In my ideal world, every commit is tested (with Jenkins, Travis,
Buildbot, etc), and then if the PR includes tests for the code and the build
passes, the reviewer says LGTM and the committer presses the merge button on
GitHub. Once the button is pushed, a build of master is triggered. If the
build passes, the code is automatically deployed.

~~~
wpietri
My world really changed once I started working with code bases that had
excellent test coverage from the get-go.

At my last shop we combined that with pair programming, feature switches, and
a few other tricks, and we basically never branched. You'd pull, work for a
few hours, push, and 10 minutes later your code would be live. It was in one
sense freeing: the release overhead of other shops was gone. And in another,
it inspired more discipline. Knowing that everything you were writing would
shortly be live kept you on your toes. You could never leave something for
later; there was no later. I loved it.

~~~
shawnps
That sounds really awesome!

I'm guessing I'll just have to sit down one day and write a whole bunch of
tests, and then hope that everyone else will see the benefit.

So you mean everyone just pushed directly to the upstream master?

~~~
wpietri
If I understand your question rightly, yes. Looking at the Github history, we
did actually have 6 branches over the life of the project. All were extended
technical experiments of one sort or another like trying out a new templating
approach. 2/6 were merged. But all normal coding was pushed to master with no
branching (beyond a local checkout and local commits, which are a sort of
branching, but none of those lasted longer than a day). There, any checkin
triggered tests, and any build that passed the test was pushed live.

If you want others to see the benefit, I'd encourage you to pick a specific
area of the code, test the hell out of it, and make sure that a) tests are
easy and quick to run on dev boxes, and b) every checkin is automatically
tested. I'd start small, and one good place is a chunk of important business
logic. It's even better if you use the tests to support refactoring and
general cleanup of an area people know is messy.

If you do this right, then people will have two experiences coding on the
project. In the tested code, it's pleasant and safe. In the messy code, it
feels dangerous and scary. Over time they may get it.

Note that this is really hard to get off the ground in an established company
and in an existing code base. So if they don't catch on, don't feel like it's
you. (I generally cheat by being the first person on greenfield projects, so
the first line of code written is a line of test code.) Also, if you get stuck
while trying to clean up legacy code to make it testable, Michael Feathers'
book "Working Effectively with Legacy Code" is very helpful.

Good luck, and feel free to drop me an email if you end up with more
questions.

~~~
shawnps
> If you want others to see the benefit, I'd encourage you to pick a specific
> area of the code, test the hell out of it, and make sure that a) tests are
> easy and quick to run on dev boxes, and b) every checkin is automatically
> tested. I'd start small, and one good place is a chunk of important business
> logic. It's even better if you use the tests to support refactoring and
> general cleanup of an area people know is messy.

Ah, this is really good advice, thanks. I'll give it a shot.

------
jessaustin
Truly, "rebase vs. every-commit-is-precious" is the "vi vs. emacs" moot
question of our time.

EDIT: haha, I just reminded myself of the "Every Sperm is Sacred" song from
_Meaning of Life_.

------
praptak
I would also add "commit often, squash later". I find frequent local commits
useful for quickly rolling back mistakes but they'd just clutter the main
history if they got there. Usually if a commit is important enough to end up
in master, it is also important enough to do the merge so most of my changes
are actually 1 commit (2 if you count the --no-ff merge.)

~~~
chmike
Learning git here. Could you please explain how rebase squashes commit ?
Looking at man git-rebase it seam that it detaches a branch and attaches it to
the current branch. From the documentation the chain of commits is preserved
and simply moved in the graph. The sequence of commit nodes of the branch are
not merged into one commit node.

~~~
Ygg2
If you use rebase interactive like this:

    
    
       git rebase -i HEAD~n 
    

Where n is number of commits from HEAD, you can do ANYTHING to your branch.
You can stop mid rebase to add some files that didn't exist before, squash,
fix, execute commands, etc.

You can even change order of commits and delete commits from history. BE VERY,
VERY CAREFUL!

[https://www.kernel.org/pub/software/scm/git/docs/git-
rebase....](https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html)
(See interactive mode and splitting commits).

------
barrkel
If you work with other people, this model doesn't work so well, IME.

In particular, rebasing is very hazard-prone if someone else may have checked
out your branch.

If you're working on a feature that needs changes in multiple components and
is broken without coordination, you may be working off the same branch, or
have separate branches with inter-merges. Either way, rebasing will cause
trouble.

~~~
DougWebb
_In particular, rebasing is very hazard-prone if someone else may have checked
out your branch._

That's why you _never_ rebase a published branch. This is easier to manage if
your team uses a central repository as the 'official' repository and everybody
pushes and pulls to that one. Then you know that your branches in your local
repository are not public, not published, and safe for history-altering
workflows like rebase. It's only the branches that you push that you're not
allowed to rebase, at least not prior to the last push.

If your team doesn't use a central repository, and you're pushing and pulling
between all of your local repositories, then I'd suggest using a naming
convention for branches to distinguish public ones from private ones. Eg:
start your private branch names with "DEV_". If someone else pulls a DEV_*
branch, then they should expect that its history might change and they'll have
to deal with that when it occurs.

~~~
valtron
> That's why you never rebase a published branch.

My problem with that is my coworkers and I usually work on our own feature
branch. Ideally I wouldn't push mine to the central repository until I'm done,
so I can rebase on master without changing the public history, _but_ at the
end of the day I don't like to leave code only on my computer (what if my hard
drive blows up??) so I push everything I don't want to lose.

~~~
jsaxton86
Git is designed so that branching is cheap. Why not create your own
development branch off of the feature branch? Then use the feature branch as
an integration-only branch?

------
caioariede
I never use rebase, but I don't see problems if your branch is _local_.

I would prevent rebasing after pushing the branch to remote.

Anyway this branching model doesn't looks so that simple.

------
programminggeek
I avoid rebase like the plague if I'm working on a team, and if I'm not
working on a team I don't see the need for it much either.

~~~
djbender
Rebase is good for when you need to rewrite or clean-up history. For example:
all those "WIP" commits you'll frequently see aren't exactly helpful. If you
want to rewrite history of a branch that others are actively working on, well
then you're going to have A Bad Time™.

------
Frostbeard
In my team we do something superficially similar, but instead of rebasing we
just merge changes from master into our feature branches whenever master is
updated. This seems to result in fewer conflicts for us, despite what you
might expect.

Also, when the feature branch is to be merged into master we do a squashed
commit so that all changes from that branch show up as one commit in the main
project history. The feature branch's commit history is preserved in the
repository (thought not in the master branch), so it's not really any more
difficult to roll back partial changes.

Our situation is likely different from many projects though, as we only ever
have one developer working in a given feature branch.

~~~
reledi
> The feature branch's commit history is preserved in the repository (thought
> not in the master branch)

This would require you not to get rid of the branches (remotely and locally),
right? GitHub does allow you to undo the deletion of a branch, but is that
only for a certain time period?

I like to delete my branches as soon as they've been merged in.

~~~
Frostbeard
We leave the feature branch on the remote repo indefinitely, but we really
don't need to do so. The diff between the feature branch's squashed commit and
the previous commit of the project usually tells us everything we need to know
when a problem crops up. We keep the feature branches "just in case", but in
practice they're never used once the branch has been merged into production.

------
dexen
FWIW, this branching model works for me in a small-ish team, two years now and
counting. The part about `good merge bubbles' is especially important for
clean history.

------
jpiasetz
Do anyone know how that branch image was created? I've been wanting to do
something similar.

------
dreamdu5t
You can use tags to present a clean history of features added or releases,
while still preserving the actual history of commits... Using rebase to clean-
up (destroy) your history is an amateur solution to having a proper
branching/tagging workflow.

------
potomak
I suggest also reading "GitHub Flow"[1] by Scott Chacon about this topic.

[1] [http://scottchacon.com/2011/08/31/github-
flow.html](http://scottchacon.com/2011/08/31/github-flow.html)

------
Systemic33
I get an error loading the page, can anyone mirror? "The page isn't
redirecting properly"

EDIT: I resolved it by going to github.com and signin, and then click link.
Shouldn't one be able to look at gists without logging in?

~~~
gizzlon
works for me now

------
nvarsj
If you're looking for an automated tool to do this, take a look at gerrit. I
used it successfully at my last day job. It basically enforces this model. The
quality of our commit history changed quite dramatically.

------
eknkc
In a similar model, I just commit hotfixes on the master branch. What is the
negative implication of this? If I had a branch for them, those would just be
merged back immediately with one commit anyway.

~~~
_prometheus
No rule is sacred, and your mileage will vary. For me, having a pull-request
for the hotfix helps us run continuous integration tests, code-review, and
ensure relevant people get notified automatically of the fix.

------
funkaster
I agree with most of what is suggested here, except forking. I think that even
for small teams forks are the way to go: you get a cleaner upstream, plus you
get a backup of your local repo.

------
koobe
This feels like the working with SVN/P4 again.

Main difference here is having your work in progress visible to others in a
feature branch. Also rebase -i being less of a pain than svn update.

------
tlo
What if you pushed your feature branch and then need to fix something in that
branch later? How do you handle this case as you shouldn't rebase a pushed
branch?

~~~
reledi
It's fine to force push to a remote branch if it's a personal branch, that is,
no one else is working on it but you.

(Or it's fine if you've previously discussed with your team the implications
of force pushing to shared branches, and they're okay with that because you
all know what you're doing.)

------
calinet6
This is exactly how you do git. Sanity. Thank you.

~~~
coherentpony
Maybe it's just one point of view, rather than a clear-cut, ' _this_ is how
you do git.'

For example, my point of view is that master should never contain development
work. master should always be _stable_. In this case, the post here does not
jive with that point of view.

------
allr
We use the exact same model but we have a dev branch for our staging server,
thanks for writing it down!

------
the1
do you rebase before accepting pull request or before publishing your feature
branch?

~~~
_prometheus
Depends on how you want to do it. I'd rebase on top of master before
publishing, _and_ before merging it in (accepting PR).

Definitely be comfortable with rebase before you try this though.

