Too often, I come across GitHub Pages branches (
gh-pages) branches that are simply forks from the
master branch of the repository. This is not ideal.
There are several problems with this strategy:
gh-pagesbranch every time you add a commit to master, you will be out of date.
It introduces the need to have lines like this in
_config.yml to prevent unrelated files from being included in the
exclude: ./app, ./lib, ./project.gemspec, ./Gemfile, ./LICENSE, ./Rakefile, ./readme.md, ./features, ./spec
git checkout --orphan gh-pages
When it comes time to create a GitHub Page for your project, use the above command. This creates a branch that is completely separate from the history of the rest of the repository. You will need to delete the files by running “
git rm -rf .”:
If you want to start a disconnected history that records a set of paths that is totally different from the one of <start_point>, then you should clear the index and the working tree right after creating the orphan branch by running "git rm -rf ." from the top level of the working tree. Afterwards you will be ready to prepare your new files, repopulating the working tree, by copying them from elsewhere, extracting a tarball, etc.
git checkout --help
After you have an empty branch, you’re ready to get started on your jekyll or HTML site with a clean history and a clear conscience.
Written by Caleb Thompson
Setting up a new Xcode project is as simple as ⇧⌘N. Unless you want to do things the right way, at which point there are a number of other configurations you need to worry about:
.gitattributes, project level indentation settings, warning levels, etc. After doing the same setup procedure a few times, you can make it a relatively quick process. But it’s 2013, and we’re living in the future now. We have the technology to build tacocopters, but I still have to set my error levels manually? That’s just ridiculous.
liftoff is a small Ruby gem that we’ve been working on to make new Xcode project setup as fast and painless as possible. With one simple command, you’ll have a slew of defaults set up for your project, along with some things that we think will make your life in Xcode a bit nicer.
First, install the gem, which is as simple as
gem install liftoff. Then, while in your project directory (wherever you are keeping the
.xcodeproj file), just run
liftoff. This will set up the project defaults we like to use:
These commands can be run individually as well. For example, setting the project’s indentation level to 2 spaces can be done with
liftoff indentation 2.
The best part about using liftoff over another solution like a custom project template is that liftoff can be used to quickly add these settings to an existing project without worrying about stomping on your current setup.
liftoff is currently at version 0.6 and, as usual, the code is open source on GitHub. We hope you enjoy it as much as we do.
This blog post is about refactoring, git, long-lived branches, and scope creep. It has a lot to say, so here is a summary:
There are three relevant kinds of refactorings: fixing large swaths of code to go from ugly to less ugly; the “refactor” step of “red, green, refactor”, where the thing you just wrote is improved, and; changing an existing architecture to better handle a new feature.
The first of these—improving code from ugly to elegant—is actually an example of a re-write, should probably be avoided, and definitely should live as its own entity. Working on this while working on another feature is an example of scope creep, and pretending that it is relevant to your feature is lying to yourself. This is not the blog post I want to write now, but stop doing this please.
The third step of “red, green, refactor” is an important one. The feature is not done if you skip this step. The whole point of “green” is to get to “refactor”. But it can be easy to lose sight while doing this step; it’s easy to start re-implementing irrelevant parts of the system. When going down this path it’s good to consider another option: back out the “green”—go back to the failing test—and make a change to the existing system in preparation for the implementation.
That brings us to the third kind of refactoring: re-architecting toward a goal. This is when you can use a classical best practice (as examples: composing instead of inheriting; replacing a global with an instance variable) to make your feature easier to implement. It’s the most fun kind of refactoring: you have a clear problem to solve with a secondary ideal of improving the codebase for all.
Don’t run an experiment without a control. Don’t conflate correlation with causation. Don’t whiz on the electric fence. Don’t refactor with broken tests. Sure sure, we’ve heard it all before, but sometimes things come up!
For serious, cut it out. Instead, use this workflow.
Let’s look at an example. In this example, we have a small gem that connects to a singleton database connection to fetch some data.
require 'sequel' module Ikea DB = Sequel.connect(ENV['DATABASE_URL']) class Couch def all DB[:couches].all end end end
The test is super chill:
require 'rspec' require 'ikea/couch' describe Ikea::Couch do it 'produces all the couches' do Ikea::DB[:couches].insert('BoConcept ripoff') Ikea::Couch.new.all.should == ['BoConcept ripoff'] end end
There is some setup involved, and the test is slow, but it passes and the code stays simple. Rocking. But now we need a new feature:
it 'produces the empty list if the DB is down'
We could mock the constant, but that’s annoying and problematic.
We could redefine the
DB constant, but that’s dumb.
Alternatively, we could pass a database connection, just like the
TDD gods intended. We’ll do that.
First step: commit what we have:
git checkout -b db-is-down git commit -am wip
Then make a new branch off
git checkout master git checkout -b no-singleton-db
Make the change:
module Ikea class Couch def initialize(db) @db = db end def all @db[:couches].all end end end
require 'rspec' require 'ikea/couch' describe Ikea::Couch do it 'produces all the couches' do fake_table = double('couch table', all: ['BoConcept ripoff']) fake_db = double('db connection', : => fake_table) Ikea::Couch.new(fake_db).all.should == ['BoConcept ripoff'] end end
Submit for a code review:
git commit -am "Move from a singleton DB to a composed DB connection" git push hub pull-request
Go back to your feature, still in progress:
git checkout db-is-down git rebase no-singleton-db
This tiny refactoring branch may seem like a waste, even confusing. Multiple short-lived branches just to implement a single feature, asking your coworkers for a five-line code review, branching off master instead of your feature branch, rebasing. Rebasing!
But think of the alternatives: a single long-lived branch that sits in isolation, asking your coworkers for a long code review, branching off a branch (and perhaps branching off that!). And rebasing makes you feel like a badass, admit it.
As a bonus, these branches help keep you focused and on-scope. Make a branch for a tiny change, and you’ll be sure to make the tiny change. That’s all you have to focus on. No distracting features or broken tests, just that one refactoring.
This will seem slow at first. That’s OK, let it be slow. It, like TDD, will become second nature if you try.
As a useful trick, pair with someone who already does this. They’ll set you straight.
Many shell or git aliases can be built atop this. Try it out and build your own. Tweet at us with your dotfiles if you’ve made some useful ones!
Way back in mid-2007, when Rails 1.2 was the new hotness and GitHub was still a year away from crawling out of the primordial internet soup, prolific open source contributor Dr Nic wrote an article titled “8 steps for fixing other people’s code”. It offers excellent general advice, but the workflow details are clearly a product of their time: RubyForge, SVN, and
.patch files feature heavily.
Here in the fantastical future world of 2012, while we still don’t have hoverboards or household nuclear fusion, we do have some great tools that make fixing other people’s code a lot easier. Join me as we rewrite “8 steps” for the modern age!
Open source projects are usually far from perfect. In many cases they started as something the author threw together to solve a problem, then released into the wild just in case it could be useful to someone else. Open source contributions come from regular people — just like you! — who start using the project and run into a bug that annoys them, or get an idea for a feature that would make their life easier.
The experience that prompted me to write this post started with finding a bug in Chronic, a date-parsing library. The issue is described in the pull request I submitted to fix it (pull requests are the final step in this process; we’ll get to them in a bit).
In recent years git and GitHub have emerged as the de facto standard, if not for open source projects in general, then at least for open source Ruby projects. Lucky you! In Dr Nic’s time it was all SVN, uphill both ways.
If your target project has a web site, it will probably link to the official GitHub repository. Failing that, you can search GitHub for the name of the project. This may also turn up other people’s forks of the project — if you’re not sure which one is the original, just pick one and follow the “forked from” links.
Once you’ve found the repository, scroll down to the README and scan it for “How to Contribute” directions. Some projects have a particular process they want contributors to follow, and it might be different from the steps outlined here. Chronic’s instructions are typical and straightforward.
Forking a project creates your own personal copy of the repository that you’re free to modify however you want. It’s integral to the GitHub workflow, and is therefore stupidly easy: Just hit the Fork button.
Copy the Read+Write link from your newly-forked repo and clone it down:
$ git clone firstname.lastname@example.org:grantovich/chronic.git Cloning into 'chronic'...
Then copy the Read-Only link from the original repository (mojombo/chronic in my case) and add it as a “remote” like so:
$ cd chronic $ git remote add upstream git://github.com/mojombo/chronic.git
Many projects use automated tests to ensure that bugs stay fixed and new features don’t introduce new bugs. Running a project’s tests is also a useful sanity check, since no tests should fail on an unmodified clone of the master branch.
Before doing this, you’ll need to install the project’s dependencies — if it has any, it should include a
gem install bundler to install Bundler if you haven’t already, then simply
In most Ruby projects, running “
rake” with no arguments will execute the full test suite. Ensure this doesn’t give you any failures before proceeding.
Come up with a short, descriptive name for a branch that will contain your changes. Here’s my Chronic branch:
$ git checkout -b handle-sm-sd-with-time
Now you’re ready to start coding! Assuming the project has tests, you can do some TDD and start by writing a failing test. Poke around the existing test suite — it likely involves Minitest or Rspec — then write one or more new tests that would succeed if your feature existed or your bug was fixed.
Re-run the test suite to ensure your tests fail (and you didn’t somehow break any other tests). Then, write the code to make them pass! Follow the style of the existing code as much as possible, and resist the temptation to “clean up” or reformat things that aren’t relevant to your change.
Many libraries have Rake tasks applicable to this step.
rake console is a common task that opens an IRB shell with your in-development copy of the library loaded into it. If the library is made available as a gem, there will be a task that builds the gem (e.g.
rake build), and you’ll want to make sure this still works after you change things.
Note that while the changes I made to Chronic were in multiple commits, you should really put both the tests and the code that passes them into a single commit. Any given commit should pass all the tests that exist within it. You can still make multiple commits locally — just squash them later using
git rebase -i origin/master.
If you’ve added a new feature or changed how something works, and the project’s documentation lives in the repository (this is usually true for at least the README file), update it to be consistent with your changes. Documentation never gets enough love, and the owner will probably appreciate your thoughtfulness.
Pull down any changes made to the original repository since you started working, and replay your commits onto the updated code. This ensures that your changes can still be successfully applied to the latest version. It sounds complicated, but the commands are quite simple:
$ git fetch upstream $ git rebase upstream/master
Here’s the other half of the fork-based GitHub workflow. After making changes in your fork, you request that the original author pull those changes into their repository.
First push the branch containing your commits up to GitHub…
$ git push -u
…then hit the Pull Request button on your forked repository.
Set the “head branch” on the right side of the pull request to your new branch.
You’ll be prompted to give your pull request a title (e.g. “Add support for XYZ”) and detailed description. Fill these in, and hit the Send pull request button!
Now comes the hardest part: Waiting. The owners of the repository will be notified of your pull request, and at some point — hopefully — will get around to reviewing it. They might suggest some changes: Make them in your branch and
git push, and the pull request will automatically update with your new commits. If your changes look good, they’ll be officially merged into the project. Success!
After you’ve done this once for a given project, the process is simplified: When you’re ready to contribute again,
git pull upstream master so you’re working with the latest code, and start again from step 4.
While the GitHub web interface is more accessible if you’re not used to the workflow yet, it’s actually possible to do all this without leaving your terminal. Check out the hub tool, and more specifically the commands dealing with forks and pull requests. In fact, my Chronic pull request was originally a bug report that I later “converted” using
Remember these steps are more like guidelines than actual rules. Every project is different, and the owners of the one you’re working on might prefer you do things a bit (or a lot) differently. Be receptive to the feedback you get on your pull requests, even if it seems nitpicky. You’ll be hailed as a model open source citizen in no time!