All version control systems have to solve the same fundamental problem: how will the system allow users to share information, but prevent them from accidentally stepping on each other's feet? It's all too easy for users to accidentally overwrite each other's changes in the repository.
Version control systems usually manage to keep track of changes and merge them together appropriately. However, there are cases when users do overlapping changes and the system cannot resolve the contradictory changes. This situation is called a conflict, and it's usually not much of a problem. When a user asks his client to merge the latest repository1 changes into his working copy2, his copy of file with conflicting changes are somehow flagged as being in a state of conflict: he'll be able to see both sets of conflicting changes, and manually choose between them. Note that software can't automatically resolve conflicts; only humans are capable of understanding and making the necessary intelligent choices. Once the overlapping changes are (manually) resolved - perhaps after a discussion with the party who made the conflicting changes - the merged file can safely be committed into the repository.
One way to avoid conflicting changes in files is to introduce locking of the repository while someone updates files3. This will prohibit concurrent changes of files, and keep conflicts to a minimum, but at the same time it becomes a nuisance since only one person in the team can make changes at the time. Of course, others can also work on the project and wait until they get to lock the repository for their commits, but after that they checked (sometimes without the support of a version control system) that their changes does not contradict other changes made before they got the locking power.
In the end, it all comes down to one critical factor: communication. When users communicate poorly, both syntactic and semantic conflicts increase. No system can force users to communicate perfectly, and no system can detect semantic conflicts. So there's no point in being lulled into a false promise that a locking system will somehow prevent conflicts.
Of course, if you need to go back and fix bugs in previous releases of your software, you will need to checkout the revision used for that release, and make necessary changes and store the changes as a branch in the subversion tree.
Branching using subversion as suggested by the subversion book:
To avoid branches to grow to far apart from each others, the feature branches must be kept in sync with the trunk. We require that branch synchronisation is performed regularly (once every week) against the trunk. Remember to write proper log messages to keep track of merges.
When the development branch is kept in sync with the trunk it is straight forward to port the branch back to the trunk since all differences between the branch and the trunk are readily made in the branch. Basically, all that needs to be done is to merge by comparing the branch with the trunk.
The solution to this problem is to use vendor branches. A vendor branch is a directory tree in the version control system that contains information provided by a third-party entity, or vendor. Each version of the vendor's data that is decided to be absorbed into the project is called a vendor drop.
Vendor branches provide two key benefits. First, by storing the currently supported vendor drop in the version control system, the members of the project never need to question whether they have the right version of the vendor's data. They simply receive that correct version as part of their regular working copy updates. Secondly, because the data lives in the subversion repository, we can store your custom changes to it in-place - there is no more need of an automated (or worse, manual) method for swapping in customisations.
Managing vendor branches generally works like this. Create a top-level directory (such as /vendor) to hold the vendor branches. Then the third party code is imported into a sub-directory of that top-level directory. This sub-directory is copied into the main development branch (for example, /trunk) at the appropriate location. Local changes are always made in the main development branch. With each new release of the code we are tracking we bring it into the vendor branch and merge the changes into /trunk, resolving whatever conflicts occur between local changes and the upstream changes.
It's important to note that working copies do not always correspond to any single revision in the repository; they may contain files from several different revisions. This happens if you commit a changed file, this file will get a new revision number while the rest stays at their current revision. The revision discrepancy will also happen if you svn update specific items in your working copy. To bring everything on par with the latest repository revision you must do an svn update in working copy root directory level.
Once you've finished making changes, you need to commit them to the repository, but before you do so, it's usually a good idea to take a look at exactly what you've changed. By examining your changes before you commit, you can make a more accurate log message. You may also discover that you've inadvertently changed a file, and this gives you a chance to revert those changes before committing. Additionally, this is a good opportunity to review and scrutinise changes before publishing them.