Proper usage of Tags in SCM - version-control

My co-workers and I are having an argument over the value and usage of Tags in release/SCM systems. We're looking to the StackOverflow community to put in their thoughts to help us resolve the issue.
One side claims that Tags are a valuable addition to release management. An example of their use: we do a Maven release, which makes a new Tag (call it 1.0) which is code snapshot used for this release. This Tag should be a READONLY branch. When a bug needs to be fixed we can make a copy of the Tag into a new Branch (call it 1.1). Bug fixes go there. These fixes may be merged back into Trunk so that the main dev branch gets the bug fixes. Finally, 1.1 is released and a Tag 1.1 is automatically created. This cycle continues. The main benefit here of the Tag is that if you ever need to re-release version 1.0 for any reason, you can just release the Tag 1.0 with the confidence that it's never been altered by anyone. Also, saying "Release Tag 1.0" is cleaner than saying "Release revision 1 of branch 1.0 which is the original 1.0 without the fixes".
The other side claims that Tags aren't providing any valuable benefit, especially in a system like Subversion with global revisions, which act like a Tag in CVS. Plus, Subversion only gives a warning when committing to a Tag; it doesn't actually stop it. Their method is developing in Trunk and upon release you'd make a Branch called 1.0. You'd continue bug fixes in Trunk and if you needed to re-release those bug fixes to production, you'd merge them into 1.0 Branch and re-release 1.0. At some point, perhaps after major fixes or features in Trunk, you'd release and make Branch 1.1. Cycle continues. If you ever need to release the original 1.0 version, you'd have to check out Branch 1.0 revision 1.
Clearly both methods work. I'd like to hear the community's thoughts on which method is preferred and why.
Edit: I'm a little worried that the "best" way depends on the underlying SCM system. Either settle on Subversion for answers or if possible keep it SCM agnostic.

From an SCM agnostic point of view, a tag is very different from a revision.
Both may be implemented in the same way, both represents a "time line", but their goal is different:
a tag represent an immutable state where all files are referenced by a unique id. It is a name representing many things but mainly a stable state, ...)
a revision represent a commit transaction (not all SCM have those, especially the old ones with a 'file-by-file approach'). All commits do not represent a "stable" state (as in "compile" or "execute" successfully). They are just a new element of the global history.
The problem with SVN is that revision, tag and branches are all implemented the same.
But I would still prefer the option where a tag is used as a "read-only" branch.

In my opinion tags are useful. There will be times at some point in the life of the project that you come across a bug or a change and you want to know if it was there in a previous release. There will be reasons to compare code from one release to another to measure efficiencies both in performance and actually the development of the code.
Sure, there is a chance you can screw it up, but it can always be undone. There really is no reason not to, and there are several reasons why it might be useful in the future. To me its a no-brainer.
I agree that you should also be using branches and doing your development there, but anytime you actually release something, make a tag out of it.

Yes, you want to use tags.
Think of a tag as just a label or a name for a particular revision. It is very helpful in my experience to tag important milestones in a project, whether it's for production release or even for interim QA releases. You often will want to go back in time and see the source code for a particular release.
If you branch upon release, you can always figure out which revision was released to production, but this is kind of a pain compared to just looking at a tag. If you don't use release branches then it will be easy to lose track of which revision was used to create a particular build.
The problem with svn is that it blurs the distinction between tags and branches. Anyone can always commit to a tag, so it's not guaranteed to be fixed/immutable. In other VCS like PVCS, a "tag" is unchangeable. You can adopt a team convention to prevent commits to tags, or even maybe use commit hooks to prevent commits to tags.

We use tags (labels) when creating new baselines. We do it once a week, but some teams do it even several times a day.
The point (for us) is always making sure the new baseline is stable: so it's not just a build, is a build that passes the entire testsuite, several hours of automated tests plus potentially manual exploratory ones too.
Then the baseline is used as starting point for all tasks during the next iteration: every new task is a new branch starting from the baseline, which is known to be stable so whatever is broken in the task should be easy to trace inside the task itself.
Normally we only put tags (labels) on the main branch (or trunk or master depending on your SCM flavour) which is the integration point for all the other branches.
When we release an official product we create a "release branch for it" so it will only receive fixes while new development stays on "main". Then these "maintenance branches" (hopefully only one or two at a time) can be tagged too.

