gitversion-controlmergegit-flow

Removing features from releases in Git Flow


I work on a team with a large Java code base (300k+ lines of code), which recently adopted Git as the source control (migrated from ClearCase). We are using Git Flow as our branching strategy. There are a couple of use cases that we come across fairly frequently which we have been struggling with.

  1. We have merged all of our features into the develop branch to be used in an upcoming release. When we get close to the release, it turns out one feature cannot go live (either due to the client not being ready, or some other reason). What's the best way to create the release branch, but leave out a specific feature (across many commits)? The feature needs to be available to be included in the next future release. What we have tried before is to do a "git revert" on all the commits, create the release branch, then do a "git revert" on the reverted commits. This is a pretty painful approach, particularly for large features.

  2. We have already created the release branch, but before the release goes live, it's determined a feature needs to be removed. Similar to the first use case, this feature needs to be able to go into a following release. Because of this, just doing a "git revert" on the commits doesn't solve it completely, as the reverts will get back-merged into the develop branch when we do a "git flow release finish."

As outlined in the Git Flow model, all commits are made on feature branches, and never directly on the develop branch. When a feature is complete and ready for the next release, it is then merged to develop. When it's time for the next release, the release branch is created off of develop. After the release has been regression tested and fixed if necessary, it goes to production and is merged to master, and back to develop in case of bug fixes, and tagged with a version number. The problems above come when a feature which we thought is going in the next release ends up needing to be left out.

What are the best methods to handle these situations? In both of these scenarios, the branches have been published and pulled down by many developers, so messing with the history can create difficulties. I know that these are less than ideal, but unfortunately the situations are out of our control.


Solution

  • In Git a merge commit does two things. Firstly it creates merge history, so Git knows what has been merged and what has not been merged. And secondly it joins the changes from two divergent lines of work together.

    You can trick Git in both of these regards which is what it sounds like you need to do. There are two ways to create merge history without keeping the changes

    git merge --strategy=ours 
    

    and

    git merge
    git revert -m 1 MERGE_SHA
    

    The former creates a merge commit (and merge history), but leaves out all the changes that would normally have been merged in. The later creates a merge commit (and merge history) and merges in the changes, but then immediately removes all the changes while preserving the first history.

    In your instance, if you merged something in and then later change your mind, you would want to use the second form and revert the merge SHA. Now, to keep the changes from that merge from propagating forward to a different branch you would want to use the first form. Note that in order to use the first form effectively you may have to merge one SHA at a time instead (or use an additional feature branch for just this).

    So imagine you have a branch trouble that contains 6 commits (1-6), and you need to merge trouble into master, but you don't want to merge the changes introduced in Commit 4. Instead of git merge trouble you would do

    git merge 3 # merges 1/2/3
    git merge -s ours 4 # creates merge history for 4, but does NOT merge any changes from 4 
    git merge trouble # merges 5/6