31

I have a client who insisted that we keep our new development separate from the main branches for the entirety of 2016. They had 3-4 other teams working on the application in various capacities. Numerous large changes have been made (switching how dependency injection is done, cleaning up code with ReSharper, etc). It has now fallen on me to merge main into our new dev branch to prepare to push our changes up the chain.

On my initial merge pull, TFS reported ~6500 files with conflict resolution. Some of these will be easy, but some of them will be much more difficult (specifically some of the javascript, api controllers, and services supporting these controllers).

Is there an approach I can take that will make this easier for me?

To clarify, I expressed much concern with this approach multiple times along the way. The client was and is aware of the difficulties with this. Because they chose to short on QA staff (1 tester for 4 devs, no automated testing, little regression testing), they insisted that we keep our branch isolated from the changes in the main branch under the pretense that this would reduce the need for our tester to know about changes being made elsewhere.

One of the bigger issues here is an upgrade to the angular version and some of the other third party softwares --unfortunately we have no come up with a good way to build this solution until all the pieces are put back into place.

Robert Harvey
  • 200,592
user258451
  • 421
  • 3
  • 5

4 Answers4

37

There would have been a simple way which had kept your new development separate from the main branch without bringing you into this unfortunate situation: any change from the trunk should have been merged into your dev branch on a daily basis. (Was your client really so shortsighted that he could not anticipate that your branch needs to be remerged back into the main line some day?)

Anyway, best approach is IMHO trying to redo what should have happened on first hand:

  • identify the semantics of the changes on the main line for day 1 after the branch was created. Apply them to your current code base as well as you can. If it was a "local change", it should be simple, if it was a "cross cutting refactoring" like renaming a widely used class, apply it in a semantically equivalent manner to your current code base. Hopefully during that year no contradictory cross-cutting changes in the code base were made on "your" branch, otherwise this can become a real brain-teaser
  • test the result (did I mention you need a good test suite for this task)? Fix all bugs revealed by the test
  • now repeat this process for the changes on the main line for day 2, then day 3, and so on.

This might work when the teams strictly obeyed to the classic rules of version control ("only commit compilable, tested states" and "check in early and often").

After 365 repetitions (or 250, if you are lucky and you can bundle the work for weekend changes), you will be almost finished (almost, because you need to add the number of changes which will happen to the main line during the integration period). The final step will be to merge the updated dev branch into the trunk again (so you don't loose the trunk's history). This should be easy, because technically it should be only a replacement of the affected files.

And yes, I am serious, there is probably no shortcut to this. It might turn out that "daily portions" might be sometimes too small, but I would not expect this, I guess it is more likely daily portions can turn out beeing too big. I hope your client pays you really well for this, and that this is so expensive for him that he will learn from his failure.

I should add that you can try this also with switched sides - reintegrating the changes from your branch in small portions to the main line. This might be simpler when on your dev branch there were much fewer changes than on the trunk, or most of the changes happened in new source files which are currently not part of the trunk. One can see this as "porting" a feature from a product A (the dev branch) to a somewhat different product B (current state of the trunk). But if the majority of cross-cutting refactorings were done on the main line, and they affect your new code (the 6500 merge collisions seem to be some evidence for this), it might be easier the way I described it first.

Doc Brown
  • 218,378
14

At that stage of merge I would say that automated merging may only over complicate the process. I have had similar issues with branches that have diverged for over a year and the most effective method I have is to do the following:

  • Take a copy of the original unmerged state
  • Diff between the unmerged and latest
  • Break down any common elements
    • For example, do all function name changes, then parameter changes, etc.
    • Ignore white space on diff if standards have changed, otherwise you will waste a lot of time counting spaces
  • Focus on the core functionality first

Eventually compiler warnings and the diffs will be your best friends, keep using the unmerged diff to see exactly what was different and just keep going. There might be various tools you could use to help, but that will be up to you to find which is best.

The key is to keep going.

Edit:

A word of warning, this approach will mean that version control history would become 'corrupted', as you'd lose the evidence of the branch-to-branch merge, as well as the unmerged branch's history.

Thanks to comments from 'Jack Aidley' and '17 of 26'

8

A few years back we had a client with the same requirements of keeping branches separate. So we did.

We never merged their branch back. They had there own unique version. We charged them extra for changes since essentially we had two major trunks instead of 1 main trunk and branches.

We attempted to merge back to trunk but after 2 weeks we decided to abandon that effort as it was burning hours of time with no tangible benefits.

So, don't merge it back. Going forward merge critical fixes to that client branch as needed and any enhancements would be one offs specifically charged to that client.

Jon Raynor
  • 11,773
1

It is not going to be fun, but how painful it will be depends on the nature of changes, and how isolated they are.

I suggest you attempt to converge the branches through refactoring as much as possible before you do an actual merge.

The merge tool is kind of dumb because it only looks at textual differences and does not understand the code in any way. If the main branch have changed the name of a class used throughout the application, and the feature branch uses the old name in some new code, then the merge tool will not understand that the class name should also be changed in the new code. But if you do a refactoring in branch B to rename the class like in branch A it will work in both old and new code and the merge will go smoothly.

Secondly, you should inspect how localized the changes in the development branch is. If the changes in the feature branch are localized to a few areas, you don't have to converge the unaffected code, you can just copy and overwrite from the main branch.

In areas of code where there have been non-trivial changes on both branches, you have to carefully inspect the code and decide how to rewrite.

JacquesB
  • 61,955
  • 21
  • 135
  • 189