The context
At work we use Vincent Driessen's Git Flow branching model. Recently we found ourselves in the following situation:
- feature A had been finished and merged into
develop - release
1.2.3, containing feature A, had been started - feature B had been started after the start of the release
1.2.3 - there were some adjustment commits for feature A in the release
1.2.3branch - feature B had been finished and merged into
develop - feature B didn't depend on any code added by feature A.
Visually, that's what we had (each column represents a branch; and each point represents a commit, with a single letter instead of its hash):
Now we just had to test and finish the release 1.2.3 (merge it into master, create a tag 1.2.3 at the merge, and then merge the tag into develop in order to integrate commits F, G and J) and deploy the newly created tag into production. Then we would create another release for feature B (probably 1.2.4), test, finish and deploy it.
The problem
For reasons that are beside the point of this post, it was decided that feature B should make it into production before feature A. In order to not mess up our version numbers:
- release
1.2.3now should contain feature B, but- without the code of feature A commits (B, C, D and E)
- without the code of the adjustment commits F, G and J
- the "new" release
1.2.3should be tested, finished and deployed - feature A and its adjustment commits should be in a new release (
1.2.4) - commit history of
developshould not be rewritten, for it's a shared branch and other features may have been started based on it.
The solution
Note: for simplicity, in the Git commands below I'll use the letter that was used to represent each commit in the images instead of the commits' hashes.
- We took note of the hashes of the feature A adjustment commits (F, G and J)
-
On branch
develop, we reverted the commit that mergedfeature/Aintodevelop(the merge commit E), so that code related to feature A was "removed" fromdevelop:<master> $ git checkout develop-
<develop> $ git revert -m 1 E # creates commit M
-
We used
reset --hardto reset the branchrelease/1.2.3todevelop, so thatrelease/1.2.3pointed to commit M<develop> $ git checkout release/1.2.3<release/1.2.3> $ git reset --hard develop
-
Still on
release/1.2.3, we made a commit to bump the version number (a change required by Git Flow)<release/1.2.3> $ echo '1.2.3' > version.txt-
<release/1.2.3> $ git add version.txt && git commit -m "Bump version number" # creates commit N
Note that, since the reset --hard, the commits F, G and J have been "lost". That's why we took note of their hashes in the beggining - we'll bring them back later.
-
After testing release
1.2.3, which now only contained code related to feature B, we finished (creating its tag and merging the tag intodevelop) and deployed it<release/1.2.3> $ git checkout master<master> $ git merge --no-ff release/1.2.3 # creates commit O<master> $ git tag -a 1.2.3./fictional-deploy.sh<master> $ git checkout develop-
<develop> $ git merge --no-ff 1.2.3 # creates commit P
At this point, we have released only feature B, but now we must bring back the code of feature A, create a new release with it, and also bring back its adjustments commits.
-
On develop, we reverted the commit M, which was a revert commit itself. Yes, we "reverted a revert".
-
<develop> $ git revert M # creates commit Q
In practice, that brought the code of feature A (inserted in commits B, C, D and E) back to develop.
-
-
Finally, we created the new release (
1.2.4) and brought the adjustments previously made to feature A into it<develop> $ git checkout -b release/1.2.4<release/1.2.4> $ git cherry-pick F # creates commit R<release/1.2.4> $ git cherry-pick G # creates commit S-
<release/1.2.4> $ git cherry-pick J # creates commit T
Conclusion
With a few basic Git commands (reset, revert, cherry-pick, etc.) we were able to solve our problem:
- only code related to feature B has been deployed
- feature A and its adjustment commits have not been lost
- we haven't messed up our versioning numbers
- the history of the branch
develophas not been rewritten.


Top comments (0)