Search code examples
gitbranchbranching-and-mergingbranching-strategy

Git branching for agile development


First, I want to

  1. Keep my master branch ALWAYS green.
  2. Be able to cherry pick changes for the next release.

Branching strategy:

  1. I have a master branch and an integration branch running alongside with it.
  2. Branch off from master by tasks/issues.
  3. When a task-branch finished its work, merge that into integration to see if it has broken any works from other task-branches. If yes, fix them.
  4. Pull request from the task-branch(not integration branch) to master branch.

    That means the integration branch is only for CI purpose, it will NEVER be merged into master

  5. Decide which changes the next release will include. Merge those branches into master.
  6. Release.

Here is the problem, let's say I have the following situation:

master       -*-----------------
              |\
integration  -+-\-------C---F---
              |  \     /   /
ken/task#1    |   A---B   /
              |          /
bob/task#2    D---------E

In F, two things happen:

  1. A merge conflict occurs as C and F have changed the same lines of some-code.js
  2. F breaks some tests from C.

Now, Bob has to fix that, he has 2 options:

Option 1

  1. Merge integration into bob/task#2 as G
  2. Fix the bugs in H
  3. Merge into integration as I
  4. integration green
  5. Pull request

    master       -*--------------------------
                  |\
    integration  -+-\-------C---F-----------I
                  |  \     /   / \         /
    ken/task#1    |   A---B   /   \       /
                  |          /     \     /
    bob/task#2    D---------E-------G---H
    

However, with this approach, I cannot pick only task#2 to be included in my next release. Because bob/task#2(H) already contains the changes made in ken/task#1 , merging bob/task#2 into master means merging ken/task#1 into master together.

Option 2

  1. Switch back to bob/task#2
  2. Try to fix the bug in G
  3. Merge into integration and run the tests to see if the tests are green
  4. If it doesn't, switch back to bob/task#2
  5. Try to fix it in I
  6. Merge into integration and run the test

    ...

    Until integration is green.

  7. Pull request

    master       -*-----------------
                  |\
    integration  -+-\-------C---F---H---J--- ..........
                  |  \     /   /   /   /
    ken/task#1    |   A---B   /   /   /
                  |          /   /   /
    bob/task#2    D---------E---G---I--- ..............
    

This approach prevents bundling changes from ken/test#1 into bob/task#2.

However, Bob now needs to "guess" what he needs to do to fix the bug. Then merge over and over again into integration to see if the tests are green because G and I now don't have the tests added in C.

He also needs to resolve that same some-code.js merge conflict EVERY TIME he merges his work into integration, which is painful and redundant.

Does Bob have a better option 3?

Thanks.


Solution

  • You should considering following the Git flow:

    https://www.atlassian.com/git/tutorials/comparing-workflows

    Here are my thoughts on how you can align with Git flow development model:

    1. Developers create feature/bug-fix branches and submit pull requests to merge their changes into the Integration branch.
    2. The decision as to which features will make it into a release should be made before the changes are integrated into the Integration branch - not after. Once you've merged features into an integration branch, it is destined for a release, and the order has been determined (the order that you applied the features into the integration branch).
    3. When you review a pull request, and decide that it will make it into a release, you should then review the changeset to see if it can be merged as a fast-forward merge, whether it will result in a clean merge commit, or whether there are merge conflicts.
    4. If there are merge conflicts, you should advise the developer to re-base their changes onto the tip of the Integration branch. This results in a clean commit history and a more stable integration branch because the conflict resolution occurs on a development branch and by the developer most familiar with the code-base.
    5. The merge from a development branch into the Integration branch should be clean: No merge conflicts, just fast-forward merges and/or clean merge commits. There should be no conflict resolution occurring on the Integration branch!
    6. Once you're near ready to release, create a pre-release branch off of the Integration branch (this branch is a release branch that will live longer than the development branches to stabilize the release). Only fixes go into a pre-release branch.
    7. When the pre-release branch is ready for production merge the pre-release branch back into the master branch (this will be a fast-forward merge) and at the same time merge the same branch into Integration. Take this opportunity to squash the commits into a single commit so that you have a cleaner commit history on master.

    8. After you've merged into the integration or master branch, clean up your branches: delete the dev branch after merging into integration; delete the pre-release branch after merging into master.

    9. Tag production releases using a semantic versioning strategy. Create an official release branch to support fixes going forward.

    10. When you identify an issue on the release branch, follow the same process to fix the issue as you would for developing new features (steps 1-5). Make fixing on the master branch a priority over fixing the issue on the release branch. Once fixed, cherry-pick the fix onto the release branch.

    11. The strategy for a hot fix is different. For a hot fix, apply the fix from a branch off of master, and cherry-pick the fix onto the Integration branch.

    To summarize, the main points that I would recommend is:

    1. Have developers merge the code and handle merge conflicts on a development branch before they are pulled into the Integration branch
    2. Pick and choose which pull requests (dev branches) will make it into a release. Once decided, the features are destined for release.
    3. Do not cherry-pick commits/changes from the integration branch into master!
    4. Merges into master should always be fast forward merges. Since you have an additional integration branch, there is no reason why you wouldn't want to enforce this.

    Git Flow is well-suited for medium to large-scale projects. But I actually prefer GitHub Flow for smaller projects, especially if I'm developing component libraries for the web.

    Learn more about it here: http://scottchacon.com/2011/08/31/github-flow.html