I like to think about tags as "just a fancy name for a revision". I've always thought about them that way, and IIRC in mercurial they are just that. In subversion however, as you say, they indeed are (cheap) copies of trunk/* to tags/fancy-name/
Honestly, I'd combine the two strategies for optimal results: tag and branch upon release. Your tag is called 1.0.0, branch 1.0-MAINT. Bugfixes go into branches, and bugfix releases are tags again (1.0.1 may by a tag intended to alias 1.0-MAINT at a certain point.)
Do not forget however that tags and branches in subversion are actually the same thing: cheap copies. The only difference between them is the semantics you/your team attributes to them, so it pretty much boils down to getting people to agree on one particualr method and stick to that (might be enforced on the server, eg disallowing commits in tags/ except for release coordinators etc.)
The problem I see though with the second approach is: how are you going to make an easy distinction between software in the field if you re-release 1.0? That means that you may have a 1.0 and another 1.0 actually referring to a different code base... .

Immutable snapshots of a project's source code (and executable) are invaluable for doing testing of any kind, whether structured testing or field usage. For structured testing, you're going to be creating data that might be referenced months or years in the future. Anytime you revisit that data, Murphy's law says you'll need to know what code it comes from and unless you went to the trouble of citing a particular snapshot of the source code, it will be impossible to tell with confidence what source code corresponded to that test data.
I can't tell you how many times someone's come to me and said "This microcontroller code's not working, can you help?" and I ask them, "What version are you using?" and they say "I'm not sure" because they're not doing good release management (at the very least putting a sticker on the device, better to put versioning info in EEPROM that can be queried in realtime). >:(

In SVN, the technical difference between using a tag and tracking a revision is nil. I find myself minimizing tag use based on how SVN's implementation is simply a cheap copy and clutters up your "structure space".
The real difference comes when communicating a particular baseline to a large team of developers. Revision tracking brings an extra layer of abstraction that can become a source of errors. And as we're all aware, when you're dealing with 50+ developers, any source of error will become an area of confusion and wasted time. A verbose tag can eliminate that confusion and remove any doubt as to what a baseline's purpose is.

I'd combine both approaches. Whenever you make a release, tag it. Tags should never change, so the presence of a "1.0.0" tag is an indicator that you shouldn't be trying to release anything else as 1.0.0.
At the same time, when it came time to do 1.0.0, I'd put it onto a 1.0 branch. So the flow is: branch trunk to 1.0, tag this new 1.0 as 1.0.0, and deploy. Then bug fixes can be done on the 1.0 branch (to avoid getting mixed up with any 1.1-targetted development that may already be on trunk now) and merged into trunk. Each release of the fixed 1.0 is tagged as 1.0.x from the 1.0 branch. This is basically the approach we use at work with Perforce, and that's very similar indeed to Subversion. (Reading through the replies, I think it's virtually identical to Vincent's recommendation)
As far as the comment about tags being redundant because you have revision numbers--- that's largely true, except that tags also specify a scope: i.e. which files in the repository are covered by the tag. You can reasonably ask someone to look at /svn/proj1/tag/1.0.0 and they are immediately looking at a coherent workspace. If you ask them to look at revision X, they have to first look at revision X to see that it was changing (say) /svn/proj1/trunk/Makefile and hence deduce that /svn/proj1/trunk/#X is what they should be looking at. What happens if revision X touched files in proj1 and proj2? Which is of course evil, but strictly speaking you should be saying /svn/proj1/trunk/#X. And where is the list of revision numbers stored? How do we know that 1.0.0 is revision X? It should IMHO be possible to determine that just from the repository.
In systems like Git, tags and branches are still basically the same thing (just references to the object database), but the convention is that tag refs don't change, and branch refs do (and preferably with a specific constraint on how they change). Perforce also has "labels" which are ways of grouping a set of file revisions together independently of a changelist; which is essentially a tag, but more confusing: historically we've used changelist numbers (equivalent to Subversion revision numbers) qualified with the name of the branch they should be on to identify versions. The two are almost identical any way, so here I guess TMTOWTDI.

