What git branching models actually work?
stackoverflow.com
stackoverflow.com
* Simple but quite expressive, covering a large number of use-cases.
* Reliable - there's not much in the way of rope to hang yourself.
* It's easy to explain to people new to git or software development.
It certainly works well for small teams, but I'm not sure how far it would scale - probably quite well as long as there are not too many deviations.
Also as a starting point for development with git it's hard to fault. As you become more familiar/confident you can start to add more complex commands ( rebasing history, etc.) and build quite a sophisticated workflow.
UPDATE: As to the why branch just use continuous integration debate, well continuous integration works just fine as long as your window to deployment is short (hours or a small number of days). With anything that takes a little longer or involves database migrations then branching in some form is still required. So rather than being an either/or situation they really just overlap in practice and one does not preclude the other.
This generally means that a git-flow 'develop' is less stable than a gitworkflows(7) 'master', so it's more common to be working on a new feature and find bugs that were there when you started. That's disruptive to development and its unpleasant to users that would really like the latest stuff that you think is actually ready for them to use.
Thus any decision to merge a topic branch comes with the pressure that any bugs introduced in the merge (possibly through indirect semantic conflicts with other work) will disrupt any developer starting new work between the merge and the time a fix is provided.
In contrast, merging to 'next' in gitworkflows(7) comes with relatively less pressure because bugs there only affect integration and eager users, but not new development. Furthermore, merges to 'master' come with knowledge that the feature has already been playing nicely in 'next', which contains everything in 'master' as well as some other new features.
I wrote a more extensive comparison in http://mail-archive.com/search?l=mid&q=87zjx4x417.fsf@mcs.an...
With gitworkflows(7), new topic branches start from 'master', merge to 'next' when thought to be complete, may receive additional patches while there (remerging to 'next'), and may fail to "graduate" to 'master' (either being discarded by reverting in 'next', or just not selected for this release). When complete, the topic branch is merged to 'master'. 'next' is periodically discarded (usually after a release). This means that the sometimes messy and occasionally broken state in 'next' does not remain in the history and is not used for new development, and some parts of 'next' will not be part of the permanent history. With gitworkflows(7), the history that eventually makes it to 'master' is only complete and fully-tested features (demonstrably so, because it has been in 'next' already). Gitworkflows(7) gives you cleaner history, a more stable 'master', and makes releasing less disruptive.
The main benefit of Nvies Branching Model is that it reduces anxiety.
Since you keep both fixes and features on separate branches, you minimize the anxiety of "can I do this now?" and "wouldn't this also break that". Instead, you just push and push and merge and worry later. You can work on several bugs for several clients - at the same time. Zero anxiety about fixing one thing for one client that breaks another thing for another client.
The golden rule is simply that you don't merge to master (or, for that matter, to a release-x branch) what isn't well tested to be good on a feature-x or hotfix-x branch.
So using that thing I currently build[0], I can just push-to-deploy whatever I'm working on without being afraid that I break clients who have automatic updates enabled. With this strategy, it's up to the clients: If they subscribe to a development or feature branch, it's understood that things could break. I simply have to be careful what touches master and that's it. (And in most cases, clients only subscribe to other branches in a support context, anyways.)
Finally - Yes, there is a certain overhead, but you can use git-flow[1] on the command line to keep that down to a minimum.
[0] http://mangrove.valanx.org [caution: WIP]
I find that because releasing is handwaved away, people find their own way which often sounds like "this is ready, I've pushed to Iteration 16" instead of "this is ready, please pull."
That post could really be fixed by deleting the "develop" branch.
Using a script set such as git-flow really helps manage this without worrying too much.
My only concern about using git-flow was that it was only really suitable on one repo; it doesn't really automate the transmission of the various branches to other repos. But then hubflow[1] sorts that one out.
Transferring that knowledge is time-intensive and expensive.
Scripts don't solve that problem because it isn't a technical problem; it's a social one.
If everyone feels responsible for being able to move stuff from develop to master, then the quality of the stuff sitting in the various develops goes up, and then you find you just don't need develop anymore.
In nvie's system, you just create a release branch from develop and then merge it back into master and develop when done. There's no other skill other than basic git-fu to do that. You can keep develop up to date with any changes from release branch periodically.
The real complication with releasing is release management. But that's nothing to do with branches or even basic use of git, but one of engineering process in general. There's definitely no magic bullet for that.
The real complication is developers that think "releasing" is somehow different than "development".
When it's in master, then it's released.
Whether you call that branch something else, or you use something other than a branch to indicate what is released, is completely irrelevant.
The fiction that "develop" is some future point for master causes huge delays at best for large projects. In reality, "develop" is the hope or belief in some magic moment when the software is "good enough", and since it's someone else's job to decide whether it's "good enough", the buck is passed.
Whatever your problems are they have nothing to do with this particular git branching model. I suspect you have an issue within the culture you are a part of and no git branching model can fix that.
I can tell you that's not the way we do it where I work. Develop is basically the staging area right before you make a release branch (for final QA before deployment).
Random feature branches do not get merged into develop by the developers, when we're going to do a release we decided which of the feature branches to pull in and add to the release. Only the few developers who actually prepare the releases merge things into develop.
Its strongly tempting to "change one little thing" outside the model. Yes yes I know "git flow hotfix" blah blah blah its only a dozen command lines or whatever. But sometimes its so tempting just to checkout master, fix one character, and push it.
The problem isn't so much dumb little typo-fixes that should have been caught in "release" testing, if not feature or develop, or keeping "real" huge changes in the git-flow, but those annoying border cases where both could be argued to be wrong or right.
One solution is to go hard core fundamentalist and demand everything go with the git-flow never outside the process, although that will "waste" some time.
Not so much, although it wastes someone's time.
Someone has to be the release manager, and git-flow gives them only one tool: To reject the release by pushing back.
If they eliminate the develop branch and merge the features directly into the release branch (whenever they attempt to perform a release) then if something goes wrong, they can simply drop one of the features and re-build their branch.
I think that sounds exciting and strongly encourage my competitors to try it. (no, seriously though, don't do it...)
The whole point of continuous integration is that you do not wait until you are done to try to merge your changes. Merges in themselves are painful and not only are there fewer conflicts but they are less serious when everyone is (with few exceptions) just doing little merges all the time.
Moreover, having your changes merged in quick also means that you will get feedback about your changes before you're "done". If your change doesn't break a test but breaks functionality in a subtle way there is a much greater chance that someone will notice it and if you're doing something wrong that you don't know about, again, it's much more likely that someone will tell you. In bigger teams or in complicated domains this becomes more and more important.
Decent and related article:
I'm genuinely interested in collecting good examples of it working. The other article about flickr doing this with feature toggles seemed to be a good fit.
<Rant>
The reason I ask is that earlier this year, I was working with a client who spent upwards of $3 million USD on a content managed website with a huge consultancy that I can neither confirm nor deny is heavily affiliated with the author of the article you may or may not have posted a link to.
They were left with a config-driven feature-toggle system that can only be described as a Rube-Goldberg monstrosity. If statements from old feature toggles littering the codebase and different features toggled on or off in environments that no one knew the meaning of. My favourite was when we discovered after days of trawling through the code that a feature toggle was being used to switch a feature off rather than on.
There was also a team-wide ban on branching of any kind, including local branching. This belies a misunderstanding of how git works more than anything else. I went ahead and kept as many local branches as I bloody well felt like, because there's no way they'd know the difference.
</Rant>
It was bad enough in the days of #ifdef driven development in C, where the meaning of your code and even your entire software design could change based on an arbitrary set of macros that didn’t respect scope, didn’t offer any type safety, and might be defined anywhere: a random header file, a makefile setting some command line option, or just some environment variable on one particular developer’s PC that they set three years ago and forgot about. Making a controlled, reproducible build that you actually trust to be what you think it is is very difficult in that kind of environment.
It’s even worse with dynamically typed languages, because now you don’t even have compile-time warnings about redundant code or type safety guarantees on the code inside the feature checks to prove it would run sensibly. To me, it feels like the whole strategy plays right into the major downsides of using dynamic types. No doubt some people would disagree with me, and would never dream of writing code without comprehensive test suites that back it up and are known to have 100% coverage with every possible combination of features toggled in or out. (If you really think you are in this position, I know a guy who’d like to offer you an exclusive financial deal guaranteed to make you rich, if you just send a 25K deposit up-front in unmarked, non-sequential notes to his mailbox in Nigeria.)
What really bugs me is that this whole feature toggling premise seems to be caused by the tail wagging the dog. Feature toggling is advocated as a way to do continuous integration. CI is advocated as a way to avoid nightmare merges. However, the existence of nightmare merges presupposes that you can have multiple developers simultaneously working on the same part of your code, making sufficiently intricate changes that merging will cause headaches, but for different reasons and without being aware of each other. Otherwise, they could just communicate effectively, and merge intelligently as they go along if that makes sense. How can any development team possibly get into that situation without some spectacular, fundamental failure of project management and technical leadership? That kind of failure is essentially a social problem, so it’s doubtful that any kind of technical solution could solve it reliably, whether a branching model, or a CI-not-branching model, or any other model for that matter.
Occasionally there are still feature branches, though they more often start out more as prototype/exploratory branches, that involve significant architectural changes, and when it's a clear win, it gets merged in.
And yes, banning local branches is stupid; uncommitted code on a developers machine happens instead, which is strictly worse than having a local branch with meaningful commits.
While working on a feature branch, you should be pulling in the latest from origin/master on a pretty regular basis such that you never have a big merge. You should be merging early and merging often.
The benefit here is that you get to work on functionality without hindering anyone else (by putting the codebase in a functioning, but transitional state), while getting to integrate on your own schedule. By the time it's ready to push to everyone else, there should be no merge. It'll be a fast-forward.
Feature branches, with a policy of merge early and often, make life substantially easier than traditional continuous integration workflows. Having everybody checking in in-progress work to the same place is a nightmare.
When I'm working on a feature, I want to be able to commit in small bite-sized chunks that allow me to explore solutions, rollback changes, rebase on-top of whatever I want, and ultimately squash my work into a single cleanly merged chunk of work. Any other workflow is limiting and restricting many of the benefits of git.
> getting to integrate on your own schedule
Essentially, this is what I oppose, for the reasons I described originally.
> Any other workflow is limiting and restricting many of the benefits of git.
The point of git is to make your workflow better, the point of your workflow is not to make git better. Yeah "branching is easy", and that's good, but it doesn't necessarily mean that you want to start using branches heavily (especially long-lived ones). Bad version control systems were only part of the reason to avoid branches.
Second, I think you have a different vision of CI from me (maybe more frequent). I'm not advocating pushing code that is broken, I'm advocating pushing code that is working (but maybe is incomplete).
Thus I don't like unnecessary merges of unfinished work, it increases the risk for breaking the tests, which will slow down development.
If you rebase your feature branch continuously then you achieve what you are asking for without merging unfinished work.
Trunk
Feature1
Feature2
If you nightly merge Trunk into Feature1 and nightly merge Trunk into Feature2 and test all 3 branches, you still haven't tested the integration of Feature1 and Feature2. With enough developers working on enough features the odds that at least one pair of features won't work together approaches unity.People have tried all sorts of methodology and design, &ct. to try and keep this from happening, and they haven't succeeded yet. On the other hand, if feature branches get merged into trunk as soon as they aren't completely broken, and with a way to disable them, then you will very quickly discover that the features don't play well together.
The point of continuous integration is that everybody is reconciling their work with everybody else's all the time, thus helping you find nasty integration surprises early and while you can still do something about them.