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
  • Contact
    • Press Room
    • Press Releases
    • In The News
    • Press Kit
  • All
  • Labs
  • Standup
  • Tracker
Kris Hicks

git add -e

Kris Hicks
Monday, May 21, 2012

git add -e is like git add -p, except instead of adding things at the hunk level, you edit the entire patch at once. Or, in other words, whereas git add -p will show you each hunk for every file and ask what you want to do for each of them, git add -e will show you the entire patch and allow you to edit it at will. I used this trick to recently split apart one massive commit into 28 smaller, digestible ones.

Say you’ve replaced a line containing “baz” with one containing “bar”. When you git add -e, you’ll be presented with a diff like so:

foo
- baz
+ bar

From here you can decide, actually, you don’t want to delete baz, you just want to add bar. And you want to add it above baz.

From this spot you can just change the minus to a space, making that line context for the diff. Then you can move the line that adds bar above baz, with this result:

foo
+ bar
baz

After saving and closing the editor you’ll be able to look at the result of your work in the index with git diff --cached:

foo
+ bar
baz

And the line you made into context remains in your working directory, which you can see with git diff:

foo
bar
-baz

But what if you end up modifying the diff in a way that makes it a patch that doesn’t apply? Git’s got you covered there.

Let’s say that when you moved bar above baz, after removing the minus from baz, you added an extra line on accident, making the patch invalid:

foo

+ bar
baz

When you save and close the editor Git will tell you of the problem:

error: patch failed: <some_filename>:1
error: file.txt: patch does not apply
fatal: Could not apply '.git/ADD_EDIT.patch'

In which case you’ll be able to attempt the add -e again, as Git will not have made any changes to the working directory or index at this point.

In some cases Git will attempt to apply the patch and give you the option of retrying the add, re-opening the editor with the modified .git/ADD_EDIT.patch if you choose to retry. If you don’t choose to retry, Git will delete .git/ADD_EDIT.patch.

In addition to editing the patch wholesale via git add -e, you can also choose during git add -p to edit a particular hunk manually by choosing ‘e’ to edit it instead of simply adding it via ‘a’. You can also add a file glob to the end of add -e as you would any other command to limit the size of the patch you’re about to edit.

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

git reset -p

Kris Hicks
Wednesday, May 16, 2012

I’ve been using git reset -p a lot recently and I think it makes sense to clarify what it is that it does because when I first started using it I found it a little confusing.

I sometimes realize that an earlier commit contains some change that I don’t want, so I want to remove it from the commit. This also works when not rebasing, so for simplicity I’ll use an example where the commit to be modified is already HEAD. Previously I would have done:

git reset HEAD~1
git add -p
git commit -C <treeish>
git checkout .

Or, in English:

  • take off the HEAD commit, adding it to the working directory
  • add back the parts you want to keep
  • make a new commit using the message from what used to be the HEAD commit
  • throw away the changes you didn’t want

With git reset -p this process is a little different. Here’s what it looks like:

git reset -p HEAD~1
git commit --amend -C HEAD
git checkout .

Again, in English:

  • apply to the index the negations of certain parts of the HEAD commit
  • amend the HEAD commit with the negations
  • throw away the changes you don’t want

How does this work?

In the second example you added -p to the reset command. This will reset only parts of the original commit, leaving it intact otherwise. That’s worth stating a different way: When you reset -p, the original commit remains unchanged. The only changes are made to your working directory and index.

The trick is to know what you’re doing when you’re saying “y” to a hunk git presents to you for resetting. Say you added a line to the commit originally:

foo
+ bar
baz

But you want to get rid of it. When you git reset -p, git will ask you:

foo
- bar
baz
Apply this hunk to index [y,n,q,a,d,/,e,?]?

If you say ‘y’, Git will apply that hunk to the index. What you also get, however, is the original hunk (that added “bar”) in your working directory.

To summarize, your working directory will have:

foo
+ bar
baz

While the index has:

foo
- bar
baz

While the commit (unchanged, remember) has:

foo
+ bar
baz

You now have a chance to tell git what you want to do, without having done anything to the original commit yet. In the example above, you wanted to get rid of the addition of the “bar” line. To do that, you want to take what’s in the index (the negation of the addition of “bar”) and apply it to the commit, making it go away:

git commit --amend -C HEAD

Then you still have in your working directory the adding of “bar”, which in this case you just want to get rid of, so:

git checkout .

I like using reset -p because it makes it really easy to make small changes to a commit, removing something I added or putting back something I deleted.

reset -p allows you to more easily get a grip on the changes you’ve made and the ones you’re about to make. It also makes much better use of Git, in that you can do even more interesting operations when in the resulting state, which I won’t go into now as to avoid information overload.

And there you have it.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Figuring out what Rails Guide to edit next

Pivotal Labs
Sunday, November 13, 2011

I’ve been contributing to Rails lately by going through the Rails Guides and making sure they’re up to date.

How do I go about finding a guide that hasn’t been updated in a while?

