How do you version your projects?

I am working on an Automated Xcode backup system for myself
and would like to know what you use to keep versioned backups of your projects as you build them.

I am creating my own because subversion is a little overkill for most of my
projects. I want something that does it automatically and more frequently than
my Time Machine backups.



I’ve used bazaar and git for web-based stuff (e.g., PHP and Python) before, and I quite liked it.

I don’t do enough work with Xcode to need such backups, but if I did, I would look into making and/or using a script like that one that you have posted.

Thanks for the info Bruce. I am guessing most Studio users do not have a versioning system in place.

I am starting to use Subversion more these days but I see the trend is toward GIT, especially in
the Rails community.

I will continue to refine my script for more of a backup system than a versioning system.
Something like backup parts of or entire project, zip and move to external drive or ftp every x builds.
Mainly to have something that is fully automated and does not require me to remember to do it.

I sort of do it by hand. When I believe I will be making a large change to my app, I duplicate it’s project folder, rename it with the new version update, then open that and do my new code/changes.
Sometimes I forget and start doing changes right in the current version, but after I "oops"d a couple times, I remember now. Yes it makes for some duplication of files, but for me it works well enough.
For actual backups I use SmartBackup. That handles all of my backing up (user data, personal info, mail, ical etc) but I could set it to just do my XCode projects folder if I wanted to. That has a nice automatic changed/removed versioning saving system as well.


Hey Chris,

That is exactly how I used to do it. I found myself forgetting to copy and start over for a
period of time and then if I my app stopped working I would have to go back farther than
I wanted.

Once I found out we could execute scripts during a build I thought that was the perfect
place to put a backup script. I would never have to remember again and I would not
be working in the wrong version. I did that a lot myself. :slight_smile:

Thanks for your input Chris.

I have made several improvements to the Backup script.
If you do not have a version-type backup system in place for your AppleScript Studio
and Xcode projects you should give this a try. This is not a replacement for Subversion
but a compliment and much easier to setup and use.

Here are the parameters you can set:

Everything is explained on the website.

The thing I like most about this system is that it requires no thought once it is setup.

I just thought I would share! :slight_smile:



For my strictly single-user purposes, Subversion was fairly easy to setup. I set it up and started using it for the first time when I started playing with Objective C a few months ago.

I am using Subversion 1.5.5 (compiled by MacPorts) with XCode 2.5 (Mac OS X 10.4, Tiger).

My setup was basically a matter of these two commands:

  1. svnadmin create ~/‘SVN-repos/Project Name and
  2. svn checkout ‘file://’“$(echo ~/)”‘SVN-repos/Project Name’ ~/‘Projects/Project Name

Then I just did the normal XCode SCM setup (project configuration: check “Enable SCM”, select “Subversion”, then specify the path to the svn binary (maybe this last step can be skipped on Leopard)).

I skipped all the SVN web stuff entirely (I abhorred the requirement for a web server with WebDAV in the early releases of Subversion!). For backup (beyond my normal system backup), I occasionally run a little shell script that does an svnadmin hotcopy and uses rsync to copy the result to another machine on the local net.

It did take a while for MacPorts to compile Subversion (and its required libraries) on my machine, but it did so without a hitch. I assume Fink and any other “ports” projects can provide Subversion with similar ease.

I might play around with a “Run Script Phase” that does something like svn commit --message ‘autocommit’. ˜If it was worth building, it is worth saving.’ seems like a useful idea.

Model: iBook G4 933
AppleScript: 1.10.7
Browser: Safari Version 3.2.1 (4525.27.1)
Operating System: Mac OS X (10.4)

Have you done much rolling back with Subversion? I found this post but it seems
a bit complicated for anyone with little shell scripting experience. You would think there
would be a command for this.

I set up Subversion by following a tutorial by Mark Kirby. Straight forward and easy to do.
He supplies all the code. :wink: Using his instructions it is slightly more complicated to put a
project in Subversion. I wrote a script for this too but have not put it on the blog yet.