Related

Branching and Merging Strategies

I have been tasked with coming up with a strategy for branching, merging and releasing over the next 6 months.
The complication comes from the fact the we will be running multiple projects all with different code changes and different release dates but approximately the same development start dates.
At present we are using VSS for code management, but are aware that it will probably cause some issues and will be migrating to TFS before new development starts.
What strategies should I be employing and what things should I be considering before setting a plan down?
Sorry if this is vague, feel free to ask questions and I will update with more information if required.
This is the single best source control pattern that I have come across. It emphasizes the importance of leaving the trunk free of any junk (no junk in the trunk). Development should be done in development branches, and regular merges (after the code has been tested) should be made back into the trunk (Pic 1), but the model also allows for source to be patched while still under development (Pic 2). I definitely recommend reading the post in its entirety, to completely understand.
Pic 1
Pic 2
Edit: The pictures are definitely confusing without words. I could explain, but I would basically be copying the original author. Having said that, I probably should have selected a better picture to describe the merge process, so hopefully this helps. I'd still recommend reading the post, however:
The simplest and most usual way I've seen branching work is off two premises. Trunk and Release. I think this is known as the "Unstable trunk, stable branch" philosophy.
Trunk is your main source. This contains the "latest and the greatest" code and is forward looking. It generally isn't always stable.
Release is a one-to-many association with trunk. There is one trunk but many releases that derive from the trunk. Releases generally start with a branch of the trunk once a particular functionality milestone has been hit so the "only" things left to go in for a particular deployment should just be bug fixes. You then branch the trunk, give it a label (e.g. 1.6 Release is our current latest Release), build and send the release to QA. We also push the version number (usually the minor number) of the trunk up at this point to ensure we don't have two releases with the same number.
Then you begin the testing cycle on your release branch. When sufficient testing has been perfomed you apply bug fixes to the release branch, merge these back to the trunk (to ensure bug fixes are carried forward!) and then re-release a build of the branch. This cycle with QA continues until you are both happy and the release is finally given to the customer(s). Any bug reports from the customer(s) that are accurate (i.e. they are a bug!) start another QA cycle with the branch in question.
As you create future releases it is a good idea to also try to move older customers onto newer branches to reduce the potential number of branches you might have to back-patch a bug fix into.
Using this technique you can deploy solutions using your technology to a variety of customers that require different levels of service (starting with least first), you can isolate your existing deployments from "dangerous" new code in the trunk and the worst merge scenario is one branch.
My first recommendation would be to read Eric Sink's Source Control HOWTO - specifically the branches and branch merge chapters.
We have 3 containers - DEV, MAIN, and RELEASE for our work. MAIN contains all our "ready-to-release" code and we tend to think of it as "basically stable." DEV/Iteration (or DEV/Feature, or DEV/RiskyFeatureThatMightBreakSomeoneElse) are branches from MAIN and are merged up when the Iteration/Feature is ready to promote up past the DEV environment. We also have TFS builds set up from the DEV/Iteration branch and the MAIN branch.
Our RELEASE container contains numbered releases (similar to the "tags" container used in many Subversion repositories). We simply take a branch from MAIN each time - I like to say we're "cutting" a RELEASE branch to signify this shouldn't have a lot of activity going on once the merge is finished.
As for VSS->TFS - Microsoft supports an upgrade path which should keep your version history, but if you don't need it the history, I would just get the latest version from VSS, check it into TFS and archive the VSS repository.
One final tip - get your team members familiar with source control. They must understand branching and merging or you will be stuck doing a lot of cleanup work :).
Good luck!
The subversion book describes some common branching patterns. Maybe you can also apply these to TFS.

When to use a Tag/Label and when to branch?