Here’s what I came up with:


ls -1 | perl -e 'while(<>) { chomp; $file = $_; print "$file was"; $changed = qx/git log -1 --format=format:"changed by %an %ar" $file/; print " $changedn" } '

In the docrails/railties/guides/source directory, this outputs:


2_2_release_notes.textile was changed by Vijay Dev 11 months ago
2_3_release_notes.textile was changed by Vijay Dev 8 months ago
3_0_release_notes.textile was changed by ov3y 3 months ago
3_1_release_notes.textile was changed by Rinaldi Fonseca 2 months ago
action_controller_overview.textile was changed by Brian Durand 3 weeks ago
[...]

There’s got to be a better way. I’d like to be able to sort by the date they were last written, etc.

Got any ideas?

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

auto_tagger and alternate tag refs

Pivotal Labs
Wednesday, June 22, 2011

A recent addition to Jeff Dean’s auto_tagger is the ability to use an alternate tag ref type instead of standard git tags. I pestered Jeff to add this feature after Scott Chacon explained to me how bad it is to create a large number of tags in git. Thanks, Jeff, for the feature addition!

There are a couple problems with generating autotags as standard git tags. One is that it pollutes the tag namespace which makes it harder to find tags for releases, etc. And it defeats the tags menu in the GitHub UI. The other is that git will automatically sync tags on every fetch and push, which can noticeably slow things down when you have a lot of tags. And it looks like running GitX with thousands of tags can make the app seriously slow and prone to crash.

A little background: A git tag is just a kind of ref in a special namespace. A ref is a file that contains a SHA-1 has identifying a commit, and is an entry point into the big network of blobs in the git object database. It’s quite easy to create new kinds of refs; you just put a new directory in the .git/refs dir and go from there. auto_tagger will now do this for you simply by adding one configuration option.

Drop a .auto_tagger options file into your project with these contents:

--ref-path=autotags

auto_tagger will automatically fetch and push tags in a custom namespace when it needs to. You almost never need to look at autotag refs in development, but if you do, you may need to fetch them manually. That’s part of the point of using an alternate tag type, avoiding syncing them automatically on every fetch. To manually fetch all the autotags (when using the ref-path=autotags option as above), do

