git-svn is a gateway drug 6
As we’re migrating away from Subversion to Git, I’m having to learn a lot about git-svn. Andy has posted a few articles on this topic, but I wanted to share a quick tip that I find myself forgetting.
Working with Subversion branches
While you’re hopefully already familiar with how great local branches are with Git, you might not know that you can connect local branches to remote branches in your Subversion repository. This allows those of us who are using Git locally to work against Subversion branches.
I’m going to assume the following:
- Your team is using Subversion
- Your team already has a branch that you’re working in
- Your team is following Subversion directory conventions (
branches/,tags/, andtrunk/) - You have Git installed (with SVN extensions)
Checkout the Subversion project with Git
Please visit Andy’s tutorial, Git SVN Workflow, for a more detailed explanation of the following commands.
First, we’ll initialize your new local Git repository with git-svn.
git svn init -s http://svn.yourdomain.com/repos/project_name
Now, you’ll change directories to your new Git repository.
cd project_name
Let’s fetch all previous revisions into your local repository1.
git svn fetch
Great, once this is done… you’re master (local) branch is linked to trunk/.
Mapping a local repository to a remote branch
Assuming that your team is working in a Subversion branch on the current iteration of work. Our team has a naming convention for branches for each iteration. For example, if we’re in Iteration 18, we’ll write this as ITER-018 everywhere (Basecamp, Lighthouse, Subversion, etc…). At the start of each iteration, we create a new branch with this naming convention.
For ITER-018, the Subversion branch would be located at:
- http://svn.yourdomain.com/repos/project_name/branches/ITER-018
If you were to do a git branch -r, you should see ITER-018 show up in the list. Now, the one thing that wasn’t clear when I first read the git-svn documentation was that you can’t just checkout that branch with one command. In fact, this has tripped me up a few times.
First, you’ll need to checkout a new local branch. I’ve opted to come up with my own convention for local branches and in this case, I’ll name it iter_018.
git co -b iter_018
So, now I’m in the iter_018 branch, which is local. I’m currently still mapped to trunk/, which isn’t what we want. However, all we need to do is reset where Git is currently pointed to. We can run git reset to point this to the ITER-018 branch.
git reset --hard ITER-018
That’s it! Now, the local iter_018 branch will point to branches/ITER-018 in your Subversion repository. This will allow you to work with your existing repository branch and still reap the benefits of local Git repositories.
What about master?
Good question. The git reset command that you ran will ONLY apply that that individual local branch. So, master is still pointing to trunk/. This will allow you to have several local branches that map to remote branches.
Next Steps…
If you’re working with Git already.. great!
If you’re working in an environment that using Subversion, git svn provides you the ability to start exploring Git without making your entire team switchover. Perhaps your a consultant and working for a client that uses Subversion… no problem!
We’re still using Subversion for past client projects and are considering GitHub, which just launched (to the public) today for future projects. A few of us are already using GitHub for open source projects.
Fun.. I just saw the following tweet pass by as I began to wrap up this post.
The Gateway Drug… Git reminds me of Cake
Questions?
I know that I glossed over a few things, so feel free to post questions and/or tips for others who are looking to dabble with Git.
1 You’ll likely have problems if you don’t have a Git authors file specified in your git config.
Tip: Link to Unimplemented 13
Throughout our design and development process, we’re working around areas of the site that are not yet implemented but we also want to be able to allow our clients to demo their application. In an effort to manage their expectations, we need to be careful about what we link to. If a page/widget isn’t ready to be demo’d yet, we should avoid providing pathways to get interact with or navigate there. However, when we’re implementing HTML/CSS for pages, it’s sometimes makes sense to not hide certain things on the screen.
For example, let’s suppose that you’re working on the primary navigation of an application. You know what the other sections are going to be, but you’ve only implemented a few of them so far. Your HTML/CSS person is working on the design for the navigation and wants to have them be proper links… even to pages that don’t yet exist.
One option, which is quite common, is to provide a link with href="#". This works to some extent, but when people click on things, they naturally expect something to happen in response.
This approach doesn’t mesh well with our team as we don’t really want to field any questions like, “the navigation links are all broken. Nothing happens!”
So, a pattern that we’ve been using for a while is to trigger a javascript alert for every link within an implemented area that is linking to something that isn’t yet implemented.
Let’s take a really basic javascript function like:
# public/javascripts/application.js
function unimplemented() {
alert("NOTICE\n\nThis feature is not implemented yet. Please check back again soon!");
}
This allows us to do the following:
<a href="javascript:unimplemented();">link text</a>
When someone clicks the link, they’ll see a typical javascript alert message. This informs our clients/beta testers that we’re paying attention to what works and what doesn’t.
Let’s take it a step further and push this into a view helper.
# app/helpers/application_helper.rb
def link_to_unimplemented( link_text, *args )
link_to_function( link_text, 'unimplemented()', *args)
end
Now, we’re able to use link_to_unimplemented and pass any arguments that you’d pass to the default link_to view helper.
<%= link_to_unimplemented( 'link text', { :class => 'link_class_name' } ) -%>
Now our web designers can go about their work and use this helper as necessary.
An nice benefit for doing this is that we have a pattern that we follow so that we can rely upon to make sure that we don’t forget anything. This is the equivalent of adding @TODO@s throughout our code base.
If we search through app/views for ‘link_to_unimplemented’ we should be able to prevent missing any broken links. In the next screenshot, I’m using grep with colorized matches.
As you can see, we have something left to implement in that area of the application. :-)
This has been one of those lightweight patterns that we’ve been able to adopt and it’s definitely helped manage the expectations of our clients throughout our development process.
I’d love to hear your thoughts on this. How does your team handle things like this?
Related Posts
Managing Required Gems on Rails Projects 17
We’re starting a new project and I’m finding myself adding things to the code base that we’ve done in the past… hence the last few posts. As we’re doing this, I’d like to highlight some of the little things that we do on each project to maintain some consistency and in that process reach out to the community for alternative approaches.
I’m intrigued by the vendor everything concept, but we haven’t yet adopted this on any of our projects (yet).
What we have been doing is to maintain a REQUIRED_GEMS file in the root directory of our Rails application.
For example:
$ cat REQUIRED_GEMS
actionmailer
actionpack
actionwebservice
activerecord
activesupport
cgi_multipart_eof_fix
daemons
fastercsv
fastthread
feedtools
gem_plugin
image_science
mongrel
mongrel_cluster
mysql
rails
rake
RedCloth
Ruby-MemCache
soap4r
uuidtools
Everybody on the team (designers/developers) knows to look here to make sure they have everything installed when beginning to work on the application.
This has worked fairly well from project to project but since we’re starting a new project, I’m curious if anybody has some better ways to approach this. Should we look more seriously at the vendor everything approach or are there any alternative approaches?
Managing SEO-friendly HTML Titles with Rails 20
I’ve seen this come up a few times in the #rubyonrails IRC channel and figured that I’d post a quick entry for future reference.
Problem: HTML titles
You want to have a clean way to manage the titles on your HTML pages.
<html>
<head>
<title>Robby on Rails — Article Title Goes Here</title>
</head>
<body>
...
Possible Solution(s):
Since the <title> tag is usually declared in your layout, you need to be able to dynamically update this information from almost every action in your application.
Here are a few ways that I’ve seen this handled.
- Use a instance variable, which would have a default value and you could override it in any controller action
- Use the
content_formethod to manage it.
Let’s take a few minutes to look at these two approaches.
Instance Variable
With the instance variable, you might end up with something like:
# app/views/layouts/application.html.erb
<title>Robby on Rails — <%= @html_title || 'Default text here...' -%></title>
Then in a controller action…
# app/controllers/articles_controller.rb
def show
# ...
@html_title = @article.title
end
So, that’s one way to handle it and is probably a more common way.
The content_for helper method approach
This solution is very similar (and underneath uses an instance variable).
We’ll use the content_for and a little yield action.
# app/views/layouts/application.html.erb
<title>Robby on Rails <%= (html_title = yield :html_title) ? html_title : '— Default text here...' %></title>
Then we’ll create a helper method.
# app/helpers/application_helper.rb
def set_html_title(str="")
unless str.blank?
content_for :html_title do
"— #{str} "
end
end
end
Now, instead of defining the HTML <title> value in the controllers, we’ll just toss this into our html.erb files as necessary.
<% set_html_title(@article.name) -%>
... rest of view
..and that’s pretty much it.
Which is the better solution?
This is where we’ll not find a lot of consensus amongst people. I’m a fan of the content_for-based approach and defining the title in views rather than in controller actions. I’m an advocate of skinny controllers and while I’m not a big fan of messy views, I believe that there is less overhead in managing this within the View-world.
I’d love to hear your thoughts on this. Perhaps you have a more eloquent for managing things like this? Do share. :-)
Things (in the Rails world) You Don't Yet Understand 8
This is inspired by a recent post by Seth Godin titled, Things you don’t understand, where he shared a list of things that he probably could understand if he put your mind to it, but doesn’t. I decided to post a list of five (5) things in response within the context of Ruby/Rails.
I’m really interested in various things but am really unable to prioritize them high enough to spend the time to understand them.
- RSpec User Stories
- Using Selenium with RSpec
- JQuery (Graeme speaks highly of it)
- JSSpec (BDD for Javascript)
- Using the Google Charts API with Rails
What about you? What’s your list of things that you’d like to understand more about?
DRY(a): Year After Year 28
I’m guilty of it. Many of you are likely guilty of it… and I know that several customers of our Rails Code Audit and Review service are guilty of it.
How many times have you realized (after a few months has passed) that your Copyright date/year on your web site was no longer current?
How many of you had the same problem last year? The year before?
Let me share some advice with you all… DRY (a)!
Don’t Repeat Yourself (again)!
This is really a simple problem to fix but when we’re busy tackling bigger problems… little things like this slip by. Don’t worry, you’re not the only one who was reminded by a colleague three months into the year that you forgot to update this.
On client projects, we have a handful of helpers that we drop into the application. We’re starting to extract more of these into plugins and will be releasing those as time permits. It just happened that I found myself looking at yet-another Rails code base this afternoon that was showing 2007 in the footer. An easily forgivable offense.. but if you’re going to go in there and change it (again), take a moment to do the right thing. ;-)
Our solution at Planet Argon on client projects is to create a basic view helper that renders the current year. This allows us to do the following.
<div id="footer">
© Copyright <%= current_year -%>. All Rights Reserved.
</div>
The helper code looks like:
# add to application_helper.rb
module ApplicationHelper
def current_year
Time.now.strftime('%Y')
end
end
Voila. Not rocket science.. is it?
Guess what? I’m getting really tired of adding this to every Rails project that I touch. So, I bottled this little gem into a new Rails plugin that we’ll just add to future projects.
Introducing Year after Year
This is really the smallest plugin that I could put together (and it includes specs!)
What does it provide you?
YearAfterYear will provide you a helper that will render the current year (dynamically)! That’s right… just add the plugin to your Rails application and you too can enjoy New Years 2009 without having to have a deployment ready with a one line change from 2008 to 2009!
To use.. add the following to any view from within Ruby on Rails.
<%= current_year -%>
Installation
As I’m using git, you’ll need to grab this and put it into vendor/plugins. That’s it!
You can grab it on GitHub!
- http://github.com/robbyrussell/year_after_year/
- Bugs / Feature Requests here
Happy New Years (8+ months early)!
Just a friendly reminder to not forget the small stuff… because your visitors will notice! ;-)
Updates…
I got a few requests for this to also provide a range of years for people who like to do: 2005-2007. So this is now provided as well.
year_range(start_year)
<%= year_range(2005) %> # => 2005-2008







