A successful Git branching model
In this post I present the development model that I’ve introduced for all of my projects (both at work and private) about a year ago, and which has turned out to be very successful. I’ve been meaning to write about it for a while now, but I’ve never really found the time to do so thoroughly, until now. I won’t talk about any of the projects’ details, merely about the branching strategy and release management.
It focuses around Git as the tool for the versioning of all of our source code.
Why git?
For a thorough discussion on the pros and cons of Git compared to centralized source code control systems, see the web. There are plenty of flame wars going on there. As a developer, I prefer Git above all other tools around today. Git really changed the way developers think of merging and branching. From the classic CVS/Subversion world I came from, merging/branching has always been considered a bit scary (“beware of merge conflicts, they bite you!”) and something you only do every once in a while.
But with Git, these actions are extremely cheap and simple, and they are considered one of the core parts of your daily workflow, really. For example, in CVS/Subversion books, branching and merging is first discussed in the later chapters (for advanced users), while in every Git book, it’s already covered in chapter 3 (basics).
As a consequence of its simplicity and repetitive nature, branching and merging are no longer something to be afraid of. Version control tools are supposed to assist in branching/merging more than anything else.
Enough about the tools, let’s head onto the development model. The model that I’m going to present here is essentially no more than a set of procedures that every team member has to follow in order to come to a managed software development process.
Decentralized but centralized
The repository setup that we use and that works well with this
branching model, is that with a central “truth” repo. Note that this
repo is only considered to be the central one (since
Git is a DVCS, there is no such thing as a central repo at a technical
level). We will refer to this repo as origin
, since this name is familiar to all Git users.
Each developer pulls and pushes to origin. But besides the
centralized push-pull relationships, each developer may also pull
changes from other peers to form sub teams. For example, this might be
useful to work together with two or more developers on a big new
feature, before pushing the work in progress to origin
prematurely. In the figure above, there are subteams of Alice and Bob, Alice and David, and Clair and David.
Technically, this means nothing more than that Alice has defined a Git remote, named bob
, pointing to Bob’s repository, and vice versa.
The main branches
At the core, the development model is greatly inspired by existing models out there. The central repo holds two main branches with an infinite lifetime:
master
develop
The master
branch at origin
should be familiar to every Git user. Parallel to the master
branch, another branch exists called develop
.
We consider origin/master
to be the main branch where the source code of HEAD
always reflects a production-ready state.
We consider origin/develop
to be the main branch where the source code of HEAD
always reflects a state with the latest delivered development changes
for the next release. Some would call this the “integration branch”.
This is where any automatic nightly builds are built from.
When the source code in the develop
branch reaches a stable point and is ready to be released, all of the changes should be merged back into master
somehow and then tagged with a release number. How this is done in detail will be discussed further on.
Therefore, each time when changes are merged back into master
, this is a new production release by definition. We
tend to be very strict at this, so that theoretically, we could use a
Git hook script to automatically build and roll-out our software to our
production servers everytime there was a commit on master
.
Supporting branches
Next to the main branches master
and develop
,
our development model uses a variety of supporting branches to aid
parallel development between team members, ease tracking of features,
prepare for production releases and to assist in quickly fixing live
production problems. Unlike the main branches, these branches always
have a limited life time, since they will be removed eventually.
The different types of branches we may use are:
- Feature branches
- Release branches
- Hotfix branches
Each of these branches have a specific purpose and are bound to strict rules as to which branches may be their originating branch and which branches must be their merge targets. We will walk through them in a minute.
By no means are these branches “special” from a technical perspective. The branch types are categorized by how we use them. They are of course plain old Git branches.
Feature branches
May branch off from:
develop
Must merge back into: develop
Branch naming convention: anything except master
, develop
, release-*
, or hotfix-*
Feature branches (or sometimes called topic branches) are used to
develop new features for the upcoming or a distant future release. When
starting development of a feature, the target release in which this
feature will be incorporated may well be unknown at that point. The
essence of a feature branch is that it exists as long as the feature is
in development, but will eventually be merged back into develop
(to definitely add the new feature to the upcoming release) or discarded (in case of a disappointing experiment).
Feature branches typically exist in developer repos only, not in origin
.
Creating a feature branch
When starting work on a new feature, branch off from the develop
branch.
$ git checkout -b myfeature develop Switched to a new branch "myfeature"
Incorporating a finished feature on develop
Finished features may be merged into the develop
branch definitely add them to the upcoming release:
$ git checkout develop Switched to branch 'develop' $ git merge --no-ff myfeature Updating ea1b82a..05e9557 (Summary of changes) $ git branch -d myfeature Deleted branch myfeature (was 05e9557). $ git push origin develop
The --no-ff
flag causes the merge to always create a new
commit object, even if the merge could be performed with a
fast-forward. This avoids losing information about the historical
existence of a feature branch and groups together all commits that
together added the feature. Compare:
In the latter case, it is impossible to see from the Git history
which of the commit objects together have implemented a feature—you
would have to manually read all the log messages. Reverting a whole
feature (i.e. a group of commits), is a true headache in the latter
situation, whereas it is easily done if the --no-ff
flag was used.
Yes, it will create a few more (empty) commit objects, but the gain is much bigger that that cost.
Unfortunately, I have not found a way to make --no-ff
the default behaviour of git merge
yet, but it really should be.
Release branches
May branch off from: develop
Must merge back into: develop
and master
Branch naming convention: release-*
Release branches support preparation of a new production
release. They allow for last-minute dotting of i’s and crossing
t’s. Furthermore, they allow for minor bug fixes and preparing meta-data
for a release (version number, build dates, etc.). By doing all of this
work on a release branch, the develop
branch is cleared to receive features for the next big release.
The key moment to branch off a new release branch from develop
is when develop (almost) reflects the desired state of the new
release. At least all features that are targeted for the
release-to-be-built must be merged in to develop
at this
point in time. All features targeted at future releases may not—they
must wait until after the release branch is branched off.
It is exactly at the start of a release branch that the upcoming
release gets assigned a version number—not any earlier. Up until that
moment, the develop
branch reflected changes for the “next
release”, but it is unclear whether that “next release” will eventually
become 0.3 or 1.0, until the release branch is started. That decision is
made on the start of the release branch and is carried out by the
project’s rules on version number bumping.
Creating a release branch
Release branches are created from the develop
branch. For example, say version 1.1.5 is the current production release and we have a big release coming up. The state of develop
is ready for the “next release” and we have decided that this will
become version 1.2 (rather than 1.1.6 or 2.0). So we branch off and give
the release branch a name reflecting the new version number:
$ git checkout -b release-1.2 develop Switched to a new branch "release-1.2" $ ./bump-version.sh 1.2 Files modified successfully, version bumped to 1.2. $ git commit -a -m "Bumped version number to 1.2" [release-1.2 74d9424] Bumped version number to 1.2 1 files changed, 1 insertions(+), 1 deletions(-)
After creating a new branch and switching to it, we bump the version number. Here, bump-version.sh
is a fictional shell script that changes some files in the
working copy to reflect the new version. (This can of course be a manual
change—the point being that some files change.) Then, the bumped version number is committed.
This new branch may exist there for a while, until the release may be
rolled out definitely. During that time, bug fixes may be applied in
this branch (rather than on the develop
branch). Adding large new features here is strictly prohibited. They must be merged into develop
, and therefore, wait for the next big release.
Finishing a release branch
When the state of the release branch is ready to become a real
release, some actions need to be carried out. First, the release branch
is merged into master
(since every commit on master
is a new release by definition, remember). Next, that commit on master
must be tagged for easy future reference to this historical version.
Finally, the changes made on the release branch need to be merged back
into develop
, so that future releases also contain these bug fixes.
The first two steps in Git:
$ git checkout master Switched to branch 'master' $ git merge --no-ff release-1.2 Merge made by recursive. (Summary of changes) $ git tag -a 1.2
The release is now done, and tagged for future reference.
Edit: You might as well want to use the -s
or -u <key>
flags to sign your tag cryptographically.
To keep the changes made in the release branch, we need to merge those back into develop
, though. In Git:
$ git checkout develop Switched to branch 'develop' $ git merge --no-ff release-1.2 Merge made by recursive. (Summary of changes)
This step may well lead to a merge conflict (probably even, since we have changed the version number). If so, fix it and commit.
Now we are really done and the release branch may be removed, since we don’t need it anymore:
$ git branch -d release-1.2 Deleted branch release-1.2 (was ff452fe).
Hotfix branches
May branch off from:
master
Must merge back into: develop
and master
Branch naming convention: hotfix-*
Hotfix branches are very much like release branches in that they are also meant to prepare for a new production release, albeit unplanned. They arise from the necessity to act immediately upon an undesired state of a live production version. When a critical bug in a production version must be resolved immediately, a hotfix branch may be branched off from the corresponding tag on the master branch that marks the production version.
The essence is that work of team members (on the develop
branch) can continue, while another person is preparing a quick production fix.
Creating the hotfix branch
Hotfix branches are created from the master
branch.
For example, say version 1.2 is the current production release running
live and causing troubles due to a severe bug. But changes on develop
are yet unstable. We may then branch off a hotfix branch and start fixing the problem:
$ git checkout -b hotfix-1.2.1 master Switched to a new branch "hotfix-1.2.1" $ ./bump-version.sh 1.2.1 Files modified successfully, version bumped to 1.2.1. $ git commit -a -m "Bumped version number to 1.2.1" [hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1 1 files changed, 1 insertions(+), 1 deletions(-)
Don’t forget to bump the version number after branching off!
Then, fix the bug and commit the fix in one or more separate commits.
$ git commit -m "Fixed severe production problem" [hotfix-1.2.1 abbe5d6] Fixed severe production problem 5 files changed, 32 insertions(+), 17 deletions(-)
Finishing a hotfix branch
When finished, the bugfix needs to be merged back into master
, but also needs to be merged back into develop
,
in order to safeguard that the bugfix is included in the next
release as well. This is completely similar to how release branches are
finished.
First, update master
and tag the release.
$ git checkout master Switched to branch 'master' $ git merge --no-ff hotfix-1.2.1 Merge made by recursive. (Summary of changes) $ git tag -a 1.2.1
Edit: You might as well want to use the -s
or -u <key>
flags to sign your tag cryptographically.
Next, include the bugfix in develop
, too:
$ git checkout develop Switched to branch 'develop' $ git merge --no-ff hotfix-1.2.1 Merge made by recursive. (Summary of changes)
The one exception to the rule here is that, when a release branch currently exists, the hotfix changes need to be merged into that release branch, instead of develop
. Back-merging the bugfix into the release branch will eventually result in the bugfix being merged into develop
too, when the release branch is finished. (If work in develop
immediately requires this bugfix and cannot wait for the release branch to be finished, you may safely merge the bugfix into develop
now already as well.)
Finally, remove the temporary branch:
$ git branch -d hotfix-1.2.1 Deleted branch hotfix-1.2.1 (was abbe5d6).
Summary
While there is nothing really shocking new to this branching model, the “big picture” figure that this post began with has turned out to be tremendously useful in our projects. It forms an elegant mental model that is easy to comprehend and allows team members to develop a shared understanding of the branching and releasing processes.
A high-quality PDF version of the figure is provided here. Go ahead and hang it on the wall for quick reference at any time.
Update: And for anyone who requested it: here’s the gitflow-model.src.key of the main diagram image (Apple Keynote).
![]() |
Git-branching-model.pdf |
Feel free to add your comments!
Excellent post to work with a team on git.
Thanks for sharing these ideas…let’s go to Twitt it.
Can u tell me what’s the software are u using for creating theses images?
Thanks again
@fefal: Thank you for your comment. The images were created using Apple’s Keynote. (Check the line styles.)
Hopefully you can use this model to your advantage.
Very interesting article.
About using –no-ff, you could configure it by default on your master and develop branches by adding this to ~/.gitconfig:
[branch "master"]
mergeoptions = –no-ff
[branch "develop"]
mergeoptions = –no-ff
see http://www.kernel.org/pub/software/scm/git/docs/git-config.html
@Jeff: Interesting remark. That would be a great addition to the branching model, since those rules only apply for develop and master.
However, it would also affect the merges that are performed by pulling in upstream changes from the origin repo and I think most likely, you would like those to be fast-forwarded. Otherwise, your commit tree explodes with branches that effectively carry no interesting information.
Summarized, you would want
git checkout develop; git merge myfeature
to be –no-ff’ed, but:
git checkout develop; git pull
to be –ff’ed.
I think it’s just too much to ask this of git.
@vincent, you’re right, on the same branch sometimes you want to fast-forward, sometimes you don’t.
After thinking about it, I agree that –no-ff should be default and -ff should be explicit. It’d make sense to have the default preserve history rather than destroy it.
But Git can be used in so many different ways that no default setting will satisfy everybody :)
This is fantastic, very well thought out. Thank you!
Great posting, thank you so much for creating this. My team is working with git branches, deployment tactics, and we’re having similar discussions about how to proceed. Your posting is valuable to me and I’m happy to donate money to you or to a charity of your choice– feel free to contact me using my full name @ gmail.com
Perhaps there should be a ff default option for pull. Then you could have the default –no-ff for merging.
Lovely, thanks!
This is great. I’m only in git-svn or github these days, so I don’t use it anymore, but I wrote a commit hook to enforce master (we renamed it to stable) only moving via no-ffs:
http://github.com/stephenh/git-central/blob/master/server/update-stable
Great article. I found some errors you may want to fix. In some places you use “were” (form of the verb ‘to be’) rather than “where”. Other one: loosing->losing. Still, great article, I didn’t really understand the multiple branch workflow before reading this.
Also, starting at “Creating a feature branch” you create branch ‘myfeature’ and then start using ‘somefeature’ … did you mean to myfeature instead?
Great post! It was very helpful that you explained the whole process.
I was sure that somebody would have asked which software was used to create the images!
Thanks, the article is great!
Your big picture is excellent and it’s exactly what we do in our company!
The only difference is that we use ClearCase and the built-in version tree function shows us this exact picture based on the checkins and branches contained in the ClearCase VOB. It’s even interactive in the GUI to let you select versions for diffs & merges. For us, the mental model and the ClearCase reality is one and the same. Hooray! Of course, ClearCase is not decentralised/distributed like Git, so it has it’s own problems too :-)
Generating this kind of version tree diagram should be standard behaviour for all version control systems alike (git, hg, svn, cvs, fossil, etc). It’s one of the key reasons why I find it hard to adjust to using these other tools.
Nice try, but I don’t see why the proliferation of branches is a good thing. Have you ever worked on a large project? Every branch increases the complexity of the project and the probability of a merge conflict. Merge conflicts are just as nasty and ugly in GIT as they are in SVN ( see http://bit.ly/17XoL )
Really good explanation of a model that works, thanks.
Not sure what software you’re releasing, but I’m wondering how you would handle hotfixing a previous release that you still had to support? i.e. you’ve just released 2.0 but have to hotfix 1.0 for a customer, where does the hotfix-1.0.1 branch get merged into and ultimately tagged for release?
Hi, great writeup. I employ a very similar model with my development team, except we don’t merge branches to develop (called next_master in our case), but use git rebase -i to squash the branch into one or a few commits and then merge it into develop after rebasing. This guarantees that all merges are fast-forwards and our git log is clean of those annoying merge-commits.
Is there a reason you decided against using rebase? In my experience regular rebasing of topic/feature branches helps a lot in the long run.
@Rory: That’s an excellent follow-up question. To be honest, I haven’t thought about that scenario consciously. (The software I’m releasing is mainly infrastructure tools that we use internally.)
But say you have the following situation:
1.0
,1.1
and2.0
.My solution to that would be the following:
support-1.x
, based on tag1.1
(since that is the latest 1.x commit). This branch should be long-lived and can be safely removed if you drop support on 1.x.hotfix-1.1.1
, based onsupport-1.x
hotfix-2.0.1
, based on2.0
Then, finish
hotfix-1.1.1
by merging back intosupport-1.x
(don’t forget--no-ff
), so not into master or develop. Technically you could just merge back those changes intodevelop
, but the commit graph would quickly become like a plate of spaghetti. Rather leave these situations togit cherry-pick
(personal taste).You can finish
hotfix-2.0.1
as you would regularly (merge back intomaster
ordevelop
). Merging the fix into develop causes the bug be fixed in all future releases.Effectively, what you’re doing then, is having a master branch per supported product release.
Maybe I’m forgetting something, haven’t thought about it too long yet. Very interesting addition to the article!
Thank you for sharing you way of work with git. I wonder why when you make some fixes to release branch you don’t merge them simultaneously to the “develop” branch? Release branch can have some long time to live (for example week or two) and all that time there will be no bug fix in develop branch?
@Dmitry: Maybe I haven’t mentioned that one explicitly in the article, but in fact, we do. This is also visible in the big picture diagram, where I’ve annotated exactly that with “Bugfixes from rel. branch may be continuously merged back into develop”. You can merge back release branch commits to
develop
as often as you like.@Mutwin: I have no objections to rebasing feature branches. It’s just personal taste: I don’t like huge commits that affect lots of files. There is nothing wrong with squashing feature branches into develop if that’s your favourite way of merging. However, I would advise against rebasing/squashing anything other than feature branches.
@0x4a6f4672,
Merge conflicts do happen, yes. SVN tries to force you to work in a way that minimises branching; pretending that that it helps in avoiding conflicts.
That’s just wrong. Branches are a natural part of development. Every checkout with any changes at all is in essence a branch, even though SVN doesn’t call them so. When you commit, your changes need to be merged to the central repository.
The thing is, sometimes you have code that you need to work on, but which you can’t commit because it’s not ready yet, so you need a real, named branch.
With Git, you can track origin (or anything you want, really) and ensure your experimental changes do not conflict with anything, without having to “commit” anything to the public repository. Git is based on the assumption that branching and *merging* happens all the time (as it does), and is built to help you.
Git is much smarter about merges because it knows at all times what needs to be merged. Furthermore, since committing in Git is cheap, fast and (locally) undoable, you can split your work into smaller, independent changes, making merge conflicts much easier to resolve.
It’s also much easier to coordinate changes with other developers because you don’t need a branch on the “central” repository to send your code back and forth. Also keep in mind that history is global accross all clones, so when one of you eventually merges with origin and pushes the changes, the other can pull without having to worry about merging at all. The merge commit is fetched along the other changes, and it just works.
@Vincent
Nice workflow what you exposed here. An script that simplifies the commands back and forth the scenarios will be amazing (thinking on writing this right now)
as for @Jeff comment about mergeoptions and pull, you can setup “git up” which is similar to svn but perform the pull operation doing a rebase, so your locally commits are lifted up and then applied back once the pull has completed:
alias.up=pull –rebase origin
That is something I use when commit locally to avoid recursive merges when pushing to origin.
Again, this workflow for version based release deployment is excellent, and really take advantage of Git features.
Cheers!
you can use mergeoptions for master and develop, and
I think one of the advantages of git is that models like this are fairly painless. Your strategy seems fairly complicated, but may be a great fit for your products.
One observation, though, is that regardless of the complexity of your workflow, I think it’s exceedingly important to script that workflow. Instead of executing a series of git commands to perform a hot-fix, for example, you can encapsulate that work into a single script. Even when the steps are obvious, it can really reduce the cognitive overhead of performing the work, and greatly reduces the chance of doing the wrong thing.
Gotta try this approach. Simplified (i dont need such complexity), but still.
This is exactly how software should be built. Amazingly only git really makes this possible. Thank you for developing such excellent charts and examples. I’m printing the PDF out now.
@Luis:
Script support is something that I have not dared to start withI have started an initial outline of what those scripts would need to become at Github yesterday. At the moment, the shared mental model of our developers has been more important.Furthermore, your idea on the ‘up’ alias is very interesting. And if you only have a (local)
develop
branch that diverged fromorigin/develop
, that kind of rebasing works just fine. But what if you would have, say, some feature branches that are based on a commit ondevelop
that was (not yet) onorigin/develop
?This
would then become
In other words, those feature branches are not rebased along with the new
develop
. Understanding this while actively using the model raises complexity significantly. Better to avoid it than to shoot yourself in the foot.@brian doll: I also encourage you to create such supporting scripts. In order to “coordinate” such undertaking, I’ve added an empty Github repo for everybody to fork. Please feel free to cooperate. Of course, this repo has the branch layout as detailed in the article.
Right now, the repo is almost empty yet, only some minor guidelines for what I think could be usable.
Feel free to join!
For anyone that wants to help with the supporting scripts, please fork the Github repo:
http://github.com/nvie/gitflow
Awesome diagram — it really helped your points come across. A picture truly is a thousand words :).
Great article, good patterns. How long on average are your release cycles? I wonder how this models would work in an environment that pushes to production multiple times per day and has the desire to pick and choose which feature branches go to production with each push.
Interesting post, thank you! I started using Git one month ago, I’m a designer so I need a guide to this language, and your diagram help me a lot :D
Fantastic article – just what I needed to get my head around this.
@joem: If your release cycles are that short, this model will be a bit overkill. However, it is not hard to think of a less formal model with, for example, no release branches. In that scenario, you can merge “stable” states from
develop
intomaster
directly and havemaster
auto-publish its state.Great article. I still have a question: do you know SVN, did you tryed to apply this process with SVN ? Do you think that Git is a requirement to apply this process ?
@Gabriel: I know Subversion pretty well (used to be a Subversion fan before I knew Git). Nevertheless, I’ve never come to such a smooth model for release management under Subversion. But you should consider that this model leans heavily on branching/merging, which is the main reason to switch from Subversion to Git anyway.
Although I’m not going to say that it can’t be done, I think you must brace yourself if you are going to try it.
Excellent article!
We tend to do the opposite of your approach. I suspect that our projects and your products have a different life cycle. We rebase feature branches onto our development branch and then leave those branches intact. This becomes a stack of feature branches that are ready for the next release.
Couple questions come to mind from you workflow?
1. Do most of your feature branches receive code from more than one team member? If not, do you simply use some other backup strategy to make sure code is not lost on system failure?
2. Do you have a special technique for visualizing your history? We use gitx and git log. I enjoy the swim lanes in your diagrams and I am wondering if you have a history viewing approach that automatically presents your history in those swim lanes. Master is always on the right. Develop is in the middle, etc.
Really great article. I think this is a really great resource to help new-comers to conceptualise the power and usefulness of good branch management..
Thanks for the great concepts and writeup.
My very minor quibble would be in assigning the semantic meaning ‘master’ == ‘current production,’ since ‘master’ exists in pretty much every Git repo by default. That is, since it’s always there unless you take definite action, committing to it doesn’t unequivocally mean anything except by convention.
I’d argue a stronger convention would be to have a branch called ‘production’ or ‘live’ or such taking the place of ‘master’ in your diagram. Then committing to that branch would have a stronger sense of definite action, which I think is what you’re rightly after.
Great article.
I understand that not pushing your feature branches to the origin saves you some maintenance tasks after they are merged onto the development branch if you pushing them would give you a free backup.
And how do you update/merge/checkot your production code?
If you tag it with v2.0 how would you update the code in the live server? Is that a checkout of the release-2.0 branche? or is it an checkou of the tag v2.0 (is this possible)?
@primeminister: That would be a checkout of the 2.0 tag, since the release branch should be destroyed after it is merged in master. (Release branches are not long-lived.)
figures… I should read on tags and how to deploy those. Thanks for the article!
I’m getting too old for this business. Kids, branching hasn’t been a real problem in software development for a long time now. Vincent’s diagram (which is lovely, btw) illustrates a branching strategy that was in use long before git, hg, bzr or darcs ever showed up. I’m surprised that no one else has mentioned this. On the contrary, people are jumping out of their shoes to pat Vincent on the back for “showing the way”. With one of the most touted benefits of git (and DVCS es in general) being that it “makes branching really easy”, you’d think more of its adopters would already know how to put those branches to good use. Meh.
Awesome. One question though: how do you keep track of your databases? Do you use SQLite and version it too, or do you use MySQL and always migrate when switching branches?
I like neither approach :|, and that is why I currently don’t use git branches at all…
Hi Jonas,
In the past I’ve managed quite a few MySQL databases and have always used version control systems to track the contents of the database. You do not necessarily have to use SQLite to achieve that. In fact, if you dump the contents of your database into a file and bring that file under version control, then you are safe. For MySQL, you can do:
to dump the actual contents to the file, and
to restore the database again.
The SQL file is textual (one line per record), which allows for easy diff'ing and merging and allows your database schema to change from branch to branch. But since you can easily regenerate your database, you'll have no problems dealing with this.
For extra ease, create Makefile targets
dump
andrestore
for exactly that (if you use make).Cheers,
Vincent
Very interesting. I’ve never used Git before, but when the time arrives, I’ll try to follow this model.
For those still using SVN for branch-based development, you may find very useful to follow the UQDS (Ultimate Quality Development System) methodology[1], which relies on Combinator[2], a Python script by Divmod.
It helps to make it easier to branch from and merge back to trunk (trunk being always an stable/production/master copy).
[1] http://divmod.org/trac/wiki/UltimateQualityDevelopmentSystem
[2] http://divmod.org/trac/wiki/DivmodCombinator
Very nice article and it really shows how gits easy branching and merging can make the development process run a bit smoother.
Admittely, I’m still an SVN user because I am still struggling to understand the principles of a DVCS. I am a lone developer (although I am trying to get a few colleagues involved with some coding) but without a central repo I worry about working on a feature branch that gets lost when my PC goes titsup. What features are available in git for backing up local branches in case of system failure?
@Dave: I would have to disagree on that this branching model has been in use in other-than-distributed VCS’s. While true, maybe, for the release and hotfix branches, this is far from reality for the feature branches as far as I’ve ever seen it.
Where Git really shines (compared to non-distributed systems) is that is makes merging so easy (there we have it again :) !) that it changes the behavioral patterns of its users: short-lived feature branches suddenly become a common pattern. Of course, theoretically, that could as well be done in CVS/Subversion. In practice, however, I think you must be nuts to try it.
Edit: or you must be using a tool like DivModCombinator, see previous comment by Julián.
But even for the releases and hotfixes, this model may be different. Trying to merge back, say, a hotfix into develop, is something that many traditional VCS users would rather do with manual diff’ing/patching than to trust their tool in doing it for them, since most of them lack merge tracking. With Git, you get all of this goodness for free.
It’s not the users that are incompetent, it’s the tools.
With my model, I never pretended to have created something entirely new. Instead, I tried to summarize our approach (which bundles existing practices together) simply because it works well in practice. On top of that, the diagram with the swim lanes was deliberately drawn so to visually clarify the workflow, making it attractive and easy to reference to, and to create a shared understanding among team members.
Apparently, judging from the comments, this way of looking at it is well-appreciated.
This is a great concise write-up, and the diagram is fabulous.
I won’t go as far as Dave Wolfe has, but I do think it’s important not to re-invent the wheel. Git and other DVCS’s make branching much easier, but there’s also decades of experience with these sorts of branching strategies. For example, Streamed Lines (http://www.cmcrossroads.com/bradapp/acme/branching/) talks *at length* about dozens of approaches to maintaining parallel development streams, complete with patterns and criteria for choosing among them.
This is by far the best git blog entry I have seen so far (in let’s say about two years). I have printed out the diagram (PDF) and it will be on my desk until I use the system by heart. Thanks!
@Martin: Backup features for Git are no different than you would have on your traditional VCS. Just setup a Git repo on a remote machine and use that as the “truth” repo, just like you would with Subversion. Use pull and push to communicate changes to that repo. It’s really that simple.
Awesome awesome awesome post!!
I’ve been looking for articles/documents that could help convince management and the rest of my team to switch over to git (or at least consider it). This is definitely one great document/article towards that goal.
You should include a footnote about the support branch strategy. The issue does arise in practice and its a subtle but useful addition to a great article.
Nice article! However I was wondering about the lifetime of the release branches. You delete them relatively quickly. What happens if you have a release in the field and you need a fix for that? I am not talking about a production hotfix but rather a bug fix for a customer that is using a release.
@Joe: Actually, by “production release”, I mean every build that is “out in the wild”. So every customer has a production release in that terminology. (They may not have the latest one, though.)
For supporting fixes on any production release from the past, please refer to this comment. gitflow will be supporting this in the future.
Thanks. I missed that previous comment and response ;)
Acutally I think a more classical way of supporting the “in the wild” releases is to keep the release branch (instead of deleting after it is merged back to develop). You would have (for example) release 1.2.x on one release branch with subsequent releases 1.2.1, 1.2.2, etc. delivered from this branch and with bug fixes merged back to the develop branch. You would delete the release branch when you stop supporting a release (but this is optional (you may want to keep the branch alive even if is dormant).
I’ve come over to Git from Bazaar, as the company have decided to use Git over SVN for all new projects, and i’ve borrowed a fairly common feature use from Bazaar – aliases for common functions.
For instance, i have “git a” be “git add -A”, which is my most common action when i want to update my index.
I think that this also applies to your merge ff/no-ff problem, you alias “git m” to “git merge –no-ff” and then feature merges can use the short version, while other merges/pulls can use the normal functionality.
I also agree with one of the above posters about re-purposing master as your production branch – as master is the default branch you’d get if you clone the repository, giving it a meaning might open you up to people accidentally messing up the production release history. We’ve decided to use your model, but have “develop” be the master branch, and your “master” we’re calling “final” (after some discussion over what to call it we gave up and decided final was good enough)
@Glen: Fair enough. My main reasoning for naming it the branch “master” is that if you check out that branch, you would get the latest stable release automatically. Git’s model never gives others write-access to your own repo. You rather pull from people when they have changes ready, so the only one who can screw up your master is yourself.
If you would like to use the
git-flow
tool, you can easily set up your custom branch naming as follows:I use the following to default the –no-ff behaviour in my ~/.gitconfig
[alias]
merge = merge –no-ff
How many git repos does your application span? Do you have any suggestions for working with multiple repos, in an environment with overlapping release branches? That is, where you may have more than one release in development or QA at a time?
Further to Dave Wolfe’s and Ned Batchelder’s comments, I would also agree that this kind of branching structure is not new per se.
For more branching strategies, and some nice visuals as well, refer to the Microsoft Team Foundation Server Branching Guidance ( http://www.codeplex.com/BranchingGuidance ). The guidance there is not limited to TFS.
In any case, I think Vincent’s diagram is an incredibly good communication tool, and the concise integration steps with git are the first I’ve seen of their kind. They have helped me to adopt this workflow (which I have been using with TFS) to my git repositories.
Hi Vincent,
I think this write up is very interesting as we are currently thinking about moving our main source code repository over to git (from subversion).
One question: I was wondering why after you’ve finished a release branch, and you are tagging it on master, you only create a lightweight tag (i.e. without the -a or -s flags). I’m no Git expert, but from reading stuff like the section on gitready.com about tagging (http://www.gitready.com/beginner/2009/02/03/tagging.html), I got the impression that the tag command is another that does the wrong thing by default. To quote:
> Without arguments, git tag creates a “lightweight” tag that is basically a branch that never moves. Lightweight tags are still useful though, perhaps for marking a known good (or bad) version, or a bunch of commits you may need to use in the future. Nevertheless, you probably don’t want to push these kinds of tags.
@Sam: You are absolutely right on that one. I’ve immediately edited the places in the article that mention
git tag
. Thanks for the note on that one.For the ones interested in
git-flow
: it will receive support for this kind of tagging before the 0.2 release, promised!Excellent article!
This is exactly what I was looking for. I have read several articles and books on GIT and understand the concepts, to a degree, but most fell short of a complete picture. They lacked the visualizations that you have included in your article here.
I look forward to you incorporating the comment to Rory’s question about hot-fixing a previous release as well as your progress on git-flow.
Thank you for this excellent piece of information.
$ git checkout master
Switched to branch ‘master’
$ git merge –no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2
I believe “git tag -a 1.2″ go before “git checkout master” makes more sense because it tags the current release branch that you finished. This way after you do the merge, you can push the tag onto the repository without needing to do an extra push step. The revise process:
$ git tag -a 1.2
$ git checkout master
$ git merge –no-ff release-1.2
(you can do a push to the repo)
$git push repo
(And you can see the list of tag available to checkout)
$git tag -l
(To checkout a tag “version”, this will create a (no branch) branch which you have to create a branch for)
$git checkout 1.2
$git branch -b v1.2
Thank you for publishing this. I will definitely be using this in future projects.
First of all, thanks for a great article!
One question: Let’s say I finished some feature, I merged my feature-branch into develop and pushed develop. Then few month later our marketing department decided that we don’t want this feature in the upcoming release. What should I do in this case? Remove it from develop applying a reverse patch?
Thanks in advance.
Thanks for posting this useful model. It works well in theory, and so far for me at least, has also been working well in practice.
After having the poster pdf up on my wall for a few weeks, and referring to it every so often, I can’t help but think the order of the columns could be reversed. The current order is feature, dev, release, hotfix, master. This left-to-right flow is how we work; first creating features, and finally shipping when the code hits the master. However, when arranged like this, it conjures up images of code finally, as it’s last gasp, making it into the master.
When I reference the diagram, it is usually at the end of a long feature, and it is time to move those changes over a few columns. The thought process goes something like, “Ok, feature complete. Time to ship! Now, were is the master on this diagram… Ah! There it is. Now, lets walk backwards. I see, I need a release branch, oh, but the changes have to be in dev first…” In other words, when I look at the diagram, master is the “home row” and the starting point.
If the column order was reversed (master on the left, features on the right), then the focus is brought back on the master (which is what everyone other than the developer cares about) and the story is more about how changes are made and brought back into the base line.
Just an idea. :-)
Thanks again,
Jonathan Wright.
Thank you for contributing this article.
It would be very helpful if you would publish a git-flow version of your diagram that would label the appropriate arrows with the appropriate git-flow commands.
@Steve: funny that you mention it—I have been planning to do exactly this in a follow-up post, among some more thoughts I gained recently as an effect of the discussion. If only I had more time. Will be continued!
Best writeup of a git branching model I’ve seen yet. Thanks!
Do you happen to use rails? I’ve always wondered what the best practice was for cherry picking features from commits on the “develop” branch that you want to prepare for a release. The scenario I’m thinking of, is when you decide that one feature is more mature in another that has already made it into “develop” and you’d like that to be pushed to production without adding other features.
So, you can “git cherry-pick” into a release branch… but what about the migrations (rails term for database script) that are skipped over? The second time you release something to production, adding in those migrations you previously skipped over will end up being ignored by db:migrate on your production server….
Thoughts?
My solution is basically to just change the timestamps / filenames for the old migration while you prepare the release.
Hi Vincent, any many comments mentioned here, I think this is the best blog/document available for git branching.
I still use SVN at work and have nightmares with merges and conflicts. I am very new to git. I have been thinking of using git but have been skeptical because of the following
i. the SCM team handles a enterprise web application which follows only one pre-defined production schedule and all developers follow it. We fear that the repositories on each developers/teams desktop might fork out of the mainline and create a huge drift which would creates bigger problems when merging the changes back to trunk. I think its ok to have such scenarios in case on the linux kernel development.
ii. I am not clear of the pull/push model for pushing changes. In your model, how do the changes make it to the release branch or the mainline. Who decides what changes go in? is it a push or pull of the changes ? We have a very tight gate-keeping done for changes, how can we ensure that when using git ?
Again thanks for the great articles.
@Etan: I don’t know Rails very well. But from your story, it sounds as if you are using the
develop
and release branches in another way as I intended in this model. The model’s equivalent of “including a feature in the next release” is merging it intodevelop
. It is important for the model to work that thedevelop
branch is considered a bucket in which you put all the functionality that needs to be in the very next release.That way, the responsibility of the release branch mainly is to clear the path for the
develop
branch to receive feature merges intended for the “next+1 release”. Furthermore, you can use it to take a breath and dot the i’s in preparing the definitive release. Our golden rule is that no commits other than minor bug fixes are allowed on the release branch.As far as migrations are concerned: you should consider those as a part of the integral feature requiring the migration in the first place. That way, migrations are also changed on feature branches and, when ready, merged into develop. It really isn’t more complicating than that.
@mastkis: Thanks for the kind words.
The fear you express in i.) is a common fear that every Subversion person experiences and feels a lot like letting go of structure and entering chaos. Partly, this is true. In practice, you can really drift away from the “central” repo. However, when you do, you are also the person who needs to deal with the conflict. So it is in everybody’s own interest to keep up regularly with the central repo. In Subversion, you typed “svn update” regularly. In Git, you type “git pull” regularly. But I agree that Git may look a little daunting at first sight.
Several models are possible. The model that I proposed here does not require any of such models. The organisation of your team however, may do so. For the model, it’s just relevant how changes make it from feature -> develop -> release -> master. Then, a person playing the role of the “release manager” may push these changes to the central repo. Determining who may push these changes to the central repo is key to how you manage the central repo.
Since my team is rather small, and we sit in a room together, almost everybody has write access to the central repo. Before we decide what goes in, we discuss it. That’s a choice, not a requirement at all. To contrast, one of the recent additions to our team is a junior developer with no Git experience whatsoever. Until he reaches the experience level required to responsibly push to the central repo, he just asks me to pull his commits directly from his local repo (where I have read access). I would then review his code and push it to the central repo myself. The other team members can then pull his commits from the central repo.
Git’s model is so flexible (too flexible?) that it does not guide you in any way. However, you can bend that around into using it exactly to your team’s needs. Typically, you want to give all team members read access from the central repo, but you can simply restrict write access to the central repo to those who are allowed. No complex configuration, just setting Unix permission bits right.
@Vincent
Thanks for this in-depth and well illustrated post about your branching strategy….as well as the code on github.
I have a question though, how do you handle it when a feature needs to be rolled back from a release branch? Unfortunately, where I work, this is an issue. Since you are doing bugfixes in the release branch, it would seem like it would be difficult to roll back a feature if there are bug fixes committed after the initial merge.
Maybe this isn’t a problem you have? If so, I’m jealous.
Anyhow, thanks again for sharing your process.
Thanks a lot for sharing Vincent. Very clear and concise explanation. It’s a big help to see the workflow that others are using and compare it to our own. The option –no-ff also makes a lot of sense to ensure we clearly delineate a block of work being merged back.
I like this approach. We do something similar, but I had never considered using a development branch along with a features branch. Very cool idea. We do the standard “topic” and “hotfixes” branching, but development is done in our own master branches (which can and does cause problems sometimes). Then we drop tags for releases when things are groovy in the master branch. A little kludgey, but we have some members on our team that are new to Git and this makes it easy for them to jump in and contribute. However, I can see the benefits of your approach and I’m interested in giving it a try.
Thanks for the great read and the new ideas. :)
Very helpful.
Do you keep any external records of branches and structure as they devlop, or do you rely only on information that can be retrieved from Git itself?
Vincent, are your diagrams all hand crafted? Do you have a tool or technique to visualize your commit history in the same vertical swim lanes in your diagram?
Yes, they are all hand-crafted, using Apple Keynote. There is no tool to visualize commit graphs based on this development model (yet). For me, the following
git log
command is what comes closest, although it does not provide the clarity that a swim lanes view would, by far:@Vincent, I can recommend adding –decorate so that neat log commit. :)
I currently have:
git config –global alias.log-graph ‘log –graph –all –decorate’
So I can write: `git log-graph` or `git log-graph –oneline` to get an overview.
Despite looking really ugly, gitk helps too.
Vincent, this article is great. Thanks for taking the time to put it together. We’re looking to potentially move to git and create a new merge/branch methodology and this looks perfect.
Any chance you could send me the keynote file for the flow? It would save me the time of recreating it just to update a few things for our particular environment.
My favorite part is when you declared, for each branch – where it may branch off from, and where it must merge back into. Such a simple thing, but it really helped to clarify my thinking. Thank you for the article.
Great stuff. We have a similar model w/ clearcase, which is slow and ancient. Its centralization does not elegantly permit subteams, etc.
The terms for releases should be more clear: internal and external instead of release and real release.
Great post! I find the “build/develop” branch pattern very interesting since it helps keeping the mainline always clean and ready to be released. Cool.
My question here is: how would you combine it with continuous integration? Every commit on “develop” will trigger the testsuite? Will you also pass all tests on a per branch basis?
I’ve found a very interesting post follow up digging into some of the details here: http://codicesoftware.blogspot.com/2010/03/branching-strategies.html
I am also curious about how this works in an environment using a continuous integration tool like Hudson. If I was to try to map this model into our environment today, I would minimally create a job for the develop branch and the release and hotfix branches as needed. However, since we have Hudson set up to create a tag for every successful release or hotfix build, the value of the master branch seems to be diminished. If we need to get the exact state of production at any time (to branch a new hot fix, for example), we can simply use the tag of the build that was pushed to production. Am I missing some additional value gained by having a full fledged branch that represents the state of production?
At the moment I only use GIT solo without any additional developers but I’ll keep this page bookmarked because it might prove useful in the future.
@Xeross: Oh, well, this model is perfectly usable in one-person projects, since it is not about cooperation but about release management. Don’t let those two confuse you.
Excellent article, this is aligned with my thoughs about this, and the most important very very handy for use in any project using any DVCS, Mercurial in my case.
Yes, could you also post the Keynote file? It would be great to tweak this slightly for our own process and then print a full-size version!
How do you handle the version numbers for the development branch if you were doing nightly builds or CI? Seems like you would want the version to reflect what release you were working towards rather than waiting until you create the release branch.
I’m trying to understand how issue tracking/QA is affected when using nightly builds and these additional release/master branches.
Thanks ! really nice post!
especially the diagram.
It clears some doubts on preventing conflicts too.
actually not preventing but preparing to merge.
I will take this branching model and convention as one of the git best practice
I started to use this model but then I found that git-describe will not work as I expected on the development branch as the tags are only in the master. In order to have a meaningful git-describe on develop what would be the best approach:
1. create the 1.2 tag in branch release-1.2 instead so when this branch is merged both to master and develop it will be “inherited” by both of them.
2. merge master into develop after creating the tag
3. create a dev1.2 tag in branch release-1.2 and a 1.2 in master
Thanks in advance for your help
Really interesting post and work.
Personnally, I encounter an issue with translations. In my project, translations are done externally (via launchpad). The difficult is to find a way to manage these contributions.
Wow!
Thank you very much for this clear and comprehensive description I was searching some time for!
The diagram made it for me and my collegues to get a clue how we can use git (instead of Visual SourceSafe…) and how to work with all the new (to us!) features, such like branches.
For those wanting to move from VSS to git: there is a tool that helps “vss2git” (http://code.google.com/p/vss2git/)
This is a great write-up! I’m fairly new to Git (coming from subversion) so I’m still getting familiar with things. Your write-up here builds nicely on top of the regular git usage documentation. I’ll be sharing this with some of my colleagues.
We probably will adopt your model, but we’d like to do a couple changes to the pdf (mainly some name conventions to reflect our actual repository).
Being yet the pdf with attribution license share alike, would you be so kind to release the sources ?
Is there a good guideline / approach for vendor branching?
I have a scenario:
(1) I have main line of development (trunk / master)
(2) I would have customer-specific code — main problem is, how do I structure this!
=> At some point later in time, the customer code will undergo customization
=> At some point later in time, the code from mainline will have to be propagated to all customer-specific code, preserving the changes/customizations done specifically for customer
Any help will be appreciated!
@Riccardo: I’ve updated the article with a link to the original Keynote source. Hope you like it!
Yes, I like it ! Thank you very much, I’m sure me and my team will have an happier life following your development model
@Vincent Driessen (January 21st, 2010 at 00:05)
In the case of rebasing subbranches on top of already rebased parent branch Git is smart enough to skip the duplicate commits. But it may be confusing when there are some other changes added on top of the rebased parent branch before rebasing the subbranches. I agree that it is a little bit messy. I would do this only with local topic branches when doing some experiments etc.
There may be methods how to do successful branching and merging with Subversion etc. but I believe not many of us really tried or dared to do that at large. In smaller teams it is too hard and annoying (remember, programmers are lazy :-)). In our team (3 devs) we are using only trunk for actual development. For each release a branch is created and hotfixes are patched onto it from trunk (or vice versa). We had some feature branches but those were really special cases with longer development (more than few weeks or so).
I actually use local git repo (with git-svn) for my own development for some time now. Local branches is a must-have for any DVCS!
Anyway, this is a great article. It gives good insight on how could be git workflow done in practice. Thanks! :-)
I like your article but I have a few questions since I am new to git.
My understanding of your article is that in the “central” repository, there would only be the master and develop branch? This is because the other branches (feature, release, hotfix) basically go ahead once changes are merged into local master and develop and pushed, correct?
What if those other branches had longer life spans (as some people mentioned) and were in the central repository. When developers would clone something from the central repository, they would have to create local branches for everything but master. I can see this would get very tedious after awhile.
If you have central repositories with several “official” branches, how does a developer easily create local (matching) branches to work on after cloning a repository?
btw, I like your diagram. It is a great visualization aid.
Thanks.
Vincent, outstanding post.
I’ve came into it searching on google form images to ilustrate our company’s branching new rules, and after I start reading your post, I’ve got to review some ideas.
@Ron: You wrote:
Yes, exactly, but only for small projects. For non-trivial projects you would probably use an alternative way of dealing with release branches. Typically, they would not only have a longer life-span, but you would also want to access/modify the release branch by multiple people.
Here’s how we do it: depending on the number of persons involved in bringing forth the release branch, we either push it out to the central server, or the developers involved fetch directly from the “release manager”‘s repo (we have read access to each others repo and I recommend it very much).
In both situations, we do not only have a
master/develop
branch locally, but each developer involved also has arelease/x.y.z
branch. It is not that tedious, as long as nobody but the “release master” merges therelease
branch intodevelop
ormaster
.The only disadvantage to this approach is that, after finishing the release, each developer needs to manually remove the branch locally.
The “release manager” may also have to remove the branch from the central repo (using
git push origin :refs/heads/release/x.y.z
).Vincent, this is super-valuable. And beautiful.
I’ve been working with git on my own now for about 5 months, with occasional collaborators. I was only introduced to the idea of having release branches recently.
Intuitively, I would work in the master branch, so that would be the development branch, and then when I was ready to release, that would be the deliberate (non-default) action. I guess from your comments the danger would be that I would pollute the “main stream” with stuff I wasn’t working on? Or that someone else would pollute my stream.
Anyway, this aspect of things is still very new for me. I think I will consider master to be the development branch. But we’ll see how things go, as I progress. Thanks again!
@Vincent: Your post and the gitflow project ist great!
We use a very similar branching model (with subversion — a real pain) over the last two years. We had been inspired by Henrik Kniberg’s paper “Version Control for Multiple Agile Teams” (InfoQ, http://www.infoq.com/articles/agile-version-control). He gave the hint & the hope that it can make some sense to use branching within agile development.
What’s different from our own model is the use of the production=master branch. This concept cannot be easily used in subversion.
Excellent post; a true revelation. I’m new to Git and this supplied vital structure.
I do have a few small quibbles with the main, top-of-page figure (Git-branching-model.pdf):
* Although you’ve incorporated support branches into gitflow, they don’t show in the figure.
* I object to naming any branch ‘master’, since no branch should be default. Users want ‘trunk’, developers want ‘devel’, at least.
* While your figure is beautiful, it is also expensive. Each fuzzy-bordered commit symbol contains over 1800 path nodes. The PDF is almost 4 Mb; deconstructed to SVG it is a hefty 7.4 Mb. My less-elegant version comes in under 100 Kb.
The new figure is at git@github.com:Xiong/gitflow.git on branch ‘figure-xiong-svg’: workflow.svg. I’m not sure where else it should go.
Not everyone will prefer my choices but they may edit the figure to serve their needs and desires. I encourage others to extend and improve.
Thanks again for an important conceptual tool.
Excellent write up. I leant a lot from your git workflow model.
I’d like to add my thanks for writing this up too. We’re just about to move from svn to git and this model is perfect for us and will save us a *lot* of time.
Excellent work, and I learn a lot, hopefully Vincent can summarize them in FAQ, furthermore I notice some comments are not answered yet like Martin’s repo concerns
And also as Xiong, I write it in balsamiq mockup format (http://www.balsamiq.com/), and contribute into my forked repo. see http://github.com/larrycai/gitflow/blob/develop/contrib/gitflow.bmml
You can visit my blog “Git branch flow in balsamiq mockup format” : http://codeslife.com/?p=134 , see picture and pdf files. http://codeslife.com/wp-content/uploads/2010/07/gitbranchflow.pdf
Thanks for the article (a friend gave me that link as a respone to “any good git model to follow?” question).
I will have to use slightly different approach as whole system has to be transparent to the world – opensource development. The “main” repo will have to remain writable for a small subset of people (1?). Also personal repositories have to remain read only for others than authors.
I am also a fan of leaving the master branch a development one, it’s something majority got used to and lowering the entry point is a good thing in opensource.
With these exceptions will git-flow be a good tool for the repository managers?
@zalun: Of course you can easily change your develop branch to be the Git
master
branch, no problem. In fact, if you use git-flow, you can simply rungit flow init
and pick your preferred branch names for develop and master.On having a main repo that is writeable for the repo owners only: that’s exactly what all Git repo’s are in the open source world. You simply setup a repo on Github for example and you already have this situation. This model changes nothing to normal, good Git practices.
I’ve opened up a Google group for gitflow. It’s at http://groups.google.com/group/gitflow-users/
You need a Flattr button…
Vincent.
How do your sub teams work? Does Jane pull directly from David, or does David have to push his feature branch to origin and then Jane pull from there?
Our team is using Github and I’m wondering if I can have team members pull directly from other team member’s local repo and save the house keeping of origin.
Thanks
@Thilo: there is one now.
@Dom: Here, we pull locally, but if you have a Github-style repo with a separate public and private repo, there really is no difference. In that case, you’d have to “publish” all of your private work to Github to have other team members fetch your work, of course.