可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I just introduced SVN in our company for our Visual Studio projects and created a repository that looks like this ("solution" is Visual Studio solution, containing 1..n projects):
/solution1/trunk/projectA/...
/projectB/...
/solution2/trunk/projectC/...
/customerX/solution3/trunk/projectD/...
/solution4/trunk/projectE/...
/projectF/...
Now, I have two options to structure the local working directories:
Option A: Let the user checkout each solution separately using AnkhSVN, leading to a structure like this:
/solution1/projectA/...
/projectB/...
/solution2/projectC/...
/solution3/projectD/...
/solution4/projectE/...
/projectF/...
or this, if I tell the user to manually create a customerX subdirectory:
/solution1/projectA/...
/projectB/...
/solution2/projectC/...
/customerX/solution3/projectD/...
/customerX/solution4/projectE/...
/projectF/...
Advantage: The user can checkout only the solutions that he really needs. Disadvantage: Every solution needs to be checked out/updated separately.
Option B: Tell the user to checkout the whole repository using TortoiseSVN, leading to a structure that is exactly the same as the repository:
/solution1/trunk/projectA/...
/projectB/...
/solution2/trunk/projectC/...
/customerX/solution3/trunk/projectD/...
/solution4/trunk/projectE/...
/projectF/...
Advantage: It's very easy to "svn update everything". Disadvantage: The user also has a local copy of all branches and tags.
QUESTION: Since some projects are shared between solutions (let's say, e.g., that projectA is a library which is also used by solution3), we need to fix one directory structure, to make sure that the relative paths in the solution files are correct. Which option do you recommend and why?
EDIT: Thanks for all your excellent answers, in particular for mentioning svn:externals
and for stressing the importance of a good repository design. I ended up updating my repository structure:
/trunk/solution1/projectA/...
/projectB/...
/solution2/projectC/...
/customerX/solution3/projectD/...
-svn:external to projectA
/solution4/projectE/...
/projectF/...
which ensures that a developer working on solution3 only needs to check out solution3 (and not solution1) and the solution can be checked out to any directory, i.e., the working directory does not need a fixed structure.
回答1:
Hehe, this is probably not very helpful, but... neither. :)
I would have trunk
at the very top level, with the projects and solutions organised underneath that alongside each other in a flat structure. Then I would use the svn:externals
property on the solution directories to pull in the appropriate projects to the correct location in each developer's working copy.
The reason I'd organise things this way is that it gives you the benefits from both your option A and your option B. So, if developers only want to check out a single solution, they are free to do so. Likewise they can also check out the entire trunk if they'd rather do that instead (and they are able to do so without getting tags and branches).
Also, this approach of having a single trunk makes it far easier to tag or branch the entire repo, if ever you need to do that.
回答2:
Option A - you do not want to be pulling the whole repository down (all the tags and branches) every time and it will encourage your users to think of the whole repository as a single entity which it isn't really - you want them thinking in terms of solutions and of tagging/branching in that context.
You address shared projects by referencing them as externals in the "root" of the appropriate solutions. This will mean that you may have the same project appear multiple times on your HDD but that's manageable.
There's a teeny bit more on the subject here:
HowTo: Reference external SLN files with TeamCity
回答3:
For what it's worth, we use option B.
We also use Tortoise SVN rather than Ankh SVN because we have a bit better flexibility with the structure of our repository if it's not tied to the same directory structure that Visual Studio expects.
I was initially vehemently opposed to this because I liked the IDE integration I had with TFS, but after working with it for just a few days, I was sold that the trade off of greater flexibility is thousands of times more important than the integration with the IDE.
Edit - Added
It's also worth noting that prior to switching to our current processes, we mapped out exactly how we wanted to lay out ALL of our source control. We took several weeks to plan it exactly, analyzing it to death before making the switch, but it paid off in ease of use and maintenance.
We have an overall structure like the following:
\Internal Web Apps
\Internet Web Apps
\Corporate WinForms Apps
\Corporate Widows Services
\Retail Location WinForms Apps
\Retail Location Services
\Shared
\Cross-Platform Solution files.
Each of the main folders contains many different projects and solutions. These each have their own branches, tags, and trunks. So for example, if we have an Internet Store finder, it might be in
\Internet\<our company name>.com\Store Finder\Trunk
The important part of this is the Shared, as this contains code that is used in ALL of the other branches. The reason that having IDE integration doesn't work for us is that we would need a solution at root level to accomplish this. Instead, we have our Sln files where appropriate and since we all have a full copy of the repository, we can ensure that the relative paths to any projects in the \Shared directory is the same on all developer's PC's.
I provided the above, not to tell you how to structure your code, but just to give you ideas and to stress how important it is to plan thoroughly before proceeding.
You need to spend some time asking questions like "If I lay it out like Y, will I be able to do X?". Your situation will be unique to your team and company.
回答4:
I would strongly second Phil Booths solution of using a flat directory structure and using the svn:externals
property in include shared projects.
The main reason is that this gives you the freedom to decouple how different client projects using a shared project, such as a library, are updated. With your proposed structure, there is only one copy of the shared library project used by all the other client projects: thus all projects using the shared project must see the same version. This is not always desirable.
Sometimes, changes to a shared library will require corresponding changes in the client code using that library. With your proposed structure, such a change would require you to update all the client projects of the library at once, or live with the fact that many of the client projects might be broken.
Using svn:externals
for each client project using a library, means that each of the clients will have its own copy of the library in a working copy (but disk space is cheap). However, there is still on one copy of the library project in the repository (client projects just refrence a different version of it. Thus a particular client project can continue to use the old version of the shared library, or it can be updated (by updating the svn:externals
property) to use a newer version.
In summary:
In your proposed layout: committing a change to a library project immediate changes all the projects that use the library. All client projects get updates to the library, whether they want them or not.
With svn:externals
, committing a change to a library project only affects the library project alone. Each client project requires an additional commit to update the svn:externals
property to refer to the newer version of the library (wich can be committed along with the correspondign changes to the client projec's code). All client projects can have updates to the library, but they only get them when they explicitly ask for them.