When you're moving a codebase from subversion to git, here are a few things that make the move go a bit more smoothly.
In the svn project, you can discover some things you'll need to adjust in git after the import.
Show all files being ignored
svn propget -R svn:ignore .
Add these files to the .gitignore file at your project root, or in appropriate subdirectories. I prefer keeping it all in one place at the top level.
Show all externals
svn propget -R svn:externals .
You'll either have to switch to using a submodule in git, or just pull the files into your project if that's not possible for some reason.
Find all empty directories
find . -type d -empty
touch /path/to/empty/dir/.gitkeep
Since git doesn't keep empty directories, you can add a .gitkeep file to empty directories that you don't want to go away. Some people add a .gitignore file to keep the directory around, but that sounds totally backwards to me. You want to keep it, not ignore it.
By the way, if you are already ignoring dir/*, that will ignore the .gitkeep file as well. Make sure it isn't missed by adding !.gitkeep to the end of your .gitignore file.
Find all authors
If you want to properly attribute commits, you'll need to set up an authors file. But if you miss any authors, the clone will stop and complain. You can discover all the svn users that you need to put in the authors file with this command:
svn log | grep -E 'r[0-9]+ ' | cut -d\ -f3 | sort | uniq
init + fetch > clone
If git svn clone doesn't complete, try doing the init/fetch as separate operations. The clone subcommand is pretty much just doing an init followed by a fetch, but I've found that if the clone fails, doing the commands separately can have better success.
Sometimes I accidentally git add files. Or more often, I do git add . and get a huge changelist and then realize I want to move certain files to a different changelist or a different branch. I could do a git reset which, absent --soft or --hard, pulls all the changes out of the index (aka dircache aka staging area) but leaves them in the filesystem (aka working tree). But wouldn't it be nice to leave all the files in the index except the few I want to keep out?
Upgraded to git 1.6.3 yet? You should, and Jason Rudolph says why (and if you're on a Mac, Rob Sanheim says how.)
Sadly, after you do upgrade, when you start doing "git push", your console will start to be littered with the following oddly patronizing message:
warning: You did not specify any refspecs to push, and the current remote
warning: has not configured any push refspecs. The default action in this
warning: case is to push all matching refspecs, that is, all branches
warning: that exist both locally and remotely will be updated. This may
warning: not necessarily be what you want to happen.
warning:
warning: You can specify what action you want to take in this case, and
warning: avoid seeing this message again, by configuring 'push.default' to:
warning: 'nothing' : Do not push anything
warning: 'matching' : Push all matching branches (default)
warning: 'tracking' : Push the current branch to whatever it is tracking
warning: 'current' : Push the current branch
While I'm generally in favor of verbose warnings, this one is kind of bizarre. Essentially, it's saying, "Warning! The command you just ran will continue to operate exactly as it did before!" Guys, telling us about new options is great but that's what release notes are for.
Worse, they don't provide keystroke-level instruction beyond the offhand gerund "configuring" on how to shush it. Here's the result of my 8-minute speluking inside the output of "git help config":
git config push.default matching
[Or, thanks to Alastair Brunton below
git config --global push.default matching
]
There, now, that wasn't so hard after all, was it?
In this post, I'll show you how to set up end-to-end Capistrano testing using Cucumber. I've extracted this from the cucumber features I wrote for a gem I'm building named auto_tagger. To fully test capistrano recipes, your tests will have to:
- Create a local git repository
- Create a local app with a config/deploy.rb file
- Push the app to the local repository
- Run
cap deploy:setupfrom the app (which will setup a directory inside your local test directory) - Run a
cap deployfrom the app (which will deploy to your test directory) - Assert against the content of the deployed app in the test directory
Background - Capistrano recipes are almost never tested
Looking around online, I couldn't find a single list of capistrano packages that has an automated test suite, even ones from some big hosts. It's no surprise that Capistrano tasks are seldom tested - testing capistrano recipes is hard, and even when you do test them, there are still so many variables in real-life deploys that you can't account for everything.
It's like Rummy said:
There are known knowns. There are things we know that we know. There are known unknowns. That is to say, there are things that we now know we don’t know. But there are also unknown unknowns. There are things we do not know we don’t know.
from wikipedia
However, there are some things you can do to stave off the "known unknowns". For example, you know that someone might forget to set an important variable in their cap task and you know they might be using cap-ext-multistage. For these kinds of examples, Capistrano testing can give you much more assurance that a bug in your recipe is less likely to rm -rf /* on your remote machine.
AutoTagger is a gem that helps you automatically create a date-stamped tag for each stage of your deployment, and deploy from the last tag from the previous environment.
Let's say you have the following workflow:
- Run all test on a Continuous Integration (CI) server
- Deploy to a staging server
- Deploy to a production server
You can use the autotag command to tag releases on your CI box, then use the capistrano tasks to auto-tag each release.
A problem I had as a git newbie, and one I've seen others struggle with, is the problem of how to conveniently stage the deletion of files which are already deleted from disk, but aren't yet reflected in the index? That is, without 'git rm'ing them one at a time or using some other hack (e.g. 'git ls-files --deleted') to do so.
The answer is 'git add'
Moving from Subversion to Git
We recently moved our project from subversion to git, and so far the move has gone very smoothly. The following post will detail what we did to make the move.
Our setup
For this project there 2 pairs working and we have 6 machines and one hosted service:
- Two Mac OSX workstations with IDEA
- One continuous integration server running Cruise Control
- A staging server running a 2-year old version of Ubuntu
- A subversion server
- A production server hosted on Engine Yard
- A Github account with the ability to create private repositories
The goal was to have one pair continue to work while the migration from svn to git was happening.







