Is source control integration in Visual Studio .Net worse than in Visual C++ 6.0?
I have often heard this affirmation in forums and newsgroups. This article describes the scenarios that generated such affirmation and tries to explain that VS .NET behavior is in fact the correct one, and in fact if you run into problems that apparently put source control integration in a bad light the things are fixable easier than you may think…
How source control integration works
Let me start with a bit of technical information about the source control integration in Visual Studio. To connect to a source control provider, an IDE like VisualStudio uses the MSSCCI interface. In MSSCCI, the IDE opens a connection from a local folder (say C:\Projects\MyProject) to a folder in the scc database (say $/MyProject). Then, the IDE can call the scc provider passing in a “connection object” and filenames under this local connection root cone (say C:\MyProject\File.cpp) and can perform source control operations on them.
Visual C++ 6.0 and SourceSafe 6.0
SourceSafe 6.0 had a bug. If the IDE called with paths outside this local “cone” used by the connection (say C:\Projects\Common\Header.h), instead of rejecting the call immediately, SourceSafe 6 tried to construct a path from the $/MyProject and the..\Common\Header.h relative path of the file to the connection root. If there was a file in the scc database at $/Common/Header.h it allowed controlling the local file in this location. Basically, files outside of the connection root could be controlled through this connection, violating the MSSCCI rules.
Visual C++ 6.0 conveniently used this “feature” by not enforcing the MSSCCI rules. Let’s see an example. In VC6, Create new project in C:\Projects\MyProject. Now add the project to source control. Select all files in FileView, then use the Project/SourceControl/AddtoSourceControl command.
VC6 use by default $/MyProject. After completing the add to source control operation, the project will look like this:
If you’re curious and look in the MyProject.dsp file you’ll see lines like these:
# Begin Project
# PROP AllowPerConfigDependencies 0
# PROP Scc_ProjName ""$/MyProject", BAAAAAAA"
# PROP Scc_LocalPath "."
MyProject.dsw will also contain similar source control section storing the project bindings. Basically, this means that your project uses one connection to the source control database, with the C:\Projects\MyProject folder (‘.’ relative to the project file’s parent folder) bound to $/MyProject.
Add to the project a file outside this connection, say C:\Projects\Common\Header.h. VC will prompt to add this file to source control. If you accept the operation, SourceSafe will realize the file is outside of the bound connection, and will try to copy it in the current folder. Say No.
Notice the file remain uncontrolled (white icon in FileList), as it should be.
Now use WindowsExplorer and drag and drop C:\Projects\Common into $/ in VSS Explorer, adding the file in VSS database (Sometimes users see that VS/VSS can’t control the file so they try to “fix” this by mixing SourceSafe Explorer operations with VisualStudio integration without realizing this is not the right way of adding files to source control). You should now have in the local disk and VSS database a structure like this:
Back in VC6, close and reopen the workspace. Notice that all of a sudden, the Header.h file got a gray icon, sign of the file being under source control!
In conclusion, in VC6 + VSS6 you can control files outside of the connection root because VC6 does not enforce the connection rules (tries to use the connection with files outside of the connection) and because of a bug in VSS 6 (that it doesn’t verify and deny such calls in all situations).
Visual Studio .NET 2002, .NET 2003 and Visual Studio 2005 (with VSS 6.0c or older source control provider)
Visual Studio .NET enforces the connection rules. It won’t try to use a connection to the scc database with files outside of the local connection root bound to the database.
Let’s open the VC6 project with VS .NET. Use the File/Open/Project… dialog, browse to the C:\Projects\MyProject\MyProject.dsw file on disk and attempt to open the workspace.
VisualStudio .NET will prompt to convert the project to a new file format. In the end of the operation you’ll get a prompt to checkin the newly MyProject.vcproj and MyProject.sln files to source control. Agree with the checkin dialog and the files will be added to the source control database.
During conversion, the source control bindings established by VC6 are preserved (they are now stored in the vcproj and sln files instead of the dsp/dsw files). You can see the project bindings using the File/SourceControl/ ChangeSourceControl dialog. (If you’re using VS 2005 you can use the Columns button in this dialog’s toolbar and you can display the LocalBinding column, too).
After conversion you can see the Header.h file not controlled: it has no source control icon in SolutionExplorer and the context menu doesn’t allow any source control operations with this file.
This happens because the file is outside of the local folder C:\Projects\MyProject that is bound to the source control database.
As you can see, VisualStudio .NET does a better job in enforcing the MSSCCI connections, and won’t try to use a connection for source control operations on files that are outside of the folder bound through this connection to the source control database.
However, from the user’s point of view, this looks like a bug in VisualStudio: something that was controlled before has “lost” the source control status! It appears that source control integration in Visual Studio .NET is “worse” than in Visual C++ 6.0.
Fortunately this is not true. Visual Studio .NET allows to completely unbind the projects from source control (try that in VS6) and to change the source control bindings.
How to fix the bindings
The ChangeSourceControl dialog can be used to manually change and fix the bindings such that all project files can be controlled.
Open the File/SourceControl/ChangeSourceControl dialog, select the line or lines of the project containing non-controllable files, then click the Browse button in the dialog’s toolbar. SourceSafe will eventually prompt you with a dialog that allows choosing a project from SourceSafe database.
Notice in this dialog the “Working folder” read-only field. This tells you which local folder was calculated by VisualStudio as the local binding root of the selected project (or projects) – this is the closest local folder containing all the files in the selected projects. In my example, this folder was calculated as C:\Projects, the root of C:\Projects\Common\ and C:\Projects\MyProject which contains files in the selected projects MyProject and solution.
You will have to select a folder from the source control database that matches this local folder. In my example, this folder is the $/ folder, because the structure of the project on local disk relative to the C:\Projects unified root is similar to the project’s structure in the VSS database under the $/ folder.
So I select the $/ project in VSS database and click Ok button. If all is done correctly, VisualStudio will accept the connection as valid, and the ServerBinding column reflects this new binding.
Click Ok in the ChangeSourceControl dialog, accept any checkout prompts to the project and solution files, checkin the changes to these files. After this, the Header.h file will be controllable because it is is a folder (C:\Projects\Common) that is subfolder of the bound connection root C:\Projects.
Note: An alternative method to fix the project bindings is to use the Unbind button in the ChangeSourceControl dialog, close the dialog and accept saving the changes to the project files (the project will be uncontrolled now), reopen the dialog again, multiselect the projects of interest (with click the lines while holding Control or Shift key pressed) and this time use the Bind button. Again you’ll have to select the scc database folder matching the proposed local binding root, accept any changes to the project and solution file and checkin your changes. The result should be the same – you should be able to control the Header.h file.
VisualStudio 2005 and later with VisualSourceSafe 2005 or SourceSafe 6.0d
Too many users have complained about this issue, that Microsoft has decided to do something in VisualStudio 2005 to make life easier. When a VC 6.0 project is opened in VisualStudio 2005, and your source control provider is either Visual SourceSafe 2005 or SourceSafe 6.0d, VisualStudio will try to automatically fix the source control bindings for you at the time the workspace/projects are converted from the VC6 format to the VS2005 format.
When the workspace is opened, you may get additional login prompts from SourceSafe, sign that VS2005 is opening other connections to the scc database in an attempt to bind the folders to maximize the number of files that can be controlled.
If you accept the login requests, after the conversion you’ll notice in ChangeSourceControl dialog that the project’s connection was changed to bind C:\Projects to $/ folder in the scc database. With this connection, the C:\Projects\Common\Header.h file could be safely controlled in $/Common/Header.h.
You may also notice that the Header.h file in SolutionExplorer has the wrong status (pending add). It looks like VS8 has a bug, too…. L
In any case, if you close the solution and save it, after reopening the solution the file status will be correct – controlled and checked in.
This “automatic binding fixup” works only with VSS 6.0d or VSS2005 because they implement the SccGetParentProjPath MSSCCI 1.2 functions not available in VSS 6.0c and older. If you converted your solution from VC6->VS7->VS8, or if you haven’t updated the source control provider at the time you converted the solution you’ll have to manually fix the bindings as described in the previous section.
(to be written)