2

I am currently working on a large project involving at least 3 teams working on separate feature sets in the same codebase versioned on Git. Some features require back-end integration and stabilization and I've heard of features taking months from being ready to going live.

I've seen A successful Git branching model and found it unsuitable for this situation, especially because feature branches must derive only from the development branch.

I assume features should always be in sync with master which represents current production code. The process of taking code from master->release->develop->feature makes keeping features up-to-date more difficult.

Plus, when complex merge conflicts arise on a merge from release to develop, who should solve it? On a large project with distributed teams with non-overlapping responsibilities not a single person is best suited to resolve complex merge conflicts across a whole codebase. No one owns the develop branch, neither a person or a team.

Merging features to and from the development branch also brings to them not-yet-production-ready code from other features while trying to keep them up-to-date with master, making feature branches sort of infect one another in the process. Once I've pulled from development to update my feature with latest production code and be able to call it "finished", I've infected my branch with supposedly finished code from other features that have merged to development. If any features in development are found to be either hard to stabilize or de facto a bad idea, we've compromised the development branch and all its feature branches.

Instead of deriving from the development branch, I found deriving from master and merging into disposable "release-package" branches lead to less headaches.

Diagram for my proposed branch model

When merge conflicts arise in master->feature merge, the person doing the merge is the one most suited to resolve them. She knows the code and what it should do, it's her feature.

Features are streamlined into disposable release branches that can be deleted and reformed at any time. If a feature is not ready to go live by the release deadline, we can delete and recreate the package without it.

Development is only done in feature branches. Release branches only receive merges. If features conflict in a meaningful way, we should question if they should be merged into one another or scheduled for sequential release, one after another. In the case we merge two features into one another, the scenario might look too similar to NVIE's branch model, but here we are given a choice to do it or reschedule the features and recreate the release package.

The disposable nature of release branches and the independence of feature branches makes it possible to stage fallback releases.

Fallback release diagram

If all four features don't stabilize until the deadline, only 1 and 2 go live.

Is my proposal a suitable branch model?

PS: I've read this answer about branch models vs quality and CI, and I don't think it applies. This project does have a quality problem. This quality problem will be there tomorrow and the next month, and while this quality problem remains there must be a suitable branch model we can use, one that does not make life harder.

  • The idea of the dev branch is not to merge into it unless your feature is finished. The problem with your model is your feature branches dont branch from the release branch you want to merge them into (although git is kind about that sort of thing) – Ewan Jul 2 '15 at 7:53
  • I saw that model, in it, develop is the new trunk and master is a "QA" branch. That model still works for you, but feel free to use master as the trunk and create a new 'QA' branch between master and releases. – gbjbaanb Jul 2 '15 at 9:47
  • @gbjbaanb master is not QA. Only code that is already in production goes to master, and only after a release cycle that does not result in a rollback, so code is guaranteed to be safe for other developers to branch from. That's the whole point: prevent branching or merging from a failed release package. – Juliano Jul 2 '15 at 13:50
  • @Ewan You say git is kind about that, are there any side-effects nonetheless? – Juliano Jul 2 '15 at 14:10
  • 1
    @Juliano Git development uses a branching model quite a bit like this - features branched from stable and integrated to temporary or release branches: manual page for gitworkflows, illustrated in the slideshare presentation. Sorry to respond to such an old one but I'm currently planning configuration management and exploring options for branching in projects and maintenance and thinking this exact problem. – apa64 May 18 '16 at 5:52
3

The main problem you are going to face is that when you are combining the feature branches to a release branch, you'll need to solve all the inter-branch conflicts. Merge conflicts are the easier ones, since they pop when you are merging specific branches and you can ask the branch owner to solve them(it's far from ideal though, since the branch is not fresh in the owner's memory). But not all conflicts pop us as merge conflicts - some create compilation errors or runtime bugs, and it's not as trivial to figure which feature branches have caused those.

A possible solution can be to shorten the release cycle - adding more rapid "sub-releases", e.g. twice a week. This will limit the number of feature branches you are merging on each sub-release, which in turn limit the conflict potential. This, of course, comes with it's own problems - a frequent release overhead, where the release master needs to choose which features to merge in each sub-release, and after the sub-release the developers need to merge/rebase their pending feature branches(and resolve conflicts).

