Reputation: 7504
I have been monitoring two branches starting from each sprint - Release
and Master
.
Master
branch is from where developers create new branch(task specific), implement their changes, and creates pull request which gets merged into the Master
.
Release
branch is sprint specific which remains always submittable to the production. We only merge branches committed to the Master
and verified by the QA into Release
branch.
This approach works best for us as we submit Release
at fix regular interval with specific functionality implemented and verified, and hence we exactly know what's going in the next release.
It's going great until I ran into following issue;
taskA
from Master
.taskA
branch.taskB
from Master
and committed multiple changes to the taskB
and got taskB
merged into Master
.Master
into taskA
branch and further carry on his task, and commits more changes into taskA
branch!taskA
branch merged into Master
.Now I just want to merge taskA
branch to Release
branch but as taskB
was also merged into taskA
branch as DeveloperA merged Master
into his branch in step#4, I get taskB
branch changes automatically into Release
branch! I don't want that.
What is the best way to avoid merging Master
into Developer
branch and what could be the right approach to follow in my case?
Upvotes: 6
Views: 2650
Reputation: 165606
I think your strategy is too complicated and prone to problems. The complication is trying to integrate feature branches separately into both Release and Master. Because features are developed on Master, each feature branch is going to make use of earlier features and bug fixes. When you try to merge a feature branch separately into Release, Release might not have integrated the earlier features and bug fixes that it relies on. Problems, conflicts, complications.
It is much simpler if you make feature branches off of Master, merge them into Master, and periodically merge Master into Release. The merge flow is Features -> Master -> Release. Never Features -> Release. In reality there should be intermediate Testing and Staging branches to hold the release currently in final user testing (this is on top of feature branch unit testing), and what is ready for the next release. Features -> Master -> Testing -> Staging -> Release.
That said, let's graph out your problem.
DeveloperA has created task specific branch say taskA from Master. He has committed multiple times to taskA branch.
A - B [master]
\
C - D [taskA]
Mean while other developerB created his branch taskB from Master and committed multiple changes to the taskB and got taskB merged into Master.
F - G
/ \
A - B - E ----- H [master]
\
C - D [taskA]
DeveloperA will merge Master into taskA branch and further carry on his task, and commits more changes into taskA branch!
F - G
/ \
A - B - E ----- H [master]
\ \
C - D ----- I - J - K [taskA]
Eventually he will get taskA branch merged into Master.
F - G
/ \
A - B - E ----- H --------- L [master]
\ \ /
C - D ----- I - J - K
Now I just want to merge taskA branch to Release branch but as taskB was also merged into taskA branch as DeveloperA merged Master into his branch in step#4, I get taskB branch changes automatically into Release branch! I don't want that.
You have a few choices. You can git cherry-pick
only the commits in taskA into Release, avoiding the merge commits. That's C, D, J and K. If J or K relied on anything from taskB (or anything else in Master that isn't in Release) you'll get conflicts or (hopefully) test failures. This is a messy, manual process.
Second choice, instead of feature branches using merge to get updates from Master, rebase on top of master. When the developer of taskA decided to update from master, if they had ran git rebase master
instead of git merge master
, they'd have this.
F - G
/ \
A - B - E ----- H [master]
\ \
C - D C1 - D1 [taskA]
C and D would be repatched on top of the new location of master. The developer would have to deal with any conflicts and test problems. Then they could continue working and merge into master when they're done.
F - G
/ \
A - B - E ----- H ----------------- L [master]
\ \ /
C - D C1 - D1 - J1 - K1 [taskA]
This approach keeps branches nice and clean with no intermediate merges. You can cherry pick the whole branch to Release without having to pick out the intermediate merges. You'll still have conflicts and test failures if taskA relies on anything which hasn't been merged into Release, but at least the process of isolating the feature is simpler.
Because your workflow requires you integrate your feature branches twice, and in possibly different orders, you're guaranteed to have conflicts. There's really no point to merging features into Master if they're just going to have to be merged again out of order into Release.
I strongly encourage you to change your process so you only have to integrate feature branches once, into Master. Release becomes just an earlier version of Master. If a feature branch isn't ready for release, don't merge it. This is good development practice in general, it raises the quality of the code the developers are working with (ie. Master), and it avoids developers having to work on an unstable pile of half finished features.
From time to time you will want to apply hot fixes to Release, that's fine. And from time to time you'll want to remove a feature from Master, and that's fine, too. These should be exceptional tasks, not normal workflow.
Upvotes: 4