My git Workflow

March 29, 2014

I've settled into what I think is an effectively simple git workflow that I thought would be helpful to share.

Let's say I am working on a new feature. First thing I want to do is make sure my local copy of the codebase is up-to-date:

$ git pull master

I'll then create a new feature branch. In my experience, 99% of the time I am branching off of master:

$ git checkout -b an-awesome-new-feature

But it’s just as easy to branch off another branch:

$ git checkout -b an-awesome-new-feature some-other-branch

Within this new branch, I can spike on the new feature, and if things get hairy I can blow it away and start over. I'll commit often. Most of my commits during the spike or early phase of a feature will look like:

$ git commit -am "WIP specs"

If I am pairing, I will be more descriptive with the commit messages. But when I am coding alone, these pre-PR commits are for me, and are not meant to be used for any meaningful code review. When I am satisfied that I the work I've done will eventually become a PR, I'll push my branch to a remote:

$ git pushr

The pushr command is a nice little shortcut from the dotfiles I use. It creates a remote branch with the same name as my local branch, in this case, an-awesome-new-feature. After the initial git pushr, I can just do git push and it will push to the remote branch.

The "do some work, test, commit, push" loop happens until I am satisfied that the feature is ready for a pull request. If a new feature was merged into master that will effect my feature, I'll pull the changes in, and then do:

$ git rebase master

Recently I've gotten into the habit of rebasing my feature branches whenever anything is merged into master, even if I don't think they will effect what I am doing. I've done this mainly because, if there is a conflict, I'd rather be in merge hell in the middle of working on a feature than at the end of a feature. It's dispiriting when you're about to open a shiny new PR and you realize it won't merge cleanly.

At this point I will rebase and squash all of my commits on the an-awesome-new-feature branch into one commit. This commit message will be as informative (detailed) as possible, since it will become the basis for the pull request message.

Once that's done, I'll force push to the branch with my new rebased history:

$ git push --force

I'll then open my pull request. I will push new commits to the branch after the PR is open, based on feedback. Once I get a :shipit:, I like to re-squash all post-PR commits back into the first PR commit.

There's been some discussion on our team about the merits and demerits of this approach. I like to have one commit per PR when it's possible. It seems cleaner to me. But there's a good argument for not doing this, since those post-PR commits were changes made based on feedback, and that feedback history is important to have. Personally, I feel the comments in the PR on GitHub are sufficient as far as history goes. Usually if I want to dig deeper into what went into a new feature and why, I'll go back and re-read the PR message and subsequent comments, as opposed to reading commit messages in git log. But that's my own preference. The other way is fine too, in my opinion.

In either case, once the PR is merged, the feature branch is deleted locally and remotely. The master is updated locally via git pull, and the cycle repeats.