So, you’ve bought Unity Pro and the Unity Asset server. If you’re like me, in spite of its disadvantages, you really like the UAS. It’s integrated into the editor and does a much cleaner job of versioning on serialized assets than does external version control, because it operates on the project’s Library folder rather than requiring you to generate and synchronize all of the sidecar data. However, there are some key things it cannot do.
I don’t have very complicated needs like branching and so on, but I do have a library of common code that I share across projects. This library contains a bunch of useful stuff that doesn’t rely on any game systems: things like helper classes, math classes, serialization for built-in types, and so on. The trouble is, I’m often working simultaneously on a bunch of projects that share my library (or worse still parts of my library), and so it can be a pain in the neck to push the changes out across all my projects. As such, I took the time to set up a system using Subversion working on top of my UAS projects in order to synchronize my library code.
Apart from Unity, you obviously need Subversion. If you’re on OS X, this is part of Snow Leopard, so you’re good to go. Because I’m not especially adept at all the setup, and because there are plenty of really good tutorials, I won’t go through all the details. Basically, you need to prepare a repository somewhere and get a good SVN client. If you’re on OS X, I really recommend Cornerstone. It’s not open source, but it does some key things I need:
- It has a great GUI. Apart from letting you do things easily, it also allows you to set up each working copy to show when it is out of sync, so I know which Unity projects needs to pull down new library updates.
- The GUI lets you effortlessly modify your snvignore settings, allowing you to exclude all of your non-library code from your SVN repo. For example, I only want to include folders like Assets/ Scripts/Library, and Assets/Editor/Library, so I want to be able to easily exclude my per-project code and assets from the SVN repo.
- It lets me take advantage of sparse checkout features in SVN. This feature was actually the deciding factor for me, as I distribute packages in the Unity Asset Store with limited copies of my library code. For example, my Biped Editor package contains library code for my VectorHelpers class, but not FloatMatrix. This requirement was also part of the reason I opted for SVN instead of Git. Maybe it’s possible to manage it easily with Git, but it wasn’t something I was up for fighting against!
The basic requirement to make this work as painlessly as possible is to have parallel structure in your Unity projects. I have a generally parallel structure, but because of Asset Store requirements, for example, my library code needs to be in folders like Assets/PackageName/ Scripts/Library, whereas all of my games are simply Assets/ Scripts/Library. Because of this issue, instead of making my Assets folder top-level in my repo, the repo simply has Scripts/Library, Editor/Library, and Plugins/Library at the top level. The problem in the video, as you can see, is that all of my working copies for my games are called Assets, whereas having Assets as the top-level folder in my repo would allow Cornerstone to display my Unity project folder names in the working copy list, so I wouldn’t have to look in the inspector to double-check what project I’m in. Depending on your SVN client, you may or may not experience this problem. Probably the absolute easiest way to set your project up is to have an Assets/Library and an Assets/Game folder in your project, the latter of which contains all of your actual per-game stuff. Using this organization, you would only have to apply svnignore to the Assets/Game folder in your working copy, instead of having to add all of your individual project folders. I leave it up to you to know what is best for your needs, but it suffices to say “stop and think about it before you pull the trigger.” Once you’ve picked out your organization system, export your library code as a unitypackage from Unity’s main menu.
At this point, create a new, empty Unity project and make it a working copy of your new SVN repo. In my case, I had to point to my project folder and call the working copy Assets because of my organizational structure. Again, if your repo will contain Assets, your project folder can be your working copy folder, but you’ve probably already figured that out.
Now, import your unitypackage into this empty project using the one you just created. This will populate your project with your library code.
Finally, check your library into the repo and voila! Now you have a common code library under version control sitting on top of your Unity project, which is managed using the Asset Server.
Now, if you set up a new project, just always make it a working copy of your repo first thing. If you dump all of your game assets into a folder that is already ignored (e.g., Assets/Game), then you shouldn’t have further work to do. Otherwise, make sure you remember to ignore your non-library folders when you commit any library code changes to your SVN repo. Using a client like Cornerstone, any new folders will show up in bold in your working copy view, and you can easily ignore them from the inspector or using the RMB context menu.
If you want to get extant projects set up on your SVN repo, you may want to first rename your extant project folders whose names conflict with those on the repo. You can then make your project a working copy and move over anything from your renamed folders that you need to keep and ignore or commit to the repo.
I hope some of you find this helpful, but if not at least I’ve documented it for myself!
Tags: Mac, OSX, Subversion, Tutorial, Unity, Unity Asset Server
I should also note, by the way, you should be careful about doing large structural changes to your repository, especially when it results in important differences in compilation order (for example, if something is in Assets/Editor/Library, be wary about moving it to Assets/ Scripts/Library). Changes such as these may result in components displaying “Missing MonoBehaviour” in the Inspector, which requires you to re-link your scripts to components.
We switched to Subversion entirely a few months ago, and it’s taken some getting used to. Cornerstone is a godsend, really, because it keeps simple ideas as simple as possible and provides a decent GUI. How many different ways are there to delete a file in Subversion? If a file is versioned, unversioned, added or missing, you have to do different things in each case. In Cornerstone, it’s Command-Delete. Awesome.
The main ugliness is that of meta files. I just don’t like looking at them, and occasionally forgetting to move or delete them. They let you do cool things, though, like have prefabs in your externals. We’re not going crazy with them, but it is helpful in a few scenarios.
The other pain is having to quit Unity when you update Library files. Unity takes forever to “scan for files that need reimporting” every time it starts a large project. It takes longer than anything else I know to scan its files. It’s a real time-waster, and I hope it gets fixed soon.
In spite of meta files and updating Library files, though, the up-sides of Subversion are well worth it: branching, merging, externals and locks, all in a robust (so far), free and widely supported version control system.
Out of curiosity, do you guys use the sparse checkout features much? I’m totally new to Cornerstone, but I’ve found one problem I have yet to solve. For example, if I accidentally add a file or folder from my library to a sparse working copy, or if something changes in my library such that some dependencies are no longer necessary in a sparse working copy, I can’t figure out how to remove them from the working copy. Obviously I can’t delete it and check that change in, and I can’t add it to the snvignore settings either. Any tips?
We don’t use sparse working copies, but if I’m reading the last paragraph on this page right, that’s not currently possible:
http://svnbook.red-bean.com/en/1.5/svn.advanced.sparsedirs.html
It doesn’t seem to have changed in 1.6, either, so the only solution I can think of is to carefully check out a new sparse copy and omit the file. Kinda stupid.
Hey Adam. First, love your blog and your Unity products (I purchased biped editor, and will probably get the Handles library). I only started using Unity last month, and I’m weighing the pluses/minuses of the Asset server. You say that it operates on the Library folder instead of the Assets folder and that it doesn’t require synchronization of out-of-band data files. By these I assume you mean things like .psd or .ma files that you might not keep in the asset folder. But surely it must sync items in the asset folder itself? And why would it sync the Library folder since it is derived from the asset folder? I’m clearly missing something here. Also, I understand your need to sync library code across multiple projects, and I watched your video. But again, being very new to all this, I got a little lost when you say “push” the changes to other projects. UAS is going to just see these as local changes in the other projects, so won’t you have to commit these with UAS as well? Sorry to be so dense; I’m just used to the ways of other game engines (i.e. severe pain).
Hi Eric,
I wasn’t suggesting that UAS versions the “Library folder instead of the Assets folder.” Using UAS or external version control will both version files in the Assets folder. The difference is that when you use UAS, much of the metadata for assets (e.g., import settings) is stored in files in the Library folder, and UAS can hook into these files directly through the Unity editor. External version control, on the other hand, requires that such metadata be exposed in sidecar data files (.meta) that will live in the Assets folder, and which you must manually check in/out and move along with your assets.
As for your other question, yes, you still have to commit the changed files to each UAS-managed project when you push them out using SVN. Adding the SVN layer on top is basically intended to be a way to maintain common code across several projects. The reason I do this is because I otherwise prefer UAS for versioning assets (e.g., it does not require creating all of the .meta files, it does not require that all project participants have Maya installed in order to import native Maya files, etc.).
This is my first time i visit here! I found so many useful stuff in your website especially its discussion. From the a lot of comments on your articles, I guess Im not the only one receiving the many satisfaction right here! keep up a good job;