Git Branching After the Fact
We have a pretty simple Git work flow here at Databasically: Just work in master. There are a couple reasons for this: we’re not a large team, and we have a very rapid (i.e. daily) release cycle. I had been used to creating branches for every new feature, so when I found out we primarily work on the “master” branch, I was a bit shocked.
I know what you’re thinking, “But what if you go down a path and realize you need to branch in order to put in a ‘hotfix’, or you find out the story is more involved than initially thought?”: you just create a branch after the fact. Here’s how to do it in just a few easy steps:
Step 1: Know where you are and where you want to go
The first thing you need to know is where you are and where you want to go.
In the case (completely contrived example) above, I need to add a fix to what is in production (SHA: fa87cd9). So I want to roll everything back and start working from that hash point.
Step 2: Create a new branch
Now that we know where we want to go, we need to first create a new branch. We create a branch in order to force Git to remember our current line of work. In some ways, you can think of Git branches as inodes in Unix/Linux: as long as a file descriptor [branch] is pointing to an inode, it can’t be fully deleted [reset]. To do this, we’re just going to issue the “git branch <branch name>” command.
I should note that before you do this, make sure you’re clean. “Add” and “commit”, or “stash”, what you’re currently working on.
So here, I created the branch “hotfix” and you can see that HEAD, master, and hotfix are all pointing to the same SHA. You can make sure your branch exists, by issuing the “git branch” command. Now, we can make our changes in master and push to production.
Step 3: There is No … step 3
This means you, Bruce.
Step 4: Reset Master
Now that we have a branch (created in step 2) we’ll reset HEAD to our chosen hash. We do that using git’s “reset” command:
git reset --hard fa87cd9
The log will look something like this:
After making our change and committing, our log looks like this:
Now we can push that into production and get back to what we were working on.
Step 5: Rebase and Merge
Step 5a: Rebase Master
In order to get back to what we were working on, we need to first rebase the changes we made in master into production. To do that, first checkout hotfix and run git rebase master
git checkout hotfix git rebase master
By rebasing master, we replay those changes made in master onto our “hotfix” branch. Our hotfix branch should now look like this:
Notice where HEAD and hotfix are, and notice also where master is. It is now safe to merge everything back to master – and without leaving those unsightly branch paths.
Step 5b: Merge
First things first: check out master. Next: merge hotfix
git checkout master git merge hotfix
You output will look something like this:
And your log will look like this:
And everything is caught up. At this point you can delete the hotfix branch:
git branch -d hotfix
Conclusion
This model works well for us, but I’m sure as we grow we’ll likely have to adopt more involved models such as the “A successful Git branching model” used by nvie.com. As we grow and modify our processes, we’ll be sure to let you know what we find to work and what we find which doesn’t.
Further Reading
Notes:
In this post, I have been calling “git log” with my alias “git lol” here is the details of the alias:
log --graph --decorate --date=local --pretty=format:'%h %cd (%an) %s%d'
default_scope: Use Cases, Caveats, and Work Arounds
In Ruby on Rails, named scopes are class methods used to restrict and organize the data searched for. In SQL terms, a named scope adds to the conditional (WHERE) and sorting (ORDER) sections of a query. See Railscast #108 for more information.
In Rails 2.3.x, a new type of scoping was added to the API: the default_scope. By using “default_scope”, one could restrict the data retrieved by every query without the need for extra method calls; it would just happen by “default”. If you wanted to have your data sorted in a particular manner, you could add “default_scope, :order => ‘created_at DESC’” to your model. From then on, all data retrieved would be ordered by “created_at” in a “descending” manner.
Caveats
In general, default_scope should be avoided if possible. Here are a few reasons:
- Out of site, out of mind: Because you don’t see that you are scoping your data as you query it, it’s easy to forget that it is in actuality being filtered. This can lead to a lot of head scratching until you remember the default_scope.
- default_scope is inherited: All subclasses of the original model will inherit the default scoping. This may not be the behavior you desire.
- Extra overhead: It’s one thing if you need your data sorted every single time, it’s quite another if you don’t. By using default_scope, you may be unnecessarily burdening your database.
Use Cases
Like curry, default_scope is not inherently evil (obscure Phineas and Ferb reference), and there are instances where using it makes good sense. As an example, here at Databasically, we use default_scope to limit data retrieved by one application to a subset of what is available in a table. There will never be an instance where all the available data will be required, and so we limit it by default.
Here are the two use cases:
- When only a subset of the data is ever required
- When the data must be returned in a specific order every time
Work Arounds
I highlighted the words “only” and “every” in the section on use cases to make a point: default_scope should be used with caution. The fact is, however, that it’s not an “only” and “every” world, and as such, we need work arounds. In our case, it’s by using “with_exclusive_scope” and the undocumented “unscoped” (Rails 3.x only)
with_exclusive_scope example:
Article.with_exclusive_scope { find(:all) }
unscoped example (Rails 3.x only):
Article.unscoped
Conclusion
In general, we like to keep our code as DRY as possible, but in cases like default_scope, we prefer to be more explicit. We recognize the value of default_scope, but only use it when we absolutely need to, and even then we try to think of alternative methods.
How about you? We would really like to hear from you about your experiences with default scopings. What considerations do you take into account when choosing whether or not to use default_scope?
Further Reading
What time is it? Or, handling timezones in Rails.
As a followup to a stack overflow answer, I thought I would give some examples of working with time zones in rails.
What does Rails timezone support do for me?
- Stores everything in UTC in the database
- Allows you to set an application default timezone and/or timezones for your users
- Automatically converts UTC in the database to the correct zone and back
What zones are available?
You can get a list of timezones with rake tasks:
# Displays names of all time zones recognized by the Rails TimeZone class, grouped by offset. rake time:zones:all # Displays names of time zones recognized by the Rails TimeZone class with the same offset as the system local time rake time:zones:local # Displays names of US time zones recognized by the Rails TimeZone class, grouped by offset. rake time:zones:us
Setting the default time zone
In your environment.rb (Rails 2) or application.rb (Rails 3) file, you can set the default timezone:
config.time_zone = 'Central Time (US & Canada)'
What does this do? By setting an application-wide timezone, any datetime will be stored in UTC in the database, but will be translated when we access it.
Set a timezone for a user
You can use time_zone_select to get a list of timezones for a user to pick from. The third argument is a list of “priority” zones that will appear first.
time_zone_select( "user", 'time_zone', TimeZone.us_zones, :default => "Pacific Time (US & Canada)")
Once the value is saved in the database, you’ll want to set it for each request, per user:
before_filter :set_timezone
def set_timezone
# current_user.time_zone #=> 'Central Time (US & Canada)'
Time.zone = current_user.time_zone || 'Central Time (US & Canada)'
end
[UPDATE: You'll need a field 'time_zone' in your user table!]
[UPDATE: You probably want to stay DRY and refer to the configured value instead of specifying the timezone value in both places:
Time.zone = current_user.time_zone || MyAppName::Application.config.time_zone]
Let me know if you have questions or improvements and I’ll integrate them into the article. Thanks!
Getting the Runaround
Yesterday was my third day on the job and to be honest, it wasn’t a lot of fun. I’m learning a lot of things right now: a new project, new methodologies, and new technologies. Combine all of that with a seemingly useless RSpec error and you can imagine where my blood pressure was reaching.
I had just added a new association to a FactoryGirl factory. I’ve not used FactoryGirl before, but it’s easy enough to copy and paste from other factories in the directory. So far, so good. I wasn’t watching the test output, but it was just one line, what could go wrong?
Several updates and commits later, I thought I’d better make sure we were still “Green”. Eh, not so much. Here’s the output I was seeing repeated over and over again.
Failure/Error: Unable to find matching line from backtrace stack level too deep # /home/user/.rvm/gems/ruby-1.9.2-p0@xxx/gems/activerecord-3.0.0/lib/active_record/locking/optimistic.rb:62
I’ll not bore you with the details of my fruitless search to track this down. Suffice it to say, Wes – that would be my new boss – helped me back out my changes and track down the error.
It turns out that my “simple” addition to the “facility” factory wasn’t so simple. It actually resulted in a never ending loop of weeping and gnashing of teeth.
There are three models which were being dealt with: Facility, User, and Department. Departments have many users; facilities have many departments, and a facility can have a user who is defined as a contact. The schema looks like this:
In my “facility” factory, I was making an association to the “users” table. Unbeknownst to me, the “user” factory was making an association to “department”, which was in turn making an association to “facility”, which was making an association to “user”, ad nauseum. The result: a “stack level too deep” error.
The solution was to just create the user association with the “department” set to nil.
Before:
t.association :contact, :factory => :user
After:
t.association :contact, :factory => :user, :department => nil
Hopefully this will make someone else’s first week on the job go a little smoother and keep them from getting the runaround.
Running rails migrations in other databases
We have a set of Ruby on Rails applications that shares user logins, so we put that table in a database and connect to it from each application.
If an app needs to add a column to the shared table, you can create a migration that accesses that other database.
First, create an entry in your database.yml file (we name ours “user_development”, etc.).
Then, establish that connection in your database migration and do your migration stuff:
This has the benefit of keeping all the migrations local to the app they’re needed for, but it stores the schema of the users table in the users database where it belongs.
Converting erb to haml in rails3
I’m taking over a project that’s just started and prefer to use haml. In setting up my environment to work with rails3 and haml, here’s the best way I found to convert the fledgling app to haml.
Install gems
Run this
This will convert all .erb files in app/views into .haml files right next to them, leaving the originals in case you need to refer to them to fix somethig the converter missed.
This isn’t rails 3 specific, except for the Gemfile part, really.
rspec2, rails3, and spork with drb to get faster tests
I started using rspec2 and rails3 on a project and wanted faster tests.
Gemfile: gem 'spork' bundle install spork --bootstrap
Bootstrapping will edit your spec_helper.rb file with some instructions. I had a vanilla spec_helper file, so everything got moved into the Spork.prefork block.
Also, I’m using autotest, so I added --drb to my .rspec file.
Finally:
spork & autotest
I only had 15 tests at the time that I did this, but they went from running in 6 seconds to running in 1.5 seconds. Significant.
UPDATE:
From the comments, here’s a fix for running rake on Windows (“can’t find executable rake”):
Using Factory Girl with Rails 3
Setting up a new project, I couldn’t get FactoryGirl working. From the README:
If you want to use factory_girl with Rails 3, see http://github.com/thoughtbot/factory_girl_rails
I added this to my Gemfile:
gem 'factory_girl_rails'
A bundle install to install and done.
Note: I’m using rspec2 and putting my factories in spec/factories/*_factory.rb and I’ve seen references to spec/support/factories/*_factory.rb as well. I’m not sure if either is the blessed location.
Overriding Rails’ automatic timestamps: updated_at & created_at
When converting something in a project, I found that I needed to updated a field for every record in a Request table. No problem, except this client grabs a SQL dump and run reports on it. So, Rails’ automatic timestamping of the updated_at field made all of the Requests look like they’d just been updated. Which they had, but not by users.
So, this rake task will reset all of them, presuming you have something to set them to. In my case, I found the latest comment date and used that, but you could figure it out some other way.
git: pull is not possible because you have unmerged files.
I saw this error message the other day and I had no clue what it meant. I’d never seen that error before!
For reference, I was trying to pull from a remote branch and got the error message:
Pull is not possible because you have unmerged files.
A google search revealed this commit (d38a30df7dd54c5c6883) to the git source on January 12, 2010.
The error messages have been updated to be much clearer. Before, you’d get “needs merge” or “error building trees” errors, which didn’t really mean much.
In this case, I was pulling in many commits and had a conflict partway through. I just needed to resolve the files, add/delete them, commit the result and then continue with the pull.

Posted by Samuel Mullen in