$ git fetch origin refs/autotags/*:refs/autotags/*

I also really like the auto_tagger option to format tag names so they are human readable timestamps by adding a separator character. To make that work, set the date-separator option. Your .auto_tagger options file should look like:

--ref-path=autotags
--date-separator=-

Then your autotags look like “ci/2010-10-09-00-56-21″ instead of “ci/20101009005621″

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Ian Zabel

[Standup][NY] Wed 5/18/2011: TeamCity + git + symlinks == fail

Ian Zabel
Wednesday, May 18, 2011

Interesting Things

A standup of pivots (Sam Coward, Sean Moon, Peter Jaros, and Brent Wheeldon) have recently run into a bug in TeamCity that causes trouble with symlinks when using git.

If you commit symlinks into your repo, TeamCity will not properly transfer these to the build agents. They end up being copied over to the agents as plain text files.

The workaround for this issue is to use Agent-side Checkouts instead of Server-side Checkouts.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Using git bisect to find where something broke

Pivotal Labs
Monday, May 9, 2011

We recently had an issue where our CI build broke over the weekend.

We used git bisect to figure out where the problem occurred.

We wrote a cucumber feature (feature/path/to/is_it_fixed.feature) that worked on Friday and fails today.

We start by setting up git bisect:

git bisect GOOD BAD

Where GOOD is the git SHA from last Friday and BAD is this morning’s SHA.

Then we created a shell script that will setup the environment and run the feature:

#!/bin/bash
set -e

git checkout .
rake db:drop
rake db:create
rake db:migrate
rake db:test:prepare
cucumber feature/path/to/is_it_fixed.feature:20 -r features

We then run this command with the following:

git bisect run /path/to/shell/script.sh

This will then automatically keep running until it finds the SHA that breaks that feature. At the end of the run, it helpfully prints “SHA __ caused the issue”.

Very cool.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Phil Goodwin

Standup 12/17/2010 Comparing indexed date columns, git subtrees, Headless Selenium for CI

Phil Goodwin
Friday, December 17, 2010

Helps

Is there a way to get MySql indexing to speed up queries involving greater and less than operators on date columns?

Postgres handles these operators a little bit better than MySql, but may not actually solve this problem.

Using millis instead of dates would give the DB the best chance of handling this scenario.

We are using Git’s subtree merge facility instead of submodules to stay synced to a different repository for part of our project. How do we push changes back to that repo?

See Tim Connor’s blog post “Git sub-tree merging back to the subtree for pushing to an upstream“. Early in that post is a pointer to an article describing the the subtree merge operation. Tim goes on to explain how to push your changes back through the chain.

Interesting

  • Some cloud environments leave the names of temp files visible even when their contents are not accessible. Be sure to use obfuscated names for your temporary files!

  • The “Headless” gem allows you to easily set up an alternate “display” that allows programs to execute in a headless environment. See this blog post about how to use Headless to run Selenium tests on a CI box: http://www.aentos.com/blog/easy-setup-your-cucumber-scenarios-using-headless-gem-run-selenium-your-ci-server

  • Ccrb will bog down to painfully slow levels if more than a couple of CC Tray clients are pinging it repeatedly during a build.

  • Cron will not honor your .rvmrc file unless you do some work to set up the environment. If you set up your cron job like this:

0 6 * * * /bin/bash -l -c 'echo /home/someuser/.rvm/bin/rvm rvmrc trust ... && cd ... 

the -l & -c parameters cause bash to load your environment as if your were logging in before running the specified commands. Someone also mentioned that rvm-shell can be used as a solution to this problem.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Sarah Mei

Standup 11/4/2010: sweeping-up-the-ticker-tape edition

Sarah Mei
Thursday, November 4, 2010

Is it possible in Jasmine to spy on a getter such as myObject[key]? We want to know when local storage is accessed.

No. Jasmine‘s spyOn only works with functions, and in JavaScript getters are not implemented as functions.

Local storage has a functionally equivalent getValue function, which you can spy on, but the spy is not triggered when you access the value via [].

Interesting:

  • On unicorn, the random number generator is seeded before the fork. So if you are depending on a set of unicorns to generate different random numbers, you need to reseed the random number generator manually after the fork.

  • If you want to make absolutely sure you aren’t generating any queries in your Rails views, try no_querying_views – which explodes if your query comes from view code.

  • Other ways to track down inefficient queries that folks have successfully used: bullet and query_reviewer

  • Skype 5 beta is out for Mac, which allows group video chat. Everyone must be on the beta for it to work.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Sarah Mei

Election Day Special!

Sarah Mei
Tuesday, November 2, 2010

Help:

We made a branch in git called “–track” by accident, and now we can’t get rid of it. git thinks it’s a command-line argument, even when it’s in quotes.

Here’s the command what did it:

$ git checkout -b --track origin/actual_branch_name
Branch --track set up to track remote branch refs/remotes/origin/actual_branch_name.
Switched to a new branch "--track"

Consensus: kill it through RubyMine or gitX. There is also a way through the command line:

$ git branch -d -- --track

…but make sure you get the dashes in all the right places.

Interesting:

  • reset after tail – sometimes, if your PS1 has colors (or square brackets, or … ?) you can lose your Terminal after tailing a file. To get it back, type reset, which should work even if you can’t see it echoing. You may need an extra return before it.

  • The Giants seem to have won! There’s a parade tomorrow, right in front of the office. If you’re coming for the tech talk, leave extra time as streets will be closed and they’re expecting a crowd.

  • 0 Shares
  • Share on Facebook
  • Share on Twitter
Pivotal Labs

Ignoring Tracked Files in Git

Pivotal Labs
Tuesday, June 8, 2010

I occasionally run into a situation with Git where I have modified a file but have no intention of committing the change to the repository. This most often happens with computer specific configuration files. My config/database.yml in Rails projects can spend a lot of time in a dirty state if one of my dev machines has a root mysql password and the other does not.

Git will ignore untracked files that are added to .gitignore files or the .git/info/exclude file. For files that git knows about and is already tracking there is a obscure way to tell git to ignore changes to those files.

git update-index --assume-unchanged config/database.yml

When you have made changes to the file that you want to commit you’ll need to execute the inverse (--no-assume-unchanged) for git to acknowledge that the file has changed.

References:

  • git-update-index
  • gitignore(5)
  • 0 Shares
  • Share on Facebook
  • Share on Twitter

Topics

  • agile (781)
  • rails (113)
  • testing (88)
  • ruby (83)
  • ruby on rails (70)
  • jobs (62)
  • javascript (55)
  • techtalk (44)
  • rspec (38)
  • ironblogger (32)
  • productivity (30)
  • activerecord (29)
  • gogaruco (29)
  • git (28)
  • nyc (27)
  • rubymine (26)
  • bloggerdome (23)
  • mobile (22)
  • process (21)
  • pivotal tracker (21)
  • cucumber (20)
  • design (19)
  • jasmine (19)
  • ios (18)
  • webos (17)
  • objective-c (17)
  • android (16)
  • tracker ecosystem (16)
  • palm (16)
  • "soft" ware (16)
  • fun (15)
  • ci (15)
  • cedar (15)
  • rails3 (14)
  • performance (14)
  • bdd (14)
  • gem (13)
  • css (13)
  • tdd (13)
  • selenium (12)
  • goruco (12)
  • bundler (12)
  • meetup (11)
  • railsconf (11)
  • nyc-standup (11)
  • capybara (10)
  • mac (10)
  • mojo (10)
  • chef (10)
  • api (10)
Subscribe to git Feed
  1. ←
  2. 1
  3. 2
  4. 3
  5. →
  • About
  • Case Studies
  • Team
  • Community
  • Careers
  • 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 >