Background:
3-5 programmers working with TFS. We support legacy apps as well as build new apps. I am implementing elements of continuous delivery and I want to have a good structure to start with. At present there is very little interdependency of apps but in the future there will be some shared components.
I plan to implement a "single trunk" branching strategy (in other words, NO BRANCHING) except for the very rare case where a long feature branch is required -- which I will work to ensure never happens.
Question:
Given this, which source code structure is better and why? Are there any material impacts to choosing one over the other (workspaces, etc)?
SINGLE MAIN BRANCH
$/MAIN/src/ApplicationA/ApplicationA.sln
$/MAIN/src/ApplicationA/Project1.csproj
$/MAIN/src/ApplicationA/Project2.csproj
$/MAIN/src/ApplicationB/...
$/MAIN/src/SharedModule/...
vs. MAIN BRANCH PER APPLICATION
$/ApplicationA/MAIN/src/ApplicationA.sln
$/ApplicationA/MAIN/src/Project1.csproj
$/ApplicationA/MAIN/src/Project2.csproj
$/ApplicationB/MAIN/src/...
$/SharedModule/MAIN/src/...
In my experience I found that it's better to use separate branches for things which have separate development cycles.
If you are going to release them always together as a single package and they are developed as a single product - single main branch is more appropriate.
If every application may be released in different moments, main branch per application seems to be more appropriate.
I like developing all the code in a single main branch. Then use a configuration setting to essentially disable the module for production and enable it for testing until it is ready for release. The added benefit is the modules (dlls) are already packaged for the release since you release early and often.
Related
I work as part of a small development team (4 people).
None of us are incredibly experienced with version control, but we are required to use Perforce under our company's policies. For the most part it has been great, but we have have kept to a simple process agreed between ourselves that is starting to become less ideal. I was wondering if people could share their experiences of version control working smoothly and efficiently.
Our original setup is this:
We have a trunk, which holds production code as it is now.
Each user creates a development branch for their work, as we have
always worked on separate areas that don't really affect each other.
We develop on Redhat Linux boxes and the code is run from /var/www/html. So we sync to a workspace and copy those files to this path, change the permissions and then perform our changes there. When we want to check in, we check out the files in the workspace, overwrite them with what we have changed and submit (I think this might be our weakest part)
Any changes to trunk will be incorporated if they affect the functionality in question. The code is then deployed for testing.
When testing is complete, we merge the branch into trunk, and then create a release branch from the current trunk this is tested again and then released into production.
This worked fine previously because our projects were small and very separated. Now, however, we are all working on the same big dev branch. Changes have been released since the creation of the dev branch, and more will be made before it is finished.
We are also required to deploy the code for testing in various stages of it's development, and this code needs to be up to date with both the development changes, and any changes that have been made to production.
We have decided at this stage that we will create the release branch at the same time as the dev branch, into which we will merge current Trunk(production) and the current dev branch each time we need a testing version so that it is completely up to date. However, this merge takes a lot of time from the whole team and isn't really working out too well.
I've been told that different teams have different ways of going about things so I'm not looking for a fix for my process, but I would love to hear what setup you use of your willing to share
If you are not particularly familiar with version control and best practices I would suggest utilizing Streams in Perforce. Functionally Streams and Branches are very similar. The difference with Streams is that Perforce utilizes pre-built relationships based on the stream type and gives basic governance (i.e. you can't copy those files to the other stream until you merge).
All the commands CAN be overridden by an admin.
Once you are utilizing streams you can do things a few different ways. You have three types of streams, Release (most stable), Main (stable), and Development (least stable). You can create any hierarchy you like.
I suppose in your case I would have a Mainline, an integration development stream, and then a development stream for each developer to utilize. That way you each have your own playground and can move your changes to the integration stream once they are complete. Those completed changes can then be merged down to the other developer streams.
I have been tasked with researching how to improve the way my company handles version control.
Background
Currently we use Borland StarTeam, which has some issues. Apart from often being difficult to use, the number of tools (IDE support, code review, ...) which support it is very low.
Our company has something like 40 developers but we work with a lot of different projects. A given project usually has something like 3-6 software developers working together.
Our projects range from (mostly) embedded systems and FPGA development to desktop applications.
The current work flow is heavily centralized with one "view" (which is close to a branch in StarTeam language) that everyone in the project works on.
One of the projects use multiple views in the following way:
There is a platform view where no development is done. This view then has two sub views for two specific products that share most code (via the platform view) but is dissimilar enough to be kept apart.
All development is made in the two product views and sometimes code from a product view is promoted to the platform view (which is then automatically available for the other product).
Another project seems to use a main view and a feature view when there was a major feature addition.
We usually have to support software for a long time and provide software updates.
Some of our products have a large number of different versions. The different versions will share most code but some parts are and must be distinctively different.
Developers use both Windows and Linux on their development work stations.
Idea
My idea is to switch over to use a modern DVCS. The work flow I am considering is where each project has a number of public branches which each developer can clone and work on. Each project could then determine if everyone can commit freely, or if we should have some kind of gate keeper system where code needs to pass a human or automated build system before being committed to the public branch.
My idea on the branching setup is to use release and feature branches as in the following scenario:
Let's say we start with development and finally ship version 1.0 of our product. We then find that we want some more features so we aim for a 2.0 release and start a new branch for this. While working on the 2.0 release branch we can still do maintenance on the 1.0 branch leading to the release of version 1.1, and so on.
While working on the 2.0 branch we discover a security problem which is fixed. Since it is available in the 1.0 branch as well that code is backported to the 1.0 branch as well.
Sometime in the 2.0 branch it is discovered that some parts of the system really needs to be completely redone to be able to create feature X. A new public 2.0-feature-X branch is created and worked on. When done, the work in that branch is merged back into the main 2.0 branch.
Actual questions
Hopefully you are still reading at this point :)
Is the above work flow (release and feature branching) a viable option? Are there pit falls to look out for?
In the scenario where a product has a platform branch and multiple product branches, what is the best way to handle this? Would creating a master branch and the product branches work? Is there a problem when two product branches diverge? How much can they diverge?
Have I missed something? I mostly see VCS from a developer perspective so I might be missing stuff that is important from the perspective of a configuration or release manager.
For your second question, I think you can SHARE the platform related code and "most code" shared by different products, and only BRANCH the source code which makes the products "dissimilar". With Share, if an item is modified in one project, the changes will be reflected in other projects simultaneously. With Branch, the file and its counterparts are independent.
So, the two product branches can be diverged as much as you need.
As an alternative to this question what is the best way to manage custom versions of software for a particular client?
Most of the differences between client releases is changes to the user interface to customize the software to look like it is owned by the client. More often then not, this is a simple logo change. Occasionaly the color scheme will change as well. But there are occassions where features will be enabled or disabled based on the client. What is the best way to keep all of these releases up to date and make them easily available to the users of a particular client?
At this point we have five different clients and each has their own build of the software and their own installer (complete with their logo in the installer). This is becoming a pain to manage, and it will only get worse as more and more clients start using our software.
So assuming the linked question isn't the way to go, what is the best way to manage these releases?
"This is becoming a pain to manage,
and it will only get worse as more and
more clients start using our
software."
The only way to really solve this part is to make sure your software has an architecture that supports the customizations as a layer on top of your core product. Ideally, they would simply be runtime configuration options (colours, logos and enable/disable are perfect for this). If you get (or want) a very large number of clients, push the configurability right into the core product and enable the clients to do the customizing themselves.
When updating, you build (and test) the core product once, and build the custom versions by simply linking to (referencing) the already-built core product as a library. You could have each client in a separate build, or you could have a single build process that generates updates for all the currently-maintained client builds (the latter is probably better for a larger number of clients). If you have a "vanilla" version, you could build that as part of the core or along with the client versions, it would depend on your particular case.
Depending on your technology, it might be possible to have the customization layer be built independently from the core product. In this case, client rebuilds will rarely be necessary (perhaps only for certain significant changes) -- you can simply link to the updated core product at runtime. For deployment to the client, you would only need to deploy the updated core, if you have a deployment method that supports this.
It's hard to say more detail without knowing your platform, but you've graciously kept this question agnostic.
Separate the common and the custom parts in your source tree. This can eliminate the great majority of merges, depending on your testing and release policies. There is always a way to abstract out and customize a build resource, even if your build process has to invoke script to rewrite some file.
Judicious use of branching in a good Source Code Management system. These aren't called "Configuration Management" systems for nothing. They are the tools optimized for precisely this task, so you're probably not going to get anything better without building on top of one.
Subversion is good at setting up multiple branches, but last I checked it could only do the 3-way merge on a single file at a time. Perforce is awesome in this department because it tracks your branching history on a file-by-file basis and uses this to automate merging of whole sets of changes between whole branches. It really is the cat's pajamas here.
Git and darcs may have similar power, but I haven't used them. They seem to be based on the idea that each working checkout tree will have a copy all changes ever since the beginning of time. That sounds impractical to me since I need to keep some large and changing SDKs under SCM control.
Arguably, the only difference needs to be a branch of whatever release you have, with the customer-unique changes in it. So for example:
/project
/trunk
/branches
/release-v1
/customer-branches
/release-v1-google
/release-v1-microsoft
....
Where your client releases are branches of your customer releases. Since these branches won't ever get rolled up into trunk or another release branch, don't pollute the regular development /branches tree.
I guess it depends on the level of customization you need for each client, but could you make your base app "customize" itself based on a config file?, so you could have the trunk being the full app and then have special config files for each customer that control the look & feel, as well as features that are enabled, and your release process would take the correct config files to deploy in your installers.
Seems that if you are always delivering custom(ish) versions of your app for each client, it would be worth the time to extend the app in this way.
I set up a header file called branding.h which contains a bunch of #ifdefs like the following example to change whatever bits need changing. In Visual Studio, it is easy to set up multiple builds with the appropriate client symbol defined.
#if defined BRAND_CLIENT1
# define COMPANY_NAME "Client 1"
# define PRODUCT_NAME "The Client 1 Widget App"
# define LOGO_FILE "res/logoClient1.ico"
#elif defined BRAND_CLIENT2
# define COMPANY_NAME "Client 2"
# define PRODUCT_NAME "The Client 2 Super Widget App"
# define ENABLE_EXTRA_MENU
# define LOGO_FILE "res/logoClient2.ico"
#endif
This is all assuming C++ of course.
I'm working on a project that will (soon) be branched into multiple different versions (Trial, Professional, Enterprise, etc).
I've been using Subversion since it was first released (and CVS before that), so I'm comfortable with the abstract notion of branches and tags. But in all my development experience, I've only ever really worked on trunk code. In a few rare cases, some other developer (who owned the repository) asked me to commit changes to a certain branch and I just did whatever he asked me to do. I consider "merging" a bizarre black art, and I've only ever attempted it under careful supervision.
But in this case, I'm responsible for the repository, and this kind of thing is totally new to me.
The vast majority of the code will be shared between all products, so I assume that code will always reside in trunk. I also assume I'll have a branch for each version, with tags for release builds of each product.
But beyond that, I don't know much, and I'm sure there are a thousand and one different ways to screw it up. If possible, I'd like to avoid screwing it up.
For example, let's say I want to develop a new feature, for the pro and enterprise versions, but I want to exclude that feature from the demo version. How would I accomplish that?
In my day-to-day development, I also assume I need to switch my development snapshot from branch to branch (or back to trunk) as I work. What's the best way to do that, in a way that minimizes confusion?
What other strategies, guidelines, and tips do you guys suggest?
UPDATE:
Well, all right then.
Looks like branching is not the right strategy at all. So I've changed the title of the question to remove the "branching" focus, and I'm broadening the question.
I suppose some of my other options are:
1) I could always distribute the full version of the software, with all features, and use the license to selectively enable and disable features based on authorization in the license. If I took this route, I can imagine a rat's nest of if/else blocks calling into a singleton "license manager" object of some sort. What's the best way of avoiding code-spaghettiism in a case like this?
2) I could use dependency injection. But generally, I hate it (since it moves logic from the source code into configuration files, which make the project more difficult to grok). And even then, I'm still distributing the full app and selecting features at runtime. If possible, I'd rather not distribute the enterprise version binaries to demo users.
3) If my platform supported conditional compilation, I could use #IFDEF blocks and build flags to selectively include features. That'd work well for big, chunky features like whole GUI panels. But what about for smaller, cross-cutting concerts...like logging or statistical tracking, for example?
4) I'm using ANT to build. Is there something like build-time dependency injection for ANT?
A most interesting question. I like the idea of distributing everything and then using a license key to enable and disable certain features. You have a valid concern about it being a lot of work to go through the code and continue to check if the user is licensed for a certain feature. It sounds a lot like you're working in java so what I would suggest is that you look into using an aspect weaver to insert the code for license checking at build time. There is still a going to be one object into which all calls for license checking goes but it isn't as bad of a practice if you're using an aspect, I would say that it is good practice.
For the most part you only need to read if something is licensed and you'll have a smallish number of components so the table could be kept in memory at all times and because it is just reads you shouldn't have too much trouble with threading.
As an alternative you could distribute a number of jars, one for each component which is licensed and only allow loading the classes which are licensed. You would have to tie into the class loader to achieve this.
Do you want to do this via Subversion ? I would use Subversion to maintain different releases (a branch per release e.g. v1.0, v2.0 etc.) but I would look at building different editions (trial/pro etc.) from the same codebase.
That way you're simply enabling or disabling various features via a build and you're not having to worry about synchronising different branches. If you use Subversion to manage different releases and different versions, I can see an explosion of branches/tags in the near future.
For switching, you can simply maintain a checked-out codebase, and use svn switch to checkout differing versions. It's a lot less time-consuming than performing new checkouts for each switch.
You are right not to jump on the branching and merging cart so fast. It's a PITA.
The only reason I would want to branch a subversion repository is if I want to share my code with another developer. For example, if you work on a feature together and it is not done yet, you should use a branch to communicate. Otherwise, I would stay on trunk as much as possible.
I second the recommendation of Brian to differentiate the releases on build and not on the code base.
I am a novice in the world of source/version control and I have been doing as much reading as physically possible to get my head around the different techniques that people use for their own source/version control.
One thing that I have noticed is a pretty distinct break in the methods of developers into two (possibly more?) groups: one group prefers to keep their trunk in an always-stable state and performs all maintenance and future development in the branches, while others prefer to do all of their development in the trunk and keep it in a not-so-stable state.
I am curious as to what the community here at StackOverflow prefers or if you have your own methods.
Note: If it would help tailor the answers, I should note that I am a single developer (at most there would be two or three others in the same project) who works primarily in ASP.NET and SQL Server 2005
As I'm sure you've noticed from searching the web for answers on this topic, this is one of those things where the best answer is "It depends.", and as most of the responses have indicated, it's a trade-off between how easy do you want to be able to commit/merge new code vs. managing an extensive version history that you can easily roll back for support or debugging purposes.
I work for a small company, which means that at any given time, we could have 3 or 4 different versions of code on developer machines that have not yet been committed to the repository. We use TortoiseSVN for our version control system, which gives us the ability to branch/merge without too much difficulty, as well as being able to view the update log or revert our local copies to an earlier revision pretty easily.
Based on your question, I suppose we would fall under the group of developers who attempts to keep, at all times, a stable Trunk, and we branch new code and test it before merging it back into the Trunk. We also make an effort to keep "snapshots" of each version release so that, if necessary, we can easily check out an earlier version and re-build it, without incorporating any new features intended for a future release (This is also a great mechanism for tracking down bugs, as you can use earlier versions of code to help determine when a particular bug was first introduced into your code. However, one thing to be careful of is if your application references common code that is maintained separately from your version-ed code, you will need to keep track of that too!).
On the repository, it ends up looking something like this:
Trunk
v1.0.1.x Release
v1.0.2.x Release
v1.0.2.x Bug-Fix A <-- (These get merged back into Trunk, but remain on the repo)
v1.0.2.x Bug-Fix B
v1.1.1.x Release
v1.2.1.x Development <-- (This will get merged back to Trunk, and replaced by a Release folder)
v1.2.1.x New Feature A <-- (These get merged back into the Development branch)
v1.2.1.x New Feature B
When I first started at the company, our version structure was not quite as sophisticated, and in my experience, I would say that if you have any need whatsoever to keep track of earlier versions, it is will worth the effort to put something like this together (like I said earlier, it doesn't have to look exactly like this, so long as it fits your individual needs), keep it well documented so that all contributors can maintain it (the alternative is that the creator ends up "babysitting" the repo, which quickly becomes an incredible waste of time), and encourage all your developers to follow it. It may feel like a lot of effort in the beginning, but you'll appreciate it the first time you need to take advantage of it.
Good luck!
I do all my development in the trunk. I'm a single developer and don't want to deal with the hassle of branching. When my code is stable I just tag that current version. For example I'd tag version 1.0, 2.0 beta, 2.0 release candidate 1, version 2.0, etc. Branching would probably a better alternative if you’re maintaining old versions for bug fixes and support but since I don't do this I don't worry about it.
The differences may have to do with how painful merging is or isn't in a given version control system.
With git, branching and merging is practically effortless, so it's a common workflow for me to keep my master clean and do all my work in branches. Branching and merging in svn, particularly in previous versions, isn't quite so cheap and easy, so when I was using svn I tended to work directly on the trunk.
Always stable. Even if I'm a single developer -- almost especially if I'm a lone developer.
Having a broken tree to me means one less way to know what I should be doing.
Big changes go in branches, as well as stable releases, and do the smallest unit of changes possible at any given point so as to keep moving forward at a good pace.
This is the methodology which we follow:
Any stable release should be taken from the trunk. Any further work or modifications should go inside the working branch and should be merged with trunk when ready to release.
If have multiple independent developments, each group should have there on branch which they should sync with trunc periodically and merge it back to trunk when ready.
I've always used the main trunk as head of code. Generally new development code goes in there.
We branch for releases and we may branch for a "big" destabilizing experiment.
When we make bug fixes they go into in main first and then they get merged (back-ported) into the appropriate version branch if required.
If the big experiment works out it get's merged back into main.
We use tags for build numbers in the version branches and the main. That way we can get back to a specific version and build if we have to.
I'm in for the always-stable trunk. You need to be able to rebuild the latest stable version at any time...
In your case, I'd strongly recommend avoiding a lot of branching. It's really a fairly advanced process and not necessary for small projects and small teams.
Try and keep it simple to start with, I always try to have a known working build that can reproduced for testing and deployments etc. Depending on your repository you could use revision number (SVN), or just label the known working versions as they are required.
If you find you have multiple people touching the same files then you will need to consider a branching strategy, other than that for such a small dev team it will just be un-necessary overhead...(IMO)
One aspect is how long will the changes be in an unstable state.
When a change I make might affect other people, or the nightly build, then I do my work on a branch, and merge when stable.
When the changes I make won't affect other people (because it is my private code at home, rather than code at work), then I'm OK with checking in non-working intermediate states if that's what I want. Sometimes, I'll make a few checkins in a row which are not stable; that's OK for me when it is just me who is affected and the workflow will be continuous. It's if I come back in a few years time (as opposed to just a few days) and things aren't working that it gets problematic (one disadvantage of having been around as long as I have - I do have some projects that are still in development and maintenance that are old enough to vote).
I use a variant of tagging to achieve repeatable builds - so if I need to go back to a stable version for a bug-fix, I can use the tag information to do that. It is crucial to be able to get a stable version on demand.
One key distinction is how big files tend to be on average. Big files (1000 lines +) tend to have many independent changes that are trivially automatically mergeable. So the fact that someone else is actively changing a file you are about to start work on is probably uninteresting, so it is ok if the system makes that hard to discover.
So you tend to end up a VC strategy that has a lot of branches, and easy merges. New functionality is written in new branches.
If you are working with the smaller, highly-cohesive files typical of an OO design, in a language like Java, such accidental conflicts are a lot rarer. Even as an artificial example, it is pretty hard to come up with two sets of changes that can be made to a class (and corresponding JUnit test cases) that can sensibly be made in isolation and then automatically weaved back together by a text merge tool.
If you do a lot of refactoring (renaming and splitting files) then that stresses out the merge tool even more.
So you tend to be best off with a VC strategy that has an identifiable and usable stable trunk and minimal branches.
In the first approach, new functionality is written in new branches, and merged when complete. In the second, it is written in new files, and enabled when complete.
Of course, if you do the second, you definitely need strong protection from the baseline becoming unusable for any length of time (i.e. continuous integration and a strong automatically-run test suite).