I like your idea of committing to Subversion during a build. Instead of a ‘autocommit’
message how about reading text from a file inside the project where notes are kept.
As long as the notes are kept up the SVN log would be more usable. I think I will add
this functionality as an option to my script.

Thanks for the feedback,


My most common “rolling back” operation with bazaar/git is to “undo” the changes I’ve made since the last commit.

That sounds much easier. I think I will do some research on GIT.

I have not found the need to yet. Though that will probably change when I start doing an automatic commit for each build, since I sometimes do some exploratory coding that I sometimes end up reverting (SCM > Discard Changes).

There does not seem to be support for “merging” or reverting to a revision other than (Subversion’s) BASE in XCode (at least in my 2.5 release), but it should be fairly easy from the command line. To take a single file back to a previous revision, the simplest method to understand goes something like this: [code]# First, make sure target file (TODO) is up to date (otherwise the eventual commit will fail).
$ svn update TODO

Revert the file TODO to the last revision as of 2008-12-10 00:00

$ svn cat -r {2008-12-10} TODO > TODO

OR Revert the file TODO to revision 103

$ svn cat -r 103 TODO > TODO[/code]
The idea is simple: have Subversion extract an old copy and just overwrite the current contents of the file with that old data.
Then review the changes (SCM > Diff With/Compare With, run test suites, etc.) and commit them. It is usually nice to include a note about the reverted file in the commit message (“TODO reverted to 2008-12-10 (r103)”).

If you want to keep most of the changes but undo a few of them, the merge command is helpful. If errors were introduced in revisions 155 and 156 but all the other changes up to HEAD are alright, you can “reverse-merge” only the changes from revision 155 and 156 like this:[code]# Update first.
$ svn update TODO

Merge out the changes made in revisions 155 and 156.

$ svn merge -r 156:154 TODO # note use of 154 (first OK revision), not 155 (first bad revision)[/code]
The newer:older ordering of the revisions makes it do a “reverse-merge” (an undo). Then review and commit the changes. Again, a commit message stating what was reverted is usually handy for later reference.

When the command looks like svn merge -r HEAD:older ., this means remove all the changes committed after older (after older up to and including HEAD). The result is nearly the same as the cat method (overwrite with an old version). The merge method will preserve any uncommitted changes in the file, the cat method will discard them. Also, the merge method might store away extra metadata about what was merged (or ˜unmerged’, as the case may be). Right now, it looks like Subversion only stores this extra merge metadata (svn:mergeinfo property) when merging between branches in the same repository.

Also, the merge command can be used to remove changes from whole subtrees with one command (use a directory name instead of the file name (“TODO” in the above examples)).

PS. I am not sure why the example in the posted link was so verbose. Assuming all the references to “changedFile.txt” are all from the same branch (this seems reasonable given the “roll back” context), then the command could be rendered as svn merge -r HEAD:215 ./folder/changedFile.txt. Does that make it seem less complicated?
PPS. Even if the working copy was supposed to be on a different branch there does not seem to be much need to repeat the whole repository URL: svn merge -r HEAD:215 svn:// ./folder/changedFile.txt.

Hi chrys,

Yes, this makes perfect sense. Thank you very much for your
thorough explanation.

Have you or have you considered writing a book? Just a thought. :slight_smile:


Hi Craig and everyone else, I use an applescript I wrote to backup my projects. I run it from the applescript menu periodically when I’m working on a project in xcode.

I understand why you would want to use subversion or any of the other methods to automate the process, but here’s my script in case it’s of use to anyone. It creates a zip file of the project folder. If you wanted to automate the process I guess you could just execute the script during the build phase by writing a unix executable that runs the applescript.

-- This script will create a backup zip file of an xcode project folder. The zip file is placed in the same folder as the project folder. The project must be open in xcode before running this script.
(* How it works:
The script will find the project folder to backup from the front project in xcode. It will then remove any build folders inside the project folder. The version number of the project will be found and the resulting zip file will include the version number. The script makes sure the zip file has a unique name by appending a number to the end of the zip file name if necessary. *)

