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.3
branch - 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.3
now 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.3
should be tested, finished and deployed - feature A and its adjustment commits should be in a new release (
1.2.4
) - commit history of
develop
should 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/A
intodevelop
(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 --hard
to reset the branchrelease/1.2.3
todevelop
, so thatrelease/1.2.3
pointed 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 thereset --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
develop
has not been rewritten.
Top comments (0)