Pivotal Labs

Main menu

Skip to primary content
Skip to secondary content
  • About
  • Case Studies
  • Team
    • Executives
    • Locations
      • San Francisco (HQ)
      • Boston
      • Boulder
      • Denver
      • London
      • Los Angeles
      • New York
  • Community
    • Blogs
    • Tech Talks
    • Events
  • Careers
    • Lifestyle
    • Principles & Practices
    • Benefits
    • FAQ
    • Apply
  • Tools
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker

Monthly Archives: July 2012

Kris Hicks

Rewinding git pull

Kris Hicks
Monday, July 9, 2012

If you’re using a rebase strategy for the first time you may run git pull in a situation where Git practically tells you to do it, but you don’t actually want to do it. The situation is described below, and the method to unwind it follows. I’ve added pictures of the branches between hashes to make it clear what the state of the world is at any given point prior to or after running a particular command, which I hope makes it easier to follow.

First, you update master, as it’s out of date:

#############################
A--B--C--D origin/master
A--B--C master
#############################

(master) $ git pull
Updating C..D
Fast-forward
...snip...

#############################
A--B--C--D origin/master
A--B--C--D master
#############################

You create and checkout a topic branch, topicA:

(master) $ git checkout -b topicA
Switched to a new branch 'topicA'

#############################
A--B--C--D origin/master
A--B--C--D master
          
           topicA
#############################

You make some changes, commit, and push it to origin.

(topicA) $ git commit -am "Changed README"

#############################
A--B--C--D origin/master
A--B--C--D master
          
           E topicA
#############################

(topicA) $ git push -u origin
(topicA) Counting objects: 28, done.
...snip...
(topicA)  * [new branch]      topicA -> topicA
(topicA) Branch topicA set up to track remote branch topicA from origin.

#############################
A--B--C--D origin/master
A--B--C--D master
          
           E topicA
A--B--C--D--E origin/topicA
#############################

At this point you have your local topicA, and also origin has a copy of topicA:

(topicA) $ git branch -a
* topicA
remotes/origin/topicA

You continue doing work, making more commits on your branch. Some time has passed since you branched from master, and another commit, F, has been pushed to origin/master.

(topicA) $ git fetch # to update your local repository's knowledge of the remote

#############################
A--B--C--D--F origin/master
A--B--C--D master
          
           E--G--H topicA
A--B--C--D--E origin/topicA
#############################

At this point you want to rebase on top of origin/master to get the updates (in this case, F).

$ git rebase origin/master
First, rewinding head to replay your work on top of it...
...snip...

#############################
A--B--C--D--F origin/master
             
              E'--G'--H' topicA
A--B--C--D master
A--B--C--D--E origin/topicA
#############################

And then you want to push your updated topicA, with your new commits and the new commit from origin/master up to origin:

The following assumes you have git config.push default upstream set. This configuration parameter limits the branch that git will attempt to push. I highly recommend you set that value as the default is to push all branches, which you probably do not want.

(topicA) $ git push
To git@github.com:intentmedia/code.git
! [rejected]        topicA -> topicA (non-fast-forward)
error: failed to push some refs to 'git@github.com:krishicks/krishicks.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again.  See the
'Note about fast-forwards' section of 'git push --help' for details.

This is where trouble sets in.

First, Git tells you the push was rejected because you would have lost history. Then comes the troublesome line: “Merge the remote changes (e.g. ‘git pull’) before pushing again.”

If you were working on master and made some commits, and someone else made some commits on master as well and pushed before you did, you would end up with the same situation as above. The push would be rejected because you don’t have the commits that the other person made. Thus, if your push were to succeed their work would be lost on origin/master. This is what Git is referring to when it says “To prevent you from losing history..” The history that would be lost would be the work the other person did.

In the situation we’ve been building up, making commits and rebasing topicA, you’re the only person committing to the branch and the history you would “lose” is the set of pre-rebase commits that you pushed to the remote originally (in this case, E). You’ve overwritten E with E’ during the rebase, and Git doesn’t want you to lose the E that’s on the remote.

What you should do in this situation is git push -f to force-push the branch. You know you’re going to lose E that’s on the remote, but that’s fine because you have E’ on your local topicA. You intend to replace whatever is on the remote with whatever you have locally.

The problem is that it says to do a git pull, which will pull the remote E into your local, which you don’t want. That will give you a merge commit, I:

A--B--C--D--F origin/master
             
              E'--G'--H' topicA
                       
                        I
A--B--C--D master      /
A--B--C--D------------E origin/topicA

If you did a git log at this point you’d see that the merge commit I brought in E, which has the same message but a different SHA than your rebased E’.

(topicA) $ git log --graph --oneline
* I Merge branch 'origin/topicA' into topicA
|
| * E
* | H'
* | G'
* | E'
|/
* D
* C
* B
* A

