Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How would you use a DVCS (mercurial in my case) to develop for different versions of the .NET framework?

I'm writing some sort of new adminstration dashboard for our cms (which runs on asp.net webforms). Some of our older servers can only handle .NET 2.0 for various reasons so I'd have to rewrite my code which uses lambda expressions etc. for that.

I wonder how you would use a dvcs like mercurial to develop those two versions concurrently.

My current codebase and mercurial repository is targeted at .NET 3.5. I'm relatively new to mercurial and I guess I'd have to branch the codebase?

Any best practices or tutorials?

like image 369
kitsune Avatar asked May 28 '09 07:05

kitsune


People also ask

How does mercurial help in source code control?

Mercurial is a free, distributed version control system. It's also referred to as a revision control system or Mercurial source control. It is used by software development teams to manage and track changes across projects.

What are the advantages of Git over Mercurial?

Git has a powerful and effective branching model. Branching in Git is better than Branching in Mercurial. Branching in Mercurial doesn't refer the same meaning as in Git. Git supports the staging area, which is known as the index file.

What is the difference between VCS and DVCS?

DVCS is faster than CVCS because you don't need to communicate with the remote server for each and every command. You do everything locally which gives you the benefit to work faster than CVCS. Working on branches is easy in DVCS.

When using a Centralised version control system for other developers to see your changes you must commit them to a central server?

Centralized version control systems are based on the idea that there is a single “central” copy of your project somewhere (probably on a server), and programmers will “commit” their changes to this central copy. “Committing” a change simply means recording the change in the central system.


1 Answers

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.

like image 59
Martin Geisler Avatar answered Nov 10 '22 08:11

Martin Geisler