Using TFS, when would you label your code and when would you branch?
Is there a concept of mainline/trunk in TFS?
A label in TFS is a way of tagging a collection of files. The label contains a bunch of files and the version of the file. It is a very low cost way of marking which versions of files make up a build etc.
A branch can be thought of as a copy of the files (of a certain version) in a different directory in TFS (with TFS knowing that this is a branch and will remember what files and versions it was a branch of).
As Eric Sink says, a branch is like a puppy. It takes some care and feeding.
Personally, I label often but branch rarely. I create a label for every build, but only branch when I know that I need to work on a historical version or that I need to work in isolation from the main line of code. You can create a branch from any point in time (and also a label) so that works well and means that we don't have branches lying around that are not being used.
Hope that helps,
Martin.
In any VCS, one usually tags when you want a snapshot of the code, to be kept as reference for the future. You branch when you want to develop a new feature, without disturbing the current code.
Andrew claims that labeling is lazier than branching; it's actually more efficient in most cases, not lazy. Labeling can allow users to grab a project at any point in time, keep a history of files changed for a version or build, and branch off of/work with the code at any point and later merge back into the main branch. Instead of what Andrew said, you're advised to only branch when more than one set of binaries is desired- when QC and Dev development are going on simultaneously or when you need to apply a hotfix to an old version, for example.
I always see labels as the lazy man's branch. If you are going to do something so significant that it requires a full-source label then it is probably best to denote this with a branch so that all tasks associated with that effort are in an organized place with only the effected code.
Branching is very powerful however and something worth learning about. TFS is not the best source control but it is not the worst either. TFS does support the concept of a trunk from which all branches sprout as well.
I would recommend this as a good place to read up on best practices - at least as far as TFS is concerned.

Best practices, building trunk against trunk?

We have many projects that use a common base of shared components (dlls).
Currently the development build for each project links against dlls built from the trunk of the components. (ie trunk builds use the dlls from other trunk builds)
When we do a release build, we have a script that goes through the project files and replaces the trunk references to specific numbered versions of the components (that are built from a tagged branch)
I think this weakens the testing that we do during development because the project that I am actually working on is using diferent dlls to what the release build will be using. I would like to always develop against the numbered versions of the components and only ever update them when there is a specific need.
However others in the team argue that unless we develop against trunk (and update to the newer versions of the components with each release) we will have the problem that (a) our products will hardly ever update to the newer version of the components then (b) when we do need to update it will be a huge task because the component source/interfaces will have changed so much.
What practices do you follow, and why?
Edit: Sorry all, I have just realised I have confused things by mentioning that there are several main products sharing components - although they share the components they don't run on the same PCs. My concern relates to the fact the because the components are likely to change with each release of a product (even though there was no specific requirement to update the component) that testing would miss some subtle change that was done in a component and not related to the specific work being done on the product.
Hmm, I may be in a minority here, but this comes down to release management.
Developing against the trunk of a set of shared components means, by definition, that the components are a "moving target" -- a developer using those shared components won't necessarily know if a newly found defect or failure is due to the project code or the shared components, which leads to a loss of productivity, IMNSHO.
The "shared components" have a release cycle all their own. Give your other developers a break and fix the version of the shared components that the projects are going to use and use tags, labels or branches to identify the shared component release. On the next iteration for the projects, bump up to the latest "stable" or "production" build of the shared components.
There's another "smell" here, if you'll pardon the expression. Having "shared components" whose "source/interfaces will have changed so much" between project releases sounds like the components aren't so solid or shouldn't necessarily be shared.
See also the answer to this question Shared components throughout all projects, is there a better alternative than svn:externals?
You should have strong interfaces that rarely change, so changing versions shouldn't be that hard.
Separating the versions and working against specific versions will increase overhead when you need to change, but it should also encourage less interface changes overall, which will help in the long term.
We develop against multiple branches and trunk simultaneously and we have chosen to build and test each branch with the code we'll be pushing out to production. I don't think it is safe any other way.
Basically, if a developer is working on trunk, all they have to do is worry about building from trunk and committing code to trunk.
Any developer working on a branch needs to build and test off that branch (there are multiple projects all branched/tagged the same build/release). When they commit changes to that branch, they must also merge those individual changes into trunk.
We expect all developers to be familiar with SCM (SVN) and to be capable of maintaining multiple branches of code. As a team we handle major framework shifts or huge code changes to minimize troublesome merging.
Two things here. First, I think you're right; you want to build against the most current development versions, not against the old versions. If you haven't already, you will see a situation in which the build-for-release blows up and you have to do an all-nighter cleaning up the diffs.
I'm personally a fan of the "commit to trunk, release from branch" model anyway. All commits go to the trunk, overnight builds or CI builds are against the trunk, and people create branches freely. When you have a trunk that meets acceptance criteria, tag a release candidate, BUT KEEP MAKING UPDATES TO THE TRUNK. If you hae a long release cycle, then you might have changes for release n+1 being added to the trunk, but ideally you should just shorten your release cycle instead. If there are changes to the trunk that shouldn't be in the released version, AND you have a problem that requires changes, create a branch against the tagged version --- and make sure you merge any changes back to the trunk once you have an actual release.
We are using the scons building system, and have our own file in the root directory which specifies what version of each library we're going to use when building the application.
That reduces the need to change version names in several locations like you mentioned.
Whether (b) is a valid argument depends on how often your shared components change and by how much. If they change often in your workplace, it might be a valid that you are "forced" to develop off the newest version. Whether that in itself is a problem is a valid question.
However, from your side of things, I don't see how you can push code into production without it being tested against the shared components being used in production. Do you do a second test cycle against the release build? Do you just pray that nothing breaks? Frankly, (b) can be reversed in these cases to support your point of view: If the trunk is different enough from the most recent tagged branch, then that effort has to be made to ensure your app works properly with it.
If your shared components are tagged often enough, then your colleagues are probably right, and it's easier to manage the incremental changes from the most recent tag to the trunk than it is to manage the change from arbitrary version X (determined at the last build) to arbitrary version Y (determined when you choose to upgrade).

