I will try to describe a strategy I adopted in a similar situation :
For a time (a few month), we had two versions living side by side :
*--x--*--*--*--*--*--* <- master
\
A--B--C--D--E--F <- side-version # the actual nr of commits was more like 100
Merging side-version in master in one go was not feasible.
What I ended up doing was to merge bit by bit :
# merging bit by bit :
*--x--*--*--*--*--*--* <- master
\ \
\ *-----*-----*--* <- fusion
\ / / / /
--------------A--B--C--D--E--F <- side-version
For ease of use : I didn't commit straight on master, I created a fusion branch and committed the merging there.
On the history of side-version, I listed some key commits (in our case : I used the commits corresponding to released versions), and started merging those versions, one at a time.
Now, since both versions were live, in some cases, the bugs fixed on side-version had also been fixed on master, so sometimes, "merging" resulted in discarding the content of side-version and keeping the version on master.
Having isolated points mainly allowed me to :
- solve conflicts on a reduced set of files, and with a scoped changelog, so it was easier to validate the behavior at each step ("the behavior on master, plus a handful of features" rather than "both versions combined")
- merge the unit tests, and validate them on each new merge commit I created
- in some cases, start the server in the current merged state, and check some features on my dev machine
The choice of "key commits" really depends on your setup :
- you may have only a handful of commits on
side-version, which all describe a state where your product is runnable and testable, in which case merging commits one by one is perfectly ok,
- you may have some way to clearly identify "this is where this specific feature was added", "this is where this bug was fixed", and use these,
- you may choose to arbitrarily split the history of
side-version in ten chunks ...
Whatever suits your needs.
The choice of the merge points can also be adapted :
- in my case, it wasn't a stopper to have an absurd commit stating "the version of
master in august combined with side-version in may"
- if you have an incentive to aim at more realistic merges, you can also identify "key commits" on
master :
# an alternative strategy :
*--x---P--Q--R--S--T--U--V <- master
\ \ \ \
\ *--*--*--*--*--*--* <- fusion
\ / / / /
A--B--C--D--E--F <- side-version
The merging did take some time (several days), during which the master branch evolved. When I reached my first satisfying fusion state, I actually had to merge in some extra features and fixes released on master.
In our case, it was acceptable to have a history of merged commits ; once you have reached a satisfying state for fusion, you may choose to rewrite its history, to split commits in some more meaningful chunks ...