---
title: Remote Branch
teaser:
tags: git
author: Dan Croak
published_on: 2012-04-18
---

Does your pair programmer maintain order, keeping the mean streets (ie. remote
branches) clean? Let's ride along with a remote branch cop to see how they
work.

![Remote Branch poster](http://images.thoughtbot.com/ui/remote-branch.png)

## fetch

Once inside the squad car, the cop runs `git fetch origin`:

    remote: Counting objects: 45, done.
    remote: Compressing objects: 100% (27/27), done.
    remote: Total 28 (delta 23), reused 0 (delta 0)
    Unpacking objects: 100% (28/28), done.
       0417137..5eb7f00  2933-upgrade-factory-bot -> origin/2933-upgrade-factory-bot
     * [new branch]      3159-fix-mobile-web -> origin/3159-fix-mobile-web

The manual tells us what happened:

> The above command copies all branches from the remote refs/heads/ namespace
> and stores them to the local refs/remotes/origin/ namespace.

This is useful for seeing what's new in the remote named `origin`.

## rebase

If we're currently working in a local feature branch, we might look for
something like this in the output of `git fetch origin`:

    84d3635..19780cc master -> origin/master

If a line like that is in the output, there's something new in `origin/master`
that we might want to investigate and `git rebase origin/master` into our
feature branch.

## tracking

However, the output in this case tells us that two remote branches have
changed:

    0417137..5eb7f00  2933-upgrade-factory-bot -> origin/2933-upgrade-factory-bot
    * [new branch]    3159-fix-mobile-web -> origin/3159-fix-mobile-web

The `2933-upgrade-factory-bot` branch is one we had tracked and was since
updated. The `3159-mobile-web-fixes` branch is a new branch.

## git branch -r

We view our existing known remote branches with `git branch -r`:

    origin/2933-upgrade-factory-bot
    origin/3114-add-validations-for-subscription-token
    origin/3159-fix-mobile-web
    origin/HEAD -> origin/master
    origin/master
    origin/production
    origin/staging

The `git branch -r` command works without an internet connection. It has all
the data stored in git objects from the earlier `git fetch origin`.

## remote tracking branches

We can see those objects with `ls .git/refs/remotes/origin`:

    2933-upgrade-factory-bot
    3114-add-validations-for-subscription-token
    3159-fix-mobile-web
    HEAD
    master
    production
    staging

These are the "remote branches", or more formally named "remote-tracking
branches" in the git `man` pages, but who has time for that mouthful when
serving and protecting the general populace?

The more formal name is clearer because the remote branches are not the actual
remote's branches. They are like pointers or bookmarks to `origin`'s branches.

## naming convention

The naming convention of `ticket-number-verb-noun` is nice for quickly finding
things and tab completing. For example: `git branch -r | ack 2933` outputs:

    origin/2933-upgrade-factory-bot

For more on `ack`, see [betterthangrep.com](http://betterthangrep.com).

When a teammate asks us to review their code on "ticket 2933", we could:

    git fetch
    git diff origin/master..`git branch -r | ack 2933`

However, that's only the diff without syntax highlighting. GitHub is better for
this.

We can do better by using the number to check out a new tracking branch:

    git checkout `git branch -r | ack 2933 | sed 's/.*\///'`
    Switched to branch '2933-upgrade-factory-bot'
    Your branch is behind 'origin/2933-upgrade-factory-bot' by 1 commit, and can be fast-forwarded

We're too busy fighting crime to type that again. So, we abstract it to a
script:

    #!/bin/sh

    code-review()
    {
      branch=`git branch -r | ack $1 | sed 's/.*\///'`
      git checkout $branch
    }

Now, we can `code-review 2933` or even `code-review 3159`, which creates a new
branch and immediately tracks `origin/3159-fix-mobile-web`.

## local machine code reviews

GitHub pull requests for [feature branch code
reviews](https://thoughtbot.com/blog/post/2831837714/feature-branch-code-reviews)
have benefits:

* People can review code at the same time (parallel processing).
* People can comment at the line level (good for discussion).

However, code reviews on our local machines have benefits, too:

* Run tests after checkout so they run while you review (parallel processing).
* Read surrounding context of the diff in your editor (faster understanding).
* Make small changes yourself, without relaying to the original author things
  like "formatting", "spelling", "parentheses" in comments (faster fixes).
* Use the app, perhaps in a web browser. (smoke test it works as intended).

## squash

While helping our teammates is part of the job, we have our own beat (our own
feature branches) to finish and send for a code review.

We've been working on a feature that adds the
[Chosen](http://harvesthq.github.com/chosen/) plugin to an admin screen, which
required about an hour of overriding styles with `!important`.

The code now works, passes tests, and looks great in a browser. We're almost
ready for a code review.

We've been making many small commits in our feature branch as we wrote the
feature but to be nice guys toward the reviewer, we squash the commits down to
one [good commit
message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html):

    git checkout 4000-use-chosen-in-admin-section
    git rebase -i origin/master

The `-i` flag is an interactive rebase, and opens our`EDITOR` with:

    pick 28e91bb [#4000] Add Chosen as Javascript asset
    pick 2043850 [#4000] Link to Chosen stylesheet in admin layout
    pick fd38b60 [#4000] Add Chosen to select field
    pick 34c2e5c [#4000] Fix Chosen formatting

    # Rebase 19780cc..34c2e5c onto 19780cc
    #
    # Commands:
    #  p, pick = use commit
    #  r, reword = use commit, but edit the commit message
    #  e, edit = use commit, but stop for amending
    #  s, squash = use commit, but meld into previous commit
    #  f, fixup = like "squash", but discard this commit's log message
    #  x, exec = run command (the rest of the line) using shell
    #
    # If you remove a line here THAT COMMIT WILL BE LOST.
    # However, if you remove everything, the rebase will be aborted.

The comment tells us what to do but we're no rookies: been doing this for years!

Fingers like lightning, we squash it down:

    pick 28e91bb [#4000] Add Chosen as Javascript asset
    squash 2043850 [#4000] Link to Chosen stylesheet in admin layout
    squash fd38b60 [#4000] Add Chosen to select field

Since we didn't actually change anything, we don't feel the need to run the
tests again and just force push to `origin`:

    git push -f

We ask a teammate for a code review. They oblige.

A few minutes later, they surprise us with a question:

> Did you forget to commit some files?

Confused, we check the commit.

To our horror, we realize we accidentally `dd`'ed in vim the time-consuming
commit that we don't think we can easily re-write.

To make matters even worse, with the interactive rebase, we re-wrote the git
history! When we force pushed, we overwrote the clone on `origin`!

Our families start screaming: "We're burning alive! I can't feel my legs!" Here
comes the meatwagon: "Whee-ooh! Whee-ooh!" The medic gets out and says [Oh. My.
God.](http://youtu.be/S2XvxDaIwCw) New guy's in the corner puking his guts out:
"Bleah! Bleah!"

## reflog

Just then, your grizzled old partner calmly types `git reflog` into the shell:

    df83012 HEAD@{0}: checkout: moving from 4000-use-chosen-in-admin-section to df83012
    3bc02a4 HEAD@{1}: commit (amend): [#4000] Use Chosen in admin section
    9dd0667 HEAD@{2}: rebase -i (squash): [#4000] Add Chosen to select field
    9dd0667 HEAD@{3}: rebase -i (squash): [#4000] Link to Chosen stylesheet in admin layout
    7d14c9d HEAD@{4}: rebase -i (pick): [#4000] Add Chosen as Javascript asset
    7a0ed21 HEAD@{5}: rebase -i (squash): updating HEAD
    19780cc HEAD@{6}: checkout: moving from 2933-upgrade-factory-bot to 19780cc47583778009f7a2c4b52dbb50bda1d78f
    b6fd856 HEAD@{7}: commit: [#4000] Fix Chosen formatting

He copies the SHA1 hash and types `git merge b6fd856`, then `git log`:

    9eaa992 [2 seconds ago] Merge commit 'b6fd856' into 4000-use-chosen-in-admin section

Whoa. That was close.

We make a mental note to run tests after future rebases and before force
pushes, for `reflog` is an option of last resort, like a union lawyer.

## prune

Before we end our shift, we `git remote prune origin`:

    - [deleted] 3159-fix-mobile-web

The manual explains:

> Deletes all stale remote-tracking branches under origin. These stale branches
> have already been removed from the remote repository referenced by origin,
> but are still locally available in remotes/origin.

So, it looks like 3159 was merged in or deleted on `origin` by another teammate.

Works for us. Let's [go for a taste](http://youtu.be/EVEwpYt0EwE).

**Fake movie poster by [Kyle Fiedler](http://twitter.com/kylefiedler). For more
posters, see [Team
Rotations](https://thoughtbot.com/blog/post/1133585959/team-rotations).**
