These days, Merging is Cheap, Thanks to Awesome DVCS like Git, Perforce etc. But, This Activity needs to be done Carefully and under Collective Collaboration with an eye for Future Issues. Else, we end up losing valuable and increase Stress during your Release Time or Run into Issues that take longer time to resolve after your Code is in Production. Either Way, It lowers Confidence in Team and creates Doubts about Processes and Tools Involved, But, No one knows How to Fix the System.
As an Engineer who used to create a lot of Service Patch Binaries, by cherry-picking a range of commits for a old Release Branch/ and sometimes Multiple old Release Branches, onto a new service branch, compile/package the code and provide the customer who requested for it, Here are a Few recommendations that Dev/ Dev Leads can keep in their mind when they merging their Release Branch UP to the master:
First Challenge: Renamed classes
– Description: Classes were renamed to better identify them, or to fit into a pattern. [Examples: SubscriberStatus –>
SubscriberStatusConstants; Feature –> FeatureVO]
– Impact: Renamed classes caused many other classes to be changed due to the import statements needing to change. This caused many classes to be modified in the Release branch, which meant that if the class had changed at all in master, the class was highlighted as having a conflict between master and Release Branch. This, in turn, meant that many classes had to be manually looked at in order to resolve the conflicts. Furthermore, any new code written in master that referenced the old class name now had to be “fixed” when it was merged up to Release Branch.
– Suggestion: Do not rename classes in a branch. Rename them in master, and merge up to the branches. Since the class is simply being renamed, the impact to master would be minimal. This is an example of a low-risk refactoring that has a high code-footprint.
Second Challenge: Removing code-behind
– Description: Some classes were deleted, and the code inside them is put into another file, say some mxml file.
– Impact: When merging from master to Release Branch, git merge would see no changes in the mxml in master, and happily accept the mxml from Release Branch. For the Deleted file, git merge would see that it was deleted in Release Branch, and therefore any changes in master would be considered irrelevant. This means that the merge tool happily reported no conflicts. This meant that you would have to take the modified deleted file, re-paste it into the mxml in release branch, and compare the code — often accounting for renamed classes (as in the first challenge).
– Suggestion: Remove code-behind in master, not in the branches. Since the files are being combined, we’d rather they were combined into a file that will result in conflicts if there are changes between master and a later branch. After combining in master, merge up to the branch.
Third Challenge: Copy/Pasted classes
– Description: Code from a Command class or other “old architecture” class is copied into a new class that fits the new architecture.
[Examples: UsageSummaryCommand -> UsageSummaryResponseHandler; AddRemoveWindowShadeRenderer –> WindowShadeRenderer;
SSSDAccountModel -> SSSDAccountPM]
– Impact: There are two distinct situations here:
– The “old architecture” class still exists: When you get a conflict, you happily merge the code into the “old architecture” class. Unfortunately, If you are not aware that this code has been copied into another class. It is quite possible we could entirely miss these, and this poses not just a risk to “merging,” but a risk to already-delivered functionality.
– The “old architecture” class was deleted: There are no conflicts when merging, and it just looks like the file has been deleted. You generally search for the re-factored class (usually from code segments inside the file). However, if a SECOND merge is done, the deleted file will already have been considered merged, and there is no way to see that you need to update another class.
– Suggestion: Still do this re-factor in the release branch, as these types of impacts would be detrimental in master. In the old class in master, add a comment at the very top of the file that says “to be phased out, use XXX class in xxx release branch ” or something along those lines.
Fourth Challenge: Replacing renamed classes
– Description: I only had one occurrence of this. A class was renamed in the release branch (Feature -> FeatureVO) and then a NEW Feature class was created in the same package as the old one.
– Impact: This causes confusion, because the imports to the old Feature class were not failing, but the contents of the class were not
equivalent.
– Suggestion: Don’t create a new class with the same name as an old, renamed class.
Fifth Challenge: Splitting projects
– Description: CoreAPI was split into CoreAPI and CommonLib.
– Impact: An git merge from master to release branch was not sufficient. You have to use a external tool (BeyondCompare for eg) to compare CoreAPI with CommonLib.
– Suggestion: Although painful to deal with, I believe that this was the correct way to do this in release branch. Splitting the project in the master would have been too disruptful to the “next release.”
Sixth Challenge: Code Quality Tools Related Rules
– Description: A CQ Tool, For Example, FlexPMD enforces this specific rule — for example, “No throwing hard-coded Strings in an Event — you must use a constant.” The rules are less stringent for master and early branches, and get more strict for later branches.
– Impact: Merging code was not the “last step.” After merging, code had to be altered in order to meet the more strict FlexPMD rules. Hence, my “merged code” contains edits done by me that were necessary to get the code building. There were less of these than I expected to encounter but it will still be troublesome to deal with.
– Suggestion: Instead of always introducing FlexPMD rules in the last branch, let each rule be individually placed. For example, if a strict rule is introduced saying “no unused private methods,” it might be better to put it in the master, and merge it up. However, if a rule enforcing the error-handling framework is put in, and that framework doesn’t exist until the Release branch, then obviously, the rule must go in Release Branch and later.
Seventh Challenge: Moving packages
– Description: A class is moved into a different package, and the old package is deleted.
– Impact: This *can* result in a tree conflict, in general, but *definitely* will result in a conflict if the new package is independently created in both the master and the release branch. Tree conflicts require me to manually merge the files. Sometimes this results in me seeing a deleted file in one location, or an added file in another without them being in conflict.
– Suggestion: Don’t create the same package, independently, in branch and master — merge it up. Otherwise, there isn’t much we can do about this one.
Eighth Challenge: Disjoint code
– Description: Code changed in master in a method or file that no longer exists in release branch, and there is no identical method in another file, nor another file with the same basic code.
– Impact: Changes can’t be merged — there is no where to put them.
– Suggestion: Not much we can do here… Sometimes the changes might be irrelevant…
Ninth Challenge: Duplicate fixes
– Description: Someone fixes a Defect in master, and someone else fixes the same defect in release branch, but they do it a different way.
– Impact: The impact is worse if there were multiple files touched in the fix. This requires the merger to attempt to understand the two different fixes, evaluate them for correctness, simplicity, performance, readability (or any other “superior” metric) and choose one. Often times, you can’t take half of one solution and half of the other, and you don’t want to take both, either, since they may not interact well together, or reduce performance.
– Suggestion: A defect should only be fixed in the “closest to release” master/branch where it needs to go, and then merged up to higher releases.
Tenth Challenge: Lack of Merging
– Description: In the worst case, virtually no one merges code until release time and its already too late with too little time.
– Impact: All conflicts become worse and worse to deal with over time.
– Suggestion: Merging needs to happen more frequently.
Eleventh Challenge: Split Classes
– Description: Parts of a class were moved into several different classes, and the class, itself, was fired upon with phasers set to kill.
– Impact: It was difficult to trace down where merged code needed to be placed.
– Suggestion: Add comments to the old class in master to explain where the code can be found in the later branches.
Twelfth Challenge: Large files
– Description: Files that are a little bit on the large side.
– Impact: Comparing them and making changes – in Eclipse – takes a ridiculously long time.
There will be Multiple Features/Bugs that modify these Huge Classes in slightly different ways, sometimes, it’s a challenge when we try to cherry-pick Multiple Features/Bugs and both modify same Lines in 2 different ways.
– Suggestion: Break it up a little.
Thirteenth Challenge: Tree Conflicted Directories
– Description: Directories are moved, or are created independently between branches
– Impact: The comparison must be performed manually.
– Suggestion: Take note of the directory and do a follow up merge. The conflicts should be handled using a comparison tool such as
BeyondCompare or Eclipse’s built in tool and commit with the merge.
Having Said and done all this, Code never ceases to throw Bananas at us 😉 It can become even more Interesting if you have to support multiple customers on multiple master(s) or released products.
Suggestion: Suggest your customers to migrate/upgrade to latest/later Releases.
If not, You can maintain Customer Specific Baselines that Co-Exist with your Release Branches. It is on the Onus of Dev Team to write Custom Code Re-using Code from Earlier Feautures/Bugs.