At any rate, I think your fear of branching-from-develop is unjustified. You are portraying develop as some big playground where all developers push their unfinished scrabbles of untested code - and it's not true. The feature branches fulfill this role. develop, while it might not need to be as stable and as rigorously tested as master, should still have a certain level of stability - the primary rule is not to push to develop if it'll prevent the other developers from continuing to develop even if they merge/rebase develop to their feature branches.

This essentially means that you don't merge a feature branch to develop unless it passes automated tests(doesn't have to be the full suite - if you have a 10-minute suite that catches most bugs and a 5-hour suite that catches even the rarest of bugs, test the feature branches with the 10-minutes suite), so it should be OK to merge it to develop.

Note that master still needs to pass the 5-hour suite, and you have no guarantee a a merged feature branch won't break the 5-hour suite - but neither does your model provide such guarantee. The point is that even if a merged feature branch does break the 5-hour suite - it's still a branch you want in the next release(otherwise you wouldn't have merged it to develop), and the solution is rarely to exclude the feature from the next release.

Update

To answer the asker's first comment to this answer:

When runtime integration bugs arise, the affected feature-set team will be assigned to correct it. If it is caused by code from features created by any of the other teams, fixes are made into pull requests to the offending feature branch. Pull requests are then reviewed by the team that owns that feature, merged in and then merged into the release package. The team that knows how a feature should work makes the fix, the team who owns the offending code reviews it.

This method of solving bugs has several drawbacks compared to solving them as part of the preparation of a feature branch to be merged into develop:

  1. The feature-set where the bug happens is usually easy in to figure in both methods. The actual changes that invoked the bug are trivial when branching from develop and very tricky when branching from master. The former only gives you a cue about you about who should be assigned to try solving the bug first, which is not as useful as the actual lead you get from the letter. At any rate, branching from develop allows you to have both hints.

  2. The responsibility is backwards. If anything, the owner of the offending code is the one who should fix it, since they know best what they are trying to achieve, and the owner of the feature-set is the one who should review it, because they know best how the different parts of the feature-set should interact with each other.

    But the branch-from-develop approach has an even better way to decide who will be the one to start solving the conflict - it's the one who tries to merge last!

    Now, that claim might seem a little weird and arbitrary - it looks unfair to "punish" the developer who pushed last for being slow. But I believe they are the best choice for starting to solve the problem:

    • They are already in the context of the problem. This is the most important reason - being in context is crucial for solving problems, and entering context is hard. But the developer who pushes last is already in context, because that's the task they are working on. They have already build the mental model that can help them solve this problem.

    • They are available. They don't have something more urgent to do right now, because what they were doing was trying to merge their feature branch, and solving the conflict is required for merging the feature branch.

    • They don't have to actually solve the conflict entirely by themselves - just to be the first ones to look at it. When examining the problem they can decide some other developers need to be involved. Since they are in context, they are in the best position to tell who these other developers are. Also since they are in context, they can help bringing these other developers quickly into context.

  3. That pull request into the offending feature branch will be a nightmare. The code in the feature branch works, because the other branch it was conflicting with is not part of it. So, you are sending a fix to a problem that's not yet there, that might have to relies on changes that come with the same code that introduced that problem. There is no sane way to do that without merging/rebasing the other branch(or the new release) into the feature branch - but if you do that you are just using branch-from-develop with develop having it's name replaced on each release.

  • When runtime integration bugs arise, the affected feature-set team will be assigned to correct it. If it is caused by code from features created by any of the other teams, fixes are made into pull requests to the offending feature branch. Pull requests are then reviewed by the team that owns that feature, merged in and then merged into the release package. The team that knows how a feature should work makes the fix, the team who owns the offending code reviews it. – Juliano Jul 2 '15 at 14:03
  • About shortening the release cycle, we already do many releases a week. Many features are small and fast, but some features are slow and deal with jelly outside services. What I'm trying to do with this model is protect the small fast features from getting infected by the slow and jelly ones. – Juliano Jul 2 '15 at 14:06
  • My main concern in this question is if there is something I'm overseeing and if there's something that might be worse in this model in this scenario. Your concerns about runtime bugs and how to fix them is exactly the kind of feedback I'm here for, thanks =] – Juliano Jul 2 '15 at 14:09
  • I've added an update to the answer regarding your first comment. As for the second comment - you don't have to merge the slow-and-jelly features into develop before they are ready. What git-flow says is to keep them in their own feature branches until they are ready to be merged into develop without corrupting it(making it unfeasible for other developers to keep working on it) – Idan Arye Jul 2 '15 at 22:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.