property removeBuildFolder : true -- if true then build folders are removed from the project folder before zipping

-- get the project folder for the front project in xcode and stop the script if it cannot be found
	tell application "Xcode" to set posixProjFolder to project directory of first project document
	set projFolder to POSIX file posixProjFolder as text
on error
	display dialog "The project folder could not be found from Xcode, please try again!" buttons {"OK"} default button 1 with icon 0
end try

-- get the version number of the project
set infoPlistPosixPath to posixProjFolder & "/Info.plist"
set key1 to "CFBundleVersion"
set key2 to "CFBundleShortVersionString"
set theVersion to false
	alias (POSIX file infoPlistPosixPath)
	set theVersion to plistValue(infoPlistPosixPath, key1)
	if theVersion is false then
		set theVersion to plistValue(infoPlistPosixPath, key2)
	end if
end try
if theVersion is false then set theVersion to "1.0"

-- remove the build folder from the project folder because we do not want to back that up
if removeBuildFolder then
	set buildFolderPath to projFolder & ":build"
		alias buildFolderPath
		tell application "Finder" to move item buildFolderPath to trash
	end try
end if

-- get a unique path for the backup zip file
tell application "Finder"
	set projFolderName to name of folder projFolder
	set projFolderParent to container of folder projFolder
end tell
set proposedName to projFolderName & space & theVersion & ".zip"
set backupPath to uniquePath(projFolderParent, proposedName, "_")

-- zip it
	do shell script ("/usr/bin/ditto -c -k -rsrc " & quoted form of posixProjFolder & " " & quoted form of POSIX path of backupPath)
on error
	display dialog "There was an error creating the zip file, please try again!" buttons {"OK"} default button 1 with icon 0
end try

(*================= SUBROUTINES =================*)
on plistValue(filePath, KeyName)
	set returnValue to false
		tell application "System Events"
			set returnValue to value of property list item KeyName of contents of property list file (filePath as text)
		end tell
	end try
	return returnValue
end plistValue

on uniquePath(fDir, fName, separator)
	set fDir to fDir as Unicode text
		set F to (fDir & fName) as alias
		set {name:Nm, name extension:Ex, kind:Knd} to info for F
		if Ex is missing value then set Ex to ""
		if Ex is not "" then set Nm to text 1 thru ((count Nm) - (count Ex) - 1) of Nm
		set idx to 0
			set idx to idx + 1
			set idxNum to (text items -3 thru -1 of ("00" & idx)) as Unicode text
			if Knd is "Folder" then
				set checkName to (fDir & fName & separator & idxNum)
				set checkName to (fDir & Nm & separator & idxNum & "." & Ex)
			end if
				checkName as alias
			on error
				return checkName
			end try
		end repeat
	on error
		return (fDir & fName)
	end try
end uniquePath

That’s cool Hank.

This is the last thing I have to add to my script. Backing up the entire
project every x builds. I think I will just use yours for now because
I am back on the Automate Sparkle Appcast project. I am working to
make it fully automated. Create all the necessary files and upload.
I really like Sparkle and think more devs would use it if there were
less steps involved. We’ll see.

I started using ZennaWare’s Cornerstone for versioning. It seems pretty nice so far. It works for AScript studio projects, and even script files, with these restrictions…

It works OK for:
compiled script bundle.scptd
compiled script data fork.scpt

It fubars:
compiled script resource fork.scpt
These files can’t be run or opened after checking-out from the system. So resource forks are not available in the svn system, since from what I read it’s like a big text database that can also handle binary files. But not Mac-specific resource forks.

Does anyone else have experience to add using CVS systems?

This is not a plug since I’m still undecided but everything has been smooth so far, and it’s not too expensive, as of 2010-04 it’s only $60 US.

Yes. I have been using GIT for almost a year and a half now. Love it.