E x p l o s i o n P i l l s

rebase-based Git Flow for the modern developer

Git Flow, or A successful Git branching model is all the rage these days when it comes to application development -- and with good reason. This is an excellent, if not the preeminent workflow available. It applies to any development methodology that I can think of, and it's especially suited for Agile.

When introducing new developers to the concept of git-flow, it's often done as a whole. We explain the important components like the feature and release branches and try to ingrain knowledge of basic git commands. It's very easy to lose sight of a developers main goal in git-flow which is pumping out easily manageable feature branches at blinding speed.

The git process itself should hardly be a hurdle. This is a tool for collaboration that exists to help us as developers maintain our work and work on teams. I don't think that the git commands that need to be run to publish a release branch should take more than a few seconds -- optimistically.

Initializing your repo on Github

This step is normally done for developers working on business projects already. However, there are times where developers may want to create their own projects for business or personal reasons. First, create the repository on Github itself and set up your ssh keys. Then...

If your repository is being maintained by you, you should also set up a develop branch on Github and ideally make it the default branch in the repository settings.

Branching out

Now that you have a repository, the first concept to grasp when developing feature branches is that you always want to cut from develop -- and an up-to-date develop at that. This means that the first step before even creating a feature branch should be pulling develop.

Ideally you would do this every time before creating a new feature branch. However, your develop branch should never contain changes that origin's develop does not have. Make sure that you stash or otherwise remove outstanding changes before you pull. git status should never report that your develop is any number of commits ahead of origin's develop. It can be behind, of course -- that's why you pull.

Of course if you follow this development model properly, no changes should ever sneak into your develop at all. They should only come from git pull from origin's develop.

Once your develop is ready to go, you can create your feature branch. Features will probably be tied to some user story or bug tracking number in a big company that uses a tool like Jira. For your own projects, you can handle this however you want. Just make sure that you follow your organization's own standards for feature branch naming.

Warning: you should do whatever you can to make sure that you are cutting a branch directly from develop. Use git status, git branch (with no arguments), or others to confirm that you are on the develop branch. You should only cut branches from non-develop branches in advanced cases when you really know what you're doing.

If you're using zsh, you can use git_prompt_info as part of your prompt and it should display the current branch you are on at each prompt. A simple Enter or Ctrl+c will update the prompt to confirm for you.

The art of commit messages

Get some work done on your branch and go crazy with commits. Writing commit messages is important and also difficult to do properly. Make sure that you follow your organization's standards which probably include prefacing all messages with the tracking number for the feature you're working on -- if it's available.

In my opinion, a good commit message starts with a very succinct line summarizing the changes. This line should be at most 50 characters. In fact, if you use git commit without the -m option (yes, this is possible), your editor will open. Vim's syntax highlighting for the git commit message will highlight the first 50 characters on the first line, so you can even tell when you've gone over.

If you have more to say than just 50 characters, enter two newlines and go nuts saying whatever it is you need/want to say. I would still keep the line length limit, but I suggest using Github flavored Markdown for the bulk of the message since most of your commit messages will probably be viewed on Github and this will be easier for others to read. Markdown also has the advantage of being semantic when viewed even before it's parsed into markup and rendered.

Going over the 50 character limit is bad enough, but even worse is the fact that the newline after the introductory line was left out. This extra newline is actually important and it affects how the oneline format of the log message is displayed.

If the extra newline after the first line is omitted, git will simply treat the single newline as a space when displaying logs in the handy oneline format.

Specifying the tracking number in the commit message can be advantageous for some software. For example, it may move the item from "In Progress" to "Development Completed" when your code is merged automatically. It's also helpful for when you have to look at history.

Publishing your changes

Now that you have awesome commit messages and feature code ready to go, you want to deploy these to Github for others to use. But wait! Your organization has decided that it prefers rebasing changes onto the development branch rather than merging them into the branch. Rebasing can simplify things for maintainers.

Without getting into a lot of details about what rebasing is and how it works right now, it's important to know this cardinal rule: Do not rebase the same branch twice!. More accurately, you should not rebase a pushed branch. Even more accurately, you should not rebase a pushed branch that has been pulled and is still being actively worked on.

Most of the time, you probably won't need to rebase a feature branch again. It does depend, though. If your changes get sent back to you, then you won't have much of a choice if you have to make a lot of changes before your feature will be accepted for a merge. If a reviewer refuses to merge a branch that you've already rebased, make sure you discuss how to handle the situation unless you already have a strong understanding of what really goes on with rebasing and how best to add new changes to this branch to complete the feature in a way that the merge will be accepted.

At any rate, other than moving the feature around in your tracking software, you can complete the feature and create a pull-request with a handy script.

This assumes that...

  • you have the handy hub command installed -- a command-line interface for Github
  • git aliased to hub

In case you can't follow it, this script rebases your current branch (hopefully a feature branch -- you may want to double-check) on top of develop, pushes your changes to Github, makes a pull request to merge your feature branch with Github's develop (and prints out a link to it for you) and checks out develop so you can start on a new feature branch again.

You can of course do all of these steps manually. You can create the pull request on Github itself. The ProjectOwner part obviously needs to be changed to the owner of the repo. If you have forked the repo and are using your forked copy as origin, you would be the owner for the -h option. Make sure you type an awesome pull-request message in the same vein as a commit message.

Once your awesome changes have been accepted and merged, you should pull from develop again. At this point, you can use git branch -d feature-branch to delete the feature branch since you don't need it anymore. If you want to delete it before it's been merged, us -D. Just make sure that you've pushed all your changes first!

In Conclusion

As simple as I've tried to make this, it's still a lot to take in. Here are the simplified steps for publishing a release branch with a git-flow rebase model once you already have a working copy of the repo and all you're all set for Github.

  1. Make sure your develop branch is up-to-date.
  2. Cut a feature branch from develop.
  3. Make lots of changes. Write nice commit messages.
  4. Make sure develop is up-to-date... again.
  5. Rebase your feature branch onto develop.
  6. Push your rebased feature branch to origin.
  7. Create a pull request to merge your feature branch into develop.

If you happen to take part in the maintenance of the repo, there may be some work for you now. Luckily, it's pretty simple:

  1. Review the proposed code changes.
  2. Reject the changes with appropriate comments if they're no good
  3. Confirm the merge if it's good. Everyone should be ready to pull from develop again before starting a new feature branch.
  4. Delete the branch, if you're into that sort of thing.

If develop is not up-to-date locally, you may wind up with a lot of unfortunate merge conflicts. It makes sense to work with only one feature branch at a time. This is not always possible, though.

My article makes a lot of assumptions about names. There is nothing special about the names develop, origin, or even master. Make sure that you know the taxonomy/terminology of your repositories for whatever organization you are working for. If one does not exist, work to create the standard.