Yes, you can use Mercurial for this. Here is how it would work.
Let's say that your current clone is called new-dot-net
since it
support the new .Net version. You make a clone of it and call it
old-dot-net
or something like that. The two clones are now identical
and both target .Net 3.5.
Now carefully make small changes in old-dot-net
in order to make it
.Net 2.0 compatible. When you make the changes the two clones will
start to diverge:
new-dot-net: ... [a] --- [b]
old-dot-net: ... [a] --- [b] --- [c] --- [d]
Here you made [c]
and [d]
changesets to add the .Net 2.0
compatibility. Notice how the old-dot-net
clone contains more
changesets than new-dot-net
since it has the backwards compatibility
changes that you dont want to see in new-dot-net
. As you continue
working, it is important to think of this: net-dot-net
will contain
a subset of the changesets in old-dot-net
. The changes flow from
new-dot-net
to old-dot-net
, but never in the opposite direction.
Let's say you make a new change in new-dot-net
. You make the change
in new-dot-net
and the situation now looks like this:
new-dot-net: ... [a] --- [b] --- [x]
old-dot-net: ... [a] --- [b] --- [c] --- [d]
You now want to back-port the change to old-dot-net
as well, you
change to old-dot-net
and pull from net-dot-net
:
% cd old-dot-net
% hg pull ../new-dot-net
This will create a new head in old-dot-net
:
[x]
/
old-dot-net: ... [a] --- [b] --- [c] --- [d]
since the [x]
changeset has [b]
as it's parent changeset. You now
have multiple heads and have to merge to reduce the number of
heads. By merging you create a new changeset which is your way of
saying "this is how [x]
and [d]
should be combined". If the [x]
changeset only touches code which is not also touched in [c]
and
[d]
, then the merge should just work. Otherwise you'll be presented
with a merge tool and have to resolve the conflict. You commit the
merge as chageset [e]
:
[x] --------------.
/ \
old-dot-net: ... [a] --- [b] --- [c] --- [d] --- [e]
And you're done -- you have now incorporated the [x]
change into
your .Net 2.0 compatible code.
You repeat this every time there has been a change in new-dot-net
.
Let's say that more features are added:
new-dot-net: ... [a] --- [b] --- [x] --- [y] --- [z]
After pulling them into old-dot-net
you get
[x] --------------.---- [y] --- [z]
/ \
old-dot-net: ... [a] --- [b] --- [c] --- [d] --- [e]
And you now merge [e]
and [z]
:
[x] --------------.---- [y] --- [z]
/ \ \
old-dot-net: ... [a] --- [b] --- [c] --- [d] --- [e] ----------- [f]
The important parts to remember are these:
- make any new features in
new-dot-net
.
- pull changes into
old-dot-net
- never push from
old-dot-net
to new-dot-net
.
Should you at some point find that a change in new-dot-net
is not
needed in old-dot-net
, then you still need to pull it in and merge
it. But you will then do a dummy merge. If the heads are [w]
and
[g]
, and you want keep [g]
, then do
% HGMERGE=true hg merge -y
% hg revert --all --rev g
% hg commit -m 'Dummy merge with y.'
The trick is to do the merge without caring about the results,
then revert all changes, and commit the unchanged working copy as the
merge. That way you tell the world that "the combination of [w]
and
[g]
is [g]
", i.e., you throw away the changes in [w]
. New
changes made in new-dot-net
after [w]
can then be merged like
normal.