So, how do you fix this? You can hard reset back to H’, which gets rid of the merge commit, but only if you didn’t already make more commits after the faulty git pull.

(topicA) $ git reset --hard H' # Only if you didn't make any more commits!

If you have made commits after, with your log looking like this:

(topicA) $ git log --graph --oneline
* K
* J
* I Merge branch 'origin/topicA' into topicA
|
| * E
* | H'
* | G'
* | E'
|/
* D
* C
* B
* A

You need to use the two-argument form of git rebase –onto:

(topicA) $ git rebase --onto H' J~1

That will get rid of the merge commit, leaving you with:

(topicA) $ git log --graph --oneline
* K
* J
* H'
* G'
* E'
* D
* C
* B
* A

And now you can git push -f. The docs on git-push (or git push --help) do give you a better explanation than the message when the push is rejected, in the section NOTE ABOUT FAST-FORWARDS.

A simple rule about git pull is to not ever use it unless you’re on master and have made no commits that put you ahead of origin/master, which you can easily tell with:

(master) $ git fetch
(master) $ git log @{u}..

or

(master) $ git fetch
(master) $ git status
# On branch master
nothing to commit (working directory clean)

If the result from git log @{u} is empty or you don’t get “# Your branch is ahead of ‘origin/master’ by commit(s)” message after git status, you’re OK to git pull. In no other case do you need to, or should you, git pull.

I generally recommend always working on a topic branch and keeping master clean to avoid accidentally running git push -f on master, and to enforce the idea that after you fetch, you’re rebasing on top of origin/master directly instead of doing git pull --rebase while on master, which hides the fact that you’re rebasing on top of origin/master.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Charlie Springer

Working on multiple projects? Velocity got you down?

Charlie Springer
Thursday, July 5, 2012

The Tracker Team gets some variation of this question a lot:
“I work on one project one week and a different one another week and it’s really throwing off our project’s velocity. Is there something we can do to account for the changes in team strength?”

Check out this short screencast on how to account for those missing team members and adjust velocity on the fly.

I received this question from one of our recent surveys; if you respond to a survey in the future, leave your contact info so we can get back with you!

-Charlie out.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Trace Wax

GORUCO 2012 Recap

Trace Wax
Tuesday, July 3, 2012

GORUCO outdid itself this year. Always the annual networking and social high point of the NYC Ruby Community, this year’s talks and events exceeded my already high expectations. Here’s a recap of some of the goings on:

Friday night, we warmed up with the GORUCO pre-party here at Pivotal Labs. Those who braved the thunderstorms to get here that night were treated to piles of chicken wings, bartenders serving directly from the Pivotal beer fridge where we all usually just help ourselves, a full open bar and some delightful Ruby-flavored conversation. I spoke with someone who had come all the way from India just to come to GORUCO, as well some of the Hungry Academy folks, up here from D.C. as a prize for winning a contest. The lights were turned on by 11pm so we could all be in good form for the long Saturday ahead of us.

Dr. Nic ‘DrNic’ Williams started us off in the morning with a talk about deployment. A key theme that stuck in my mind was to consider how the tools we use affect our thinking. For example, that’s why we don’t build enterprise on-prem versions of our apps.

Matt Wynne was next with his talk on Hexagonal Rails. He guided the way towards breaking down large interconnected Rails apps into modular, easily testable, maintainable components, making many references to Ruby’s SmallTalk roots. Having recently worked on an app with a test suite that took over an hour to run, I clearly felt the pain he was describing and look forward to implementing his recommendations in upcoming projects.

Francis Hwang then took the stage to talk about our ‘Front-End Future’. Thick Clients using Backbone.js, Ember.js and the like are becoming increasingly pervasive, and for good reason: it can make apps so responsive to users that they don’t know they’re using software. He described when using thick clients would or would not make sense. After the talk, there were several good-natured jokes about how much Javascript was being discussed at a Ruby conference, but that was exactly Francis’s point: we can take the great values we’ve built as a Ruby community and continue to apply them even as we’re using Javascript-based tools more and more in our apps.

All that was much food for thought and conversations over lunch. BBQ meat, tortillas and chips, and guacamole were all piled high with the food we got from the aptly named Mexicue. The line snaked through several rooms but moved quick, and while waiting we had a good chat about TDD in startups.

After lunch and later on in the afternoon there were a series of Micro talks: 10-minute talks on Javascript packaging, MacRuby, API caching and high performance caching, and several other topics. I enjoyed the format; the bite-size talks were well-prepared and were just long enough to go into some depth.