The theory (and terminology) behind Source Control

I've tried using source control for a couple projects but still don't really understand it. For these projects, we've used TortoiseSVN and have only had one line of revisions. (No trunk, branch, or any of that.) If there is a recommended way to set up source control systems, what are they? What are the reasons and benifits for setting it up that way? What is the underlying differences between the workings of a centralized and distributed source control system?
Think of source control as a giant "Undo" button for your source code. Every time you check in, you're adding a point to which you can roll back. Even if you don't use branching/merging, this feature alone can be very valuable.
Additionally, by having one 'authoritative' version of the source control, it becomes much easier to back up.
Centralized vs. distributed... the difference is really that in distributed, there isn't necessarily one 'authoritative' version of the source control, although in practice people usually still do have the master tree.
The big advantage to distributed source control is two-fold:
When you use distributed source control, you have the whole source tree on your local machine. You can commit, create branches, and work pretty much as though you were all alone, and then when you're ready to push up your changes, you can promote them from your machine to the master copy. If you're working "offline" a lot, this can be a huge benefit.
You don't have to ask anybody's permission to become a distributor of the source control. If person A is running the project, but person B and C want to make changes, and share those changes with each other, it becomes much easier with distributed source control.
I recommend checking out the following from Eric Sink:
http://www.ericsink.com/scm/source_control.html
Having some sort of revision control system in place is probably the most important tool a programmer has for reviewing code changes and understanding who did what to whom. Even for single person projects, it is invaluable to be able to diff current code against previous known working version to understand what might have gone wrong due to a change.
Here are two articles that are very helpful for understanding the basics. Beyond being informative, Sink's company sells a great source control product called Vault that is free for single users (I am not affiliated in any way with that company).
http://www.ericsink.com/scm/source_control.html
http://betterexplained.com/articles/a-visual-guide-to-version-control/
Vault info at www.vault.com.
Even if you don't branch, you may find it useful to use tags to mark releases.
Imagine that you rolled out a new version of your software yesterday and have started making major changes for the next version. A user calls you to report a serious bug in yesterday's release. You can't just fix it and copy over the changes from your development trunk because the changes you've just made the whole thing unstable.
If you had tagged the release, you could check out a working copy of it and use it to fix the bug.
Then, you might choose to create a branch at the tag and check the bug fix into it. That way, you can fix more bugs on that release while you continue to upgrade the trunk. You can also merge those fixes into the trunk so that they'll be present in the next release.
The common standard for setting up Subversion is to have three folders under the root of your repository: trunk, branches and tags. The trunk folder holds your current "main" line of development. For many shops and situations, this is all they ever use... just a single working repository of code.
The tags folder takes it one step further and allows you to "checkpoint" your code at certain points in time. For example, when you release a new build or sometimes even when you simply make a new build, you "tag" a copy into this folder. This just allows you to know exactly what your code looked like at that point in time.
The branches folder holds different kinds of branches that you might need in special situations. Sometimes a branch is a place to work on experimental feature or features that might take a long time to get stable (therefore you don't want to introduce them into your main line just yet). Other times, a branch might represent the "production" copy of your code which can be edited and deployed independently from your main line of code which contains changes intended for a future release.
Anyway, this is just one aspect of how to set up your system, but I think giving some thought to this structure is important.

Branching Strategies [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 11 years ago.
The company I work for is starting to have issues with their current branching model and I was wondering what different kinds of branching strategies the community has been exposed to?
Are there any good ones for different situations? What does your company use? What are the advantages and disadvantages of them??
Here is the method I've used in the past with good success:
/trunk - bleeding edge. Next major release of the code. May or may not work at any given time.
/branches/1.0, 1.1, etc. Stable maintenance branches of the code. Used to fix bugs, stabilize new releases. If a maintenance branch, it should compile (if applicable) and be ready for QA/shipping at any given time. If a stabilization branch, it should compile and be feature complete. No new features should be added, no refactoring, and no code cleanups. You can add a pre- prefix to indicate stabilization branches vs maintenance branches.
/branches/cool_feature. Used for highly experimental or destructive work that may or may not make it into trunk (or a maintenance branch). No guarantees about code compiling, working, or otherwise behaving sanely. Should last the minimum time as possible before merging into the mainline branch.
/tags/1.0.1, 1.0.2, 1.1.3a, etc. Used for tagging a packaged & shipped release. Never EVER changes. Make as many tags as you want, but they're immutable.
Our repository looks like:
/trunk
/branches
/sandbox
/vendor
/ccnet
/trunk is your standard, bleeding edge development. We use CI so this must always build and pass tests.
/branches this is where we put 'sanctioned' large changes, ie something we KNOW will make it into trunk but may need some work and would break CI. Also where we work on maintenance releases, which have their own CI projects.
/sandbox each developer has their own sandbox, plus a shared sandbox. This is for things like "Lets add a LINQ provider to our product" type of tasks that you do when you are not doing your real work. It may eventually go into trunk, it may not, but it is there and under version control. No CI here.
/vendor standard vendor branch for projects where we compile but it is not code that we maintain.
/ccnet this is our CI tags, only the CI server can write in here. Hindsight would have told us to rename this to something more generic such as CI, BUILDS, etc.
One branch for the active development (/main or master, depending on the jargon)
One branch for each maintenance release -> it will receive only really small fixes, while all major development goes to /main
One branch for each new task: create a new branch to work on every new entry on your Bugzilla/Jira/Rally. Commit often, self document the change using inch pebble checkins, and merge it back to its "parent" branch only when it's finished and well tested.
Take a look at this http://codicesoftware.blogspot.com/2010/03/branching-strategies.html for a better explanation
The first thing: KISS (Keep it simple stupid!)
/branches
/RB-1.0 (*1)
/RB-1.1 (*1)
/RB-2.0 (*1)
/tags
/REL-1.0 (or whatever your version look like e.g. 1.0.0.123 *2)
/REL-1.1
/REL-2.0
/trunk
current development with cool new features ;-)
*1) Keep version maintainable - e.g. Service Packs, Hotfixes, Bugfixes which may be merged to trunk if necessary and/or needed)
*2) major.minor.build.revision
Rules of the thumb:
The Tags folder need not to be checked out
Only few coding in release branches (makes merging simpler) - no code cleanup etc.
Never to coding in tags folder
Never put concrete version information into source files. Use Place-holders or 0.0.0.0 which the build mechanism will replace by the version number you're building
Never put third party libraries into your source control (also no one will add STL, MFC etc. libraries to SVN ;-))
Only commit code that compiles
Prefer using environment variables instead of hard-coded paths (absolute and relative paths)
--hfrmobile
We branch when a release is ready for final QA. If any issues are discovered during the QA process, the bugs are fixed in the branch, validated and then merged to the trunk. Once the branch passes QA we tag it as a release. Any hotfixes for that release are also done to the branch, validated, merged to the trunk and then tagged as a separate release.
The folder structure would look like this (1 QA line, 2 hotfix releases, and the trunk):
/branches
/REL-1.0
/tags
/REL-1.0
/REL-1.0.1
/REL-1.0.2
/trunk
We use the wild, wild, west style of git-branches. We have some branches that have well-known names defined by convention, but in our case, tags are actually more important for us to meet our corporate process policy requirements.
I saw below that you use Subversion, so I'm thinking you probably should check out the section on branching in the Subversion Book. Specifically, look at the "repository layout" section in Branch Maintenance and Common Branch Patterns.
The alternative I'm not seeing here is a "Branch on Change" philosophy.
Instead of having your trunk the "Wild West", what if the trunk is the "Current Release"? This works well when there is only one version of the application released at a time - such as a web site. When a new feature or bug fix is necessary a branch is made to hold that change. Often this allows the fixes to be migrated to release individually and prevents your cowboy coders from accidentally adding a feature to release that you didn't intend. (Often it's a backdoor - "Just for development/testing")
The pointers from Ben Collins are quite useful in determining what style would work well for your situation.
Gnat has written this excellent break down on the various bits of advice your can find on branching strategies.
There's not one branching strategy, it's what works for:
Your team size
Your product and the lifecycle periods
The technology you're using (web, embedded, windows apps)
Your source control, e.g. Git, TFS, Hg
Jeff Atwood's post breaks down a lot of possibilities. Another to add is the concept of promotion (from Ryan Duffield's link). In this setup you have a dev branch, test bracnh and release branch. You promote your code up until it reaches the release branch and is deployed.
We currently have one branch for ongoing maintenance, one branch for "new initiatives" which just means "stuff that will come out sometime in the future; we're not sure when." We have also occasionally had two maintenance branches going on: one to provide fixes for what is currently in production and one that is still in QA.
The main advantage we've seen is the ability to react to user requests and emergencies more rapidly. We can do the fix on the branch that is in production and release it without releasing anything extra that may have already been checked in.
The main disadvantage is that we end up doing a lot of merging between branches, which increases the chance that something will get missed or merged incorrectly. So far, that hasn't been a problem, but it is definitely something to keep in mind.
Before we instituted this policy, we generally did all development in the trunk and only branched when we released code. We then did fixes against that branch as needed. It was simpler, but not as flexible.
The philosophy that we follow at work is to keep the trunk in a state where you can push at any time without drastic harm to the site. This is not to say that the trunk will always be in a perfect state. There will of course be bugs in it. But the point is to never, ever leave it broken drastically.
If you have a feature to add, branch. A design change, branch. There have been so many times where I thought, "oh I can just do this in the trunk it isn't going to take that long", and then 5 hours later when I can't figure out the bug that is breaking things I really wished that I had branched.
When you keep the trunk clean you allow the opportunity to quickly apply and push out bug fixes. You don't have to worry about the broken code you have that you conveniently branched off.
For Subversion, I agree with Ryan Duffield's comment. The chapter he refers to provides a good analyses on which system to use.
The reason I asked is that Perforce provides a completely different way to create branches from SVN or CVS. Plus, there are all the DVCSs that give it's own philosophy on branching. Your branching strategy would be dictated by which tool(s) you're using.
FYI, Svnmerge.py is a tool to assist with merging branches in SVN. It works very well as long as you use it frequently ( every 10-30 ) commits, otherwise the tool can get confused.
No matter which branching pattern chosen, you should try to keep your branches in a binary tree form like this:
trunk - tags
|
next
/ \ \
bugfix f1 f2
/ \ \
f11 f21 f22
Child nodes should only merge with the direct parent.
Try ur best to merge only the whole branch with the parent branch. never merge subfolders within a branch.
You may cherry pick commits when needed as long as you only merge and pick from whole branch.
The next branch in the above figure is only for illustration, you may not need it.