Creating a new Subversion branch from an existing local Git branch
When I'm coding I frequently have to work with Subversion repositories. I'm a Git user, so I use git-svn for this. Usually I do my work in local branches, using a fairly regular Git workflow, then checkout the integration branch, merge in my changes and git svn dcommit to push the code to Subversion.
Sometimes however I need to share changes that I've made on an existing local branch in my Git repository with a Subversion user before they're ready to integrate back into the mainline. It takes me a while to hunt down and work out exactly what to do whenever I want to do this, so here are the instructions for my future reference. Hopefully they help you too.
git checkout master
git svn branch <new_svn_branch_name>
git svn fetch
git branch -r # make sure <new_svn_branch_name> exists
git checkout -b tmp/svn-rebase-target <new_svn_branch_name>
git rebase --onto tmp/svn-rebase-target master <existing_git_branch_name>
# That should have checked out <existing_git_branch_name>.
git svn dcommit -n # This should say it'll commit to <new_svn_branch_name>.
git branch -D tmp/svn-rebase-target # clean up the temporary branch.
git svn dcommit
This time mainly I used comments on a blog post that asked how to do this. Thanks Björn Steinbrink and Cameron.
When should a merge be squashed?
I'm still somewhat new to Git so now and again I come up with a question that's so obvious to other developers that it doesn't seem to be answered anywhere. One such question is "when should a merge be squashed?"
Squashing a merge means taking all the commits that would normally be replayed individually on your target branch and replaying them as one large commit.
Well, as far as I can tell, here's the answer: squashing a merge is appropriate when all the commits in the merge deal with one topic.
As an example, consider having a branch that deals with the performance of one particular method. Each time you increase the performance you commit your changes. After a few days of this you have several commits in your branch and a lovely fast implementation that you want to merge back to the master branch. The merge from your branch to master should be a squashed commit and your commit message should explain what you did to speed up the implementation.
git merge --squash speed-up-the-method
An unsquashed commit could be more appropriate if you're merging from a development branch since in this case the branch should be composed of a nicely formatted series of commits based on topic relevant to the development branch.
git merge dev/v1.2.3
When doing an unsquashed commit your repository will use the original commit messages.
Accepting changes from a remote Git repository
Previously I wrote about how to work on an external project using Git. I didn't show how the owner could accept your changes though.
Connect to the remote repository
Being a committer to the project you of course already have the repository cloned. If you don't, now might be a good time to do that.
The person that's asked you to review their changes should have provided you with the repository location, and probably a branch with the changes that they'd like you to look at. Add the remote repository to yours.
git remote add \
craigwebster http://barkingiguana.com/~craig/project_name.git
Double check just to make sure the repository is correct.
git remote show craigwebster
* remote craigwebster
URL: http://barkingiguana.com/~craig/project_name.git/
New remote branches (next fetch will store in remotes/craigwebster)
dev/sprozzled-some-gromits master
Grab the information on those juicy looking branches
git fetch craigwebster
Review, critique, rinse, repeat
To look at the changes you'll want to check them out to a local branch. Ask Git to track the remote branch for you so that any changes the patcher makes can easily be pulled into this branch.
git co --track \
-b craigwebster-sprozzled-gromits-are-good \
craigwebster/dev/sprozzled-some-gromits
Do your stuff, run the test suite, look over the code, discuss it with your peers, whatever.
git whatchanged
commit b9e0f1b4ff4bc196513c9551f6c25f0ee40d991f
Author: Craig R Webster <craig@xeriom.net>
Date: Wed Nov 19 20:53:08 2008 +0000
# and so on
I'll assume that you accept the changes wholesale - you'll have to cherry pick commits if you don't.
Ask for a wider review
In some cases it may be appropriate to ask for a wider review of the changes before they are accepted into the master branch. Maybe the change is too huge to be in a minor release, or maybe it's patching a development branch. In these cases you can apply the changes to a branch.
git checkout dev/version-2-0-45
git merge craigwebster-sprozzled-some-gromits
git commit -m \
"The Gromits are well and truly Sprozzled." \
--author "Craig R Webster <craig@xeriom.net>"
git push origin \
dev/version-2-0-45:refs/heads/dev/version-2-0-45
From here you can merge, commit, or otherwise screw around with the commit much as you would with any change you've made.
Accepting the changes without review
If the change is appropriate to merge directly into the master branch then you can do that too.
git checkout master
git merge craigwebster-sprozzled-some-gromits
git commit -m \
"The Gromits are well and truly Sprozzled." \
--author Craig R Webster <craig@xeriom.net>"
git push origin master
Working on other people's projects with Git
I'm still somewhat new to Git. I'm not really sure what best practice is, or what protocol surrounds providing patches to other people's projects. Here's the best I could come up with for making a change to someone's project and allowing them to incorporate the changes if they desire them.
Clone the repository
First off you'll need to get a copy of the project to work on. Hopefully they're using Git... because I've not worked out the best way to handle if they're not.
git clone git://github.com/username/project_name.git
cd project_name.git
Add a public repository
If you're like me then you're disconnected a lot of the time. I setup a public Git repository that I could make code available from by pushing changes to it. If you're connected all the time (or at least all the time that another developer might want to get to your code) then you probably don't need to do this.
git remote add public ssh://barkingiguana.com/~craig/code/project_name.git
git push public master
Time to work
Here comes the hard but interesting bit: do some work. Typically this involves checking out a branch for a feature, bug fix or topic area.
git checkout -b sprozzle-the-gromits
# ... do the work ...
git add gromits/blue.txt
git commit -m "Sprozzle Gromit with the blue face."
# ... do more work ...
git add gromits/cherry.txt
git commit -m "Cherry Gromits are even better with more Sprozzle."
Conflict resolution
While you've been working on your awesome patch (and until your patch is accepted back into the project origin) there may be upstream changes. You'll want to make sure that it applies cleanly to the master branch as this will increase the chances that your patch will be accepted.
git checkout master
git pull origin master
git checkout sprozzle-the-gromits
git rebase master
# resolve any conflicts
git commit -m "Made branch patch master at 351ac1b cleanly."
git push public
Advertise your changes
You want to make just the changes on the branch available to the public so push the branch to the public repository. Once again, this is only needed if you live a disconnected life.
git push public sprozzle-the-gromits:refs/heads/sprozzled-gromits
Automation is awesome
Mark Brown pointed out that you can use git request-pull to create a few paragraphs suitable for emailing to the project team that contain all the information needed for your changes to be looked at and merged into the project.
get request-pull \
b9e0f1b4ff4bc196513c9551f6c25f0ee40d991f \
http://barkingiguana.com/~craig/project_name.git
And relax...
Your changes are now available to the public. They can clone your repository and fetch any of your pushed branches. Now would be a good time to email the owner of the project and ask nicely that they pull from your repository and check out the changes you've made.
If you need to make more changes to the branch, do the work on the branch, commit it, and do a git push public from the branch (or a git push public sprozzle-the-gromits from a different branch).
Difference is the spice of life
The project you want to work on may not support this style of contributing. Check with the project team before embarking on your quest. If you'd prefer not to (or are unable to) publish your own copy of the repository, check out the Git book which covers using Git and Email.
Get the current Git branch in your command prompt
It seems that everyone and their dog has their own way to represent the current Git branch in the command prompt. Here's mine. Stick it in your ~/.profile.
export PS1='\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[01;34m\]\w\[\033[00m\]$(git branch &>/dev/null; if [ $? -eq 0 ]; then echo "\[\033[01;33m\]($(git branch | grep ^*|sed s/\*\ //))\[\033[00m\]"; fi)$ '
craig@shiny ~/sandbox/addressbook(master)$
Now with 50% cleaner code
Not long after I posted this snippet I found a post about enabling git auto-completion. If you use the auto-complete file that's bundled with Git you can use the following code to get the same prompt (and get some nifty tab-based goodies too).
export PS1='\[\033[01;32m\]\u@\h\[\033[00m\] \[\033[01;34m\]\w\[\033[00m\]$(__git_ps1 "\[\033[01;33m\](%s)\[\033[00m\]")$ '
Setting up a public Git repository
More and more these days I'm using Git as my version control system. I want to make code available to the general public. The easy choice would be to use a service like GitHub or repo.or.cz but I'm vain and want to serve my code from barkingiguana.com. I don't need to support multiple committers and I'd like to learn more about how Git works so I don't want to use Gitosis. It turns out that it's pretty easy to setup your own public repository. Here's how I did it if you'd like to try the same.
General Setup
I've already got Apache setup (serving my blog among other things) so I'll use that and serve code from repositories under http://barkingiguana.com/~craig/. The easiest way to do this is to use mod_userdir. Since I'm using Ubuntu it's really easy to enable this module.
sudo a2enmod userdir
sudo /etc/init.d/apache2 restart
I'd like to keep my Git repositories under ~/code since this will let me selectively link in this repositories that I'd like to be public.
mkdir ~/code
The SSH port for my VM is on a non-standard port so I needed to put that into ~/.ssh/config on my local development machine. I also took the opportunity here to upload my SSH key to the VM.
Publishing a project
I've got a project that I'd like to publish. It's got a bit of work already done locally and I'd like to share that with the public. First I need to create a bare repository on the public machine.
# On the public server
mkdir -p ~/code/project_name.git
cd ~/code/project_name.git
git --bare init
chmod +x hooks/post-update
Success looks like this:
Initialized empty Git repository in /home/user_name/code/ project_name /
Next I setup my local development repository with an alias for the public repository because I'm going to push to this fairly regularly.
# On the local development machine
cd ~/sandbox/project_name
git remote add public ssh://barkingiguana.com/~/code/project_name.git
Now push the local master branch to the public repository.
# On the local development machine
cd ~/sandbox/project_name
git push public master
Ace, the code is on the public server and I can easily push changes that I've merged back into the local master branch to the remote repository by running git push public master. The code still isn't available to the public though since it's not in my ~/public_html. Link it in now.
ln -s ~/code/project_name.git ~/public_html/
Bam, just like that the repository is available for public use.
Did it work?
To make sure everything went okay, try cloning the repository. If you're following along at home remember to replace http://barkingiguana.com/~craig/addressbook.git with wherever your repository lives.
# On the local development machine
mkdir ~/tmp/
cd ~/tmp/
git clone http://barkingiguana.com/~craig/addressbook.git
Success should look something like this:
Initialized empty Git repository in /Users/craig/tmp/addressbook/.git/
got d0cc5f06e1d164ea6ada301dbd2e7c946d1ae532
walk d0cc5f06e1d164ea6ada301dbd2e7c946d1ae532
got b68d1319a780a776afdb60e3bba2985793a11f3e
got 2baa33597deecfc3eb558c59bc69745e153f9b82
got da7110115566b026c7316bd1be4cbf3d76c0f656
Found this article useful?
If you enjoyed this article I'd appreciate recommendations at Working with Rails.
Getting started with Rails 2.0
Rails has changed quite a lot since Agile Web Development with Ruby on Rails (2nd Ed) was released. A number of new best practice techniques are now used in favour of those described in the book.
To demonstrate these techniques it is necessary to have a new Rails application to build upon. In this article I'll cover the basics needed to setup and run a Rails 2 project on your desktop or laptop. Future articles can then build on this base.
In this article
- Installing Rails 2.0
- Starting your Rails 2.0 project
- The importance of version control
- Working with the database: Models
- Creating dynamic pages: Views
- Hooking up the view and the model: Controllers
- What next?
Installing Rails 2.0
Rails 2 now uses SQLite as it's development and test database so you needn't worry about setting up MySQL on the development machine. This makes installing Rails and starting a new project a lot easier: we only have to get Ruby and the Rails code onto our machines. To simplify this even further use MacPorts. If you don't have that installed, go install it now. Remember to install XcodeTools - you can get it from your OS X install media if you didn't install it the first time around.
To install Ruby with MacPorts open Terminal.app (it's in Applications / Utilities) and run sudo port install rb-rubygems. Technically this command will install RubyGems, but since Ruby is a dependency that'll get installed too. Once RubyGems has installed (it might take a while) use that to install Rails by running sudo gem install -y rails.
That's pretty much it. You now have a working Rails install on your development machine.
Starting your Rails 2.0 project
First, to keep your home directory tidy, create an area to keep all your projects under. I call mine sandbox. In the terminal run the command mkdir ~/sandbox to create the sandbox.
Under the sandbox directory we want to create our project. To do this use the rails command, letting it know the name of your project - in this case I call my project QuickBite.
cd ~/sandbox/
rails QuickBite
You'll see a bit out output scroll past as Rails builds a basic project for you. Let's run that Rails app and see what we get.
cd QuickBite
ruby ./script/server
Open a web browser and type http://localhost:3000/ into the address bar.

It's not much, but our project now has a decent starting point. Lets save our progress in case anything bad happens.
The importance of version control
Version control does just what the name suggests: it allows you to control various version of your project. It's useful because it allows you to see when a change was made, what files the change affected, who made it, and it provides you the option of undoing changes that you don't like.
Git!
The version control system I use is Git. It does lots of cool things, but most of them won't be used until later articles. For just now we're only interested in being able to add changes to our projects so we can undo them if something bad happens.
You are of course free to use whichever system you're comfortable with, but the commands given in this article will only cover Git use.
Installing
Installing Git is simple if you use MacPorts. Simply run sudo port install git-core from the Terminal. Grab a cup of coffee, this can take a while.
Configuring Git
Since Git has only just been installed it doesn't know who we are. Let's tell it.
git config --global user.name "Your Full Name"
git config --global user.email "you@domain.com"
This is useful when working in teams as it lets you check who made a change to the code but it's a good idea to get it set up correctly from the get-go. By using --global we tell git that we want to use these values for all projects, not just this one - you only have to set your name and email address once.
Adding your Rails project to Git
Version control is great, but sometimes we don't want to version certain kinds of file. In a file called .gitignore in the top-level directory of your project add the following directives to ignore development and test databases, generated documentation, logs and temporary files that may be generated while running or developing a Rails project.
.DS_Store
db/*.sqlite3
doc/api
doc/app
log/*.log
tmp/**/*
Git is different from most version control systems in that it tracks content rather than files. We've told Git to ignore all content in tmp/ and log/ but we do want those directories to exist - Rails complains if they don't - so you'll need to create two .gitignore files, one in tmp/ and one in log/.
touch tmp/.gitignore
touch log/.gitignore
Now that Git in only paying attention to the files we're interested in we can add the project.
# Create the repository
git init
# Add the project to the next commit
git add .
# Commit the changes
git commit -m "Setup a new Rails application."
Normally we won't add . as it adds all uncommitted files under the current directory to the next commit. It's preferable to pick the files we want to commit (called staging in Git-speak) by using git add <filename> then using git commit -m "Commit Message" to commit just the staged files.
Once that's committed we can start building our application.
Working with the database: Models
In order to make a useful application we need to model the problem domain that the application operates in. Most - though not all - models interact with a database. Models can be found in app/models/, although there won't be any there yet.
The application I've created is called QuickBite. It's going to be an application for exchanging sandwich recipes. Sandwiches usually have a name - BLT, New York Deli, that sort of thing. We can tell Rails about Sandwiches by generating a model.
ruby ./script/generate model Sandwich name:string
If you look at the output of this command you'll notice that it's created a file in app/models/sandwich.rb. That's our sandwich model. The generator has also create some files called migrations. Migrations are commands that tell Rails how to manipulate your database - adding, deleting and renaming tables, columns and indexes. By running the migrations we ask Rails to tell the database what we know about sandwiches.
# Run any pending migrations
rake db:migrate
Now that Rails knows about sandwiches we should commit our changes to the source code repository in case something bad happens. The generator created some tests for us. I'm going to be a bad man and ignore those for just now - I'll cover testing at a later date.
# Look to see what's been changed
git status
# Stage the models, migrations, schema and tests.
git add app/models/ db/migrate/ db/schema.rb test/
# Commit the changes with a message
git commit -m "Added a model to represent sandwiches."
Creating dynamic pages: Views
Rails knows about sandwiches, but that doesn't help us get information into the database or show the people visiting our application what we've added to the database. We want to create a page that allows us to enter sandwich details and to let people see those details.
Pages are made up of several views - in our case we're just going to use one per page to keep things simple. Views live in subfolders of app/views/. If you take a look you'll see that there's already one subfolder there: layouts. Ignore it for now - we'll play with layouts soon, but they're not needed to get a basic application up and running.
Create a file called app/views/sandwiches/new.html.erb containing the following simple form which will allow us to create sandwich records.
<form action="/sandwiches/create">
Name: <input type="text" name="sandwich[name]" />
<input type="submit" value="Save" />
</form>
Now that we have a way of creating records we should allow people to see them. Create a file called app/views/sandwiches/show.html.erb containing the following code.
<p>This sandwich is called <%=h @sandwich.name %>.</p>
There are three important things to notice about the view we've just created.
- ERb output blocks (
<%= ... %>) are used where something - such as the sandwich name - should appear in the output HTML. - The helper method h is used to make sure that the output is properly sanitised HTML ie it doesn't include any nasty HTML tags that could mess up our page.
- The variable we're using starts with an @ symbol. It's not important to understand why at this stage, but it's important to take note of.
Let's try to create a sandwich. Fire up a browser and visit http://localhost:3000/sandwiches/new.

Oh no, an error! Rails doesn't know what we mean by asking for /sandwiches/new. We should tell Rails what to do when we ask for our new sandwich form, but first we should commit our views in case we screw anything up.
# Check what's changed
git status
# Stage the views for the next commit
git add app/views/sandwiches
# Commit the changes
git commit -m "Added create and show views for sandwiches."
Hooking up the view and the model: Controllers
Controllers tell Rails what to do when the view wants to talk to the model - for example when a view sends data as the result of someone hitting the submit button of a form, or when a browser requests a view. Controllers live in app/controllers/. There will already be one there, the application controller, which we will use as a base for our other controllers.
Create a new file called app/controllers/sandwiches_controller.rb
class SandwichesController < ApplicationController
def new
end
def create
@sandwich = Sandwich.create(params[:sandwich])
redirect_to :action => 'show', :id => @sandwich
end
def show
# Notice that this variable starts with an @ to match the view.
@sandwich = Sandwich.find(params[:id])
end
end
Now that we have told Rails what to do when we submit data, fire up a browser and visit the new sandwich form again. This time when you should see your form, and when you hit save you will be shown the sandwich record you've just created as a webpage.

Success! Our application allows us to create sandwiches and share them with visitors. One last time (for this article), save your progress.
# Look to see what's been changed
git status
# Stage the sandwiches controller
git add app/controllers/sandwiches_controller.rb
# Commit the changes with a message
git commit -m "Added a controller for sandwiches."
What next?
You've seen how to install Rails 2 and create a basic project that allows you to create sandwich records and show them to people.
In the next article we'll flesh out some missing functionality by providing a sandwich index so visitors can find sandwiches and a way of editing and deleting sandwiches, and we'll start using layouts and partials to DRY up views and make them look good. Stay tuned!
If you've found this article useful I'd appreciate recommendations at Working With Rails.
You may also be interested in attending my Rails tutorial at Scotland on Rails Charity Day in Edinburgh, Scotland on April 3rd 2008.
