Restarting a Git Branch

I tend to think about my code a lot, even when I’m not in front of a computer. Sometimes I’ll think of a refactor or performance improvement on the train, in the shower, or as I’m lying in bed right before I get up in the morning. When I have one of these ideas, I tend to just start banging out code the moment I sit down. I often forget to pull or start a new branch first. Fortunately, git makes it relatively simple to move your commits around as long as you haven’t pushed your changes yet. (Once you push your commits, you shouldn’t alter them because someone else may have pulled them.)

The easiest case is if you have changes that haven’t been committed yet. Just create your branch before committing your changes.

git checkout -b great-train-idea
# now on branch great-train-idea
git commit -a -m "Great idea I thought of on the train"

The next-eaisest case is if you have made several commits in master that you haven’t pushed yet, but you want to move them to a new branch. Since branches are simply pointers to commits in git, you can just create a new brach that points at your new changes, then reset master to the commit before you made those changes.

# assuming current branch is master and working directory is clean
git branch genius-shower-idea
git reset --hard origin/master

The example above works with branches other than master too — if you accidentally made commits on great-train-idea that you wanted to move to a new genius-shower-idea branch, just replace master with great-train-idea in the example. Also, if you’ve never pushed great-train-idea (the branch you mistakenly committed to), you can use git log to figure out which commit to revert to instead of relying on the origin/great-train-idea reference.

The trickiest case is if you have made several commits in master, but master wasn’t up to date. The solution here is to move the commits to a new branch as before, then update master, then replay the changes in your new branch using the new updated master as a starting point.

# assuming current branch is master and working directory is clean
git branch awesome-morning-idea
git reset --hard origin/master

# update master
git pull

# make it as if awesome-morning-idea was branched from up-to-date master
git checkout awesome-morning-idea
git rebase master

Again, let me emphasize that you shouldn’t do any of this if you’ve already pushed your changes. Hopefully, if you were so wrapped up in your idea that you forgot to pull or committed to the incorrect branch, you were also too distracted to push. 😉

Code Foo July 2012: Using Git

On Monday I will be presenting an introduction to Git to IGN’s Code Foo class of 2012. Some of the content makes some assumptions about IGN’s workflow, but most of it is generally applicable to anyone new to Git or looking for a refresher. The slides are done in reveal.js and the source is available on GitHub. I also have a copy of the presentation here on my blog.

Flexible Mock Objects with Mockery

If you use stubs and mocks in your PHPUnit tests, you may have run across some of these limitations:

  • You want to call a mocked method more than once and have it expect or return different things on subsequent calls, e.g., multiple calls to query()
  • You want to set up an expectation that mocked methods are called in a certain order, e.g., validate() before save()
  • You want to mock a method that has an argument passed by reference, e.g., MongoCollection::insert()
  • You want to mock a method that doesn’t exist, i.e., the object being mocked only implements __call()

If you have, you may be pleased to know that there’s a drop-in replacement for PHPUnit’s mock objects that supports all of these use cases. It’s called Mockery.

Continue reading

Using Stubs and Mocks in Unit Tests

In the real world, not all unit tests are as simple as

public function testAdd()
{
    $txn = new Transaction(50);
    $this->assertEquals(75, $txn->add(25));
}

For example, a controller for a page that displays tweets might have a dependency on a TwitterService object.

use Zend\Mvc\Controller\ActionController,
    TwitterService;

class TweetsController extends ActionController
{
    public function indexAction()
    {
        $twitter = new TwitterService();
        $tweets = $twitter->getTweetsBy('jtai');
        return array('tweets' => $tweets);
    }
}

If you tried to test this controller like the hypothetical transaction object above, you’d end up with something that looks like this:

public function testIndexAction()
{
    $controller = new TweetsController();

    $expected = array('tweets' => array(
      'Ate breakfast',
      'Good morning!',
      'Ate dinner',
      'Funny cat picture, lol',
      'Ate lunch',      
    ));

    $this->assertEquals($expected, $controller->indexAction());
}

There are a number of problems with this approach. The most obvious problem is that the correct output will vary depending on what I’ve tweeted recently. As soon as I tweet about another meal or post another funny cat picture, the test will break. A more subtle problem is that this test now depends on Twitter being available, so the test cannot be run offline. Also, if Twitter were to go down, the test would fail. Even if Twitter had perfect uptime, the test would run more slowly because it would have to make a real network request. Finally, this is no longer a unit test. The TwitterService object is being tested along with the TweetsControlller.

Continue reading

Continuous Deployment with Brood

I just wrote my first post on the (relatively) new IGN Code blog introducing the deployment system I wrote in December, Brood. Here’s an excerpt that explains what Brood is:

Brood takes a different approach than most other deployment systems. It leverages Gearman to deploy to multiple servers in parallel. Deploys are triggered by a Gearman client, the Overlord. Most deployment tasks (actions) are executed by Gearman workers running on each server called Drones. In this respect, it is more similar to Chef than Fabric or Capistrano which both execute commands on servers directly with SSH.

Each action is encapsulated in a PHP class. What servers to deploy to and what actions to run on them are defined in an XML config file. There are no pre-determined deployment phases in Brood, nor do you specify on the command line which deploy tasks to be executed. Actions simply run one after the other as specified in the config file — the config file defines your entire deployment process. When you specify an action in the config file, you also specify which hosts or host groups the action should be run on. By default, the action will be run on all hosts in parallel, but you can specify a maximum concurrency for each host group. Brood ships with a few common tasks, such as a task to do a “git pull” and a task to send out e-mail notifications about a deploy. Different source control systems, different code distribution or notification methods, etc. can be supported by writing new actions.

Besides the design philosophy, the most interesting feature (and the one I’m most proud of) is the fine-grained control over parallelism. Consider this snippet from the example configuration file:

<!-- Groups of hosts, typically each group is behind 
     a different load balancer -->
<!-- Each host runs a Gearman worker called a Drone -->
<hostgroup name="www">
    <host alias="www1">www1.example.com</host>
    <host alias="www2">www2.example.com</host>
    <host alias="www3">www3.example.com</host>
    <host alias="www4">www4.example.com</host>
</hostgroup>
<hostgroup name="static">
    <host alias="static1">static1.example.com</host>
    <host alias="static2">static2.example.com</host>
</hostgroup>
<action class="Brood\Action\Distribute\Git">
    <!-- Actions are run on hostgroups/hosts concurrently -->
    <hostgroup>www</hostgroup>
    <hostgroup>static</hostgroup>
    <parameters>
        <sudo>deploy</sudo>
        <directory>/var/www/exampleapp</directory>
    </parameters>
</action>
<action class="Brood\Action\Restart\Apache">
    <!-- Within a hostgroup, concurrency can be specified -->
    <hostgroup concurrency="2">www</hostgroup>
    <hostgroup concurrency="1">static</hostgroup>
</action>

With this configuration, all six servers will do a git pull simultaneously. Once that is done, Apache will be restarted on www1, www2, and static1 simultaneously. And once that is done, Apache will be restarted on www3, www4, and static2 simultaneously. Of course, you may not need to restart Apache unless you’re running APC with apc.stat=off, and you probably never need to restart static asset servers. But your deployment process probably includes a task or two that has to happen after git pull, should be done as quickly as possible, but shouldn’t be done on all servers at the same time. Brood makes this incredibly easy.