Justin Leitgeb had the first full-length talk of the afternoon, all about sensible testing practices, and walked us through a good mnemonic acronym to keep in mind as we write our tests. What’s not to love about CUPID:
C: Consistent Distance (Integration? Don’t stub. Unit? Don’t integrate.)
U: Unstubbed. Don’t stub anything that isn’t yours
P: Pyramidal (the most unit tests at the bottom of the pyramid, some integrated subset tests in the middle, and just a few end to end tests at the top)
I: Idempotent (Always run specs with –random and kiss test pollution goodbye)
D: Distinct.
His talk had many quotable quotes. My favorite was: ‘In a project that I worked on, one single bug caused 124 tests to fail. I was so perplexed I didn’t know which bridge to jump from.’

David Chelimsky’s presentation reminded us that while DRY stands for Don’t Repeat Yourself, it really means ‘Don’t Repeat Yourself’ unless that doesn’t make sense. For example, if you reduce duplication but that creates a new dependency, that increases coupling of things that shouldn’t be coupled and reduces the quality of your code. He also showed a great example where a Rails route file was de-duplicated completely, leaving a completely unreadable mess of CONST1 + CONST2 + CONST3 code on every line.

Jim Weirich gave the last presentation of the day, opening our eyes to the power of what Rake can do for us. For example, Rake has a lot of native support centered around file lists. He showed an example where he kept a set of images in one directory and had Rake create thumbnails for those images in another directory. Rake notices when a file hasn’t changed, so running it a second time skips the thumbnails it’s already built.

Video of all the talks is available, and fellow Pivot Kris Hicks uploaded his photos of the conference. Check ‘em out!

Once the presentations were done, the GORUCO staff donned their sailor hats and we all headed over to Pier 40 to get on board our yacht cruise. Hungry devs and their significant others were talking about the best algorithm to most quickly make their way through the meat, salad, and pasta serving stations on the boat’s 3 floors. The 210′ vessel was brand new; the staff told us we were the first to spill our drinks on the carpet! The top-shelf open bar was well-provisioned and it’s not surprising that when the very eclectic soundtrack started playing Adele’s ‘Someone Like You’, a large group got an early start to the evening’s karaoke by screaming it at the top of their lungs. I saw the video, but it was deemed too hot for this blog post.

We had great conversations on that boat, technical and otherwise. I spent a bunch of time hanging out with a large group of dev leads from NYC’s hottest startups. One guy was telling me about a day-long pairing exercise that can expand our horizons. Can’t wait to try it!

The boat ride ended with a pass by the Statue of Liberty, directly below a huge fireworks display. The warm night and close view was perfection.

After we returned to Pier 40 and disembarked, many folks headed over to Karaoke Cave in the Village to sing until the wee hours. I couldn’t make it, but I heard that it was very fun and memorable. So much so that the people I spoke with couldn’t remember some of it! But apparently, Dr. Nic can really hold a tune.

Thanks again to the GORUCO organizers for putting together such a great event. Looking forward to next year!

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Kris Hicks

quick tips

Kris Hicks
Tuesday, July 3, 2012

The following are things I found very helpful, which you also may find make your day-to-day usage of Git more enjoyable.

Go HEADless

In many (and perhaps all) cases HEAD is implied when no ref is given, such as the following equivalent statements:

$ git log origin/master..HEAD
$ git log origin/master..

Upstream reference

Before you start referring to the upstream, you’ll want to do a git fetch to update your refs/heads:

$ git fetch

You only need to do this once in a while, or whenever you know the upstream to have changed.

You can refer to the upstream of any branchname or otherwise symbolic-ref by appending @{u} to the ref, such as:

$ git log master@{u}

If you just want the upstream of the current branch, whatever it may be, you can replace master from above with HEAD:

$ git log HEAD@{u}

Upstream difference

Oftentimes I’ll want to see what commits are on upstream that I don’t have. I usually will do this via:

$ git log @{u}..

Which, when on master, is equivalent to:

$ git log origin/master..HEAD

You can see the reverse difference, or the commits are on the remote that you don’t have, by reversing the range:

$ git log ..@{u}

Which, again on master, is equivalent to:

$ git log HEAD..origin/master

To see the full list of formats recognizable, see git revisions --help

If you want to see both of the above at the same time, you can use git log with the –left-right parameter. I’ve also included –format=” and –oneline (which must be passed in that order), which may be optional depending on your format configuration, but for me are not:

$ git log HEAD@{u}...HEAD --left-right --format='' --oneline

Which can be shortened to:

$ git log @{u}... --left-right --format='' --oneline

Note: The above example uses three dots, not two, to show only the commits which are reachable as ancestors of one branch but not the other.

You can replace HEAD in the above with any symbolic-ref or branchname to use as a reference instead. The output (with the format given previously) will look like:

< e86bd83 D
< 6ea2155 C
> eb2de55 B
> 74829bd A

Commits beginning with “<” are only on the left side of the triple-dot (in this case, the upstream), commits beginning with “>” are only on the right side (in this case, the current branch). A..D are the commit messages.

Is it merged?

To find out if a particular branch has been merged into origin/master, you could dig through the log on master and search for it:

$ git log origin/master

Or, if you knew who would have merged it, you could limit the above with that:

$ git log origin/master --author Kris

I wanted a better way, and I found it. I wanted to see if a particular branch had been merged to master without changing branches or having to dig through a log looking for the merge of the branch.

The situation that prompted this was that I had a topic branch, topicB, which depended on another topic branch, topicA. I wanted to see if topicA had been merged into master to find out if I could rebase onto master to get up to date, or if I should continue rebasing on top of the branch.

$ git fetch
$ git branch --contains topicB@{u} -r

This gives you a list of all the remote branches that can reach (as an ancestor) the ref given. origin/master will be right at the top if the branch has been merged into it.

Many thanks to John Wiegley, Scott Chacon and Mark Longair for the sources of the tips.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Mark Rushakoff

JavaScript disappoints yet again: sorting an array of numbers

Mark Rushakoff
Tuesday, July 3, 2012

We were writing a spec yesterday where we had a method that was returning an array of numbers in no particular order, and we wanted to verify its output. It went something like:

expect(model.foo().sort()).toEqual([1, 2, 3, 10, 25]);

The error message from Jasmine was something like “expected [1, 10, 2, 25, 3] to equal [1, 2, 3, 10, 25]“.

I couldn’t believe it. I wanted to sort an array of numbers, and JavaScript decided it would do me a favor and cast them all to strings first.

The workaround is simple: Mozilla recommends just passing a comparison function to sort:

expect(model.foo().sort(function(a, b) {
    return a-b;
})).toEqual([1, 2, 3, 10, 25]);

When you’re working in JavaScript everyday, you learn to expect the unexpected to some extent, but even this one threw me off.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Sean Beckett

New MBA plus Migration Assistant can lead to runaway Dock process

Sean Beckett
Monday, July 2, 2012

With the power contained in the newest 13″ MacBook Airs l was ready to give up my 27″ iMac for a laptop plus Thunderbolt display. My new laptop arrived today and after a few false starts with Migration Assistant, we got everything moved over and I switched to using my new machine.

While browsing Google Reader during lunch, I was getting hangs just moving between articles. A quick check of iStat Menus showed that two of my four cores were chugging at a constant 70% load, even after I closed all applications. I ran top -o cpu in Terminal to see what processes were burning up the wires and it turned out to be Dock, an Apple OS X internal process. A few minutes Googling lead me to this helpful page on MacRumors and specifically this post. I did indeed have a custom desktop pic on my old machine so this seemed a likely culprit.

I checked the contents of the ~/Library/Preferences/com.apple.desktop.plist and didn’t see anything earth-shattering. It appears to contain only options related to the desktop pictures (if they change over time, where are they located, etc.) Removing the plist is highly unlikely to have any long-term negative consequences, but to be extra careful, you can use these steps that don’t destroy your old plist:

Open Terminal and run

mv ~/Library/Preferences/com.apple.desktop.plist ~/Library/Preferences/com.apple.desktop.plist.bad
killall Dock

This caused the desktop to refresh, loading the default Lion background, and my CPU usage instantly dropped to sane levels. I opened up System Preferences and went to the Desktop pane and was able to quickly restore my preferred background image.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (783)
  • rails (117)
  • testing (90)
  • ruby (86)
  • ruby on rails (71)
  • jobs (62)
  • javascript (59)
  • techtalk (44)
  • ironblogger (42)
  • rspec (39)
  • bloggerdome (34)
  • productivity (34)
  • activerecord (30)
  • rubymine (30)
  • git (29)
  • gogaruco (29)
  • nyc (27)
  • design (24)
  • mobile (23)
  • pivotal tracker (22)
  • process (21)
  • cucumber (21)
  • jasmine (19)
  • ios (18)
  • tracker ecosystem (17)
  • webos (17)
  • objective-c (17)
  • fun (16)
  • android (16)
  • palm (16)
  • ci (16)
  • "soft" ware (16)
  • bdd (15)
  • tdd (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • css (14)
  • gem (13)
  • mouse-free development (12)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • api (12)
  • keyboard (11)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
Subscribe to Community Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. 4
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • Tools
  • Contact
  • Labs
  • Events

Contact Us

contact@pivotallabs.com
+1 415-77-PIVOT
TwitterLinkedInFacebook

Pivotal Tracker

Tracker is the award-winning agile project management tool that enables real-time collaboration around a shared, prioritized backlog.
Visit pivotaltracker.com >