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.
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:
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"
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.
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.
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.
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.
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.
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:
Ask for Help
Passenger Memory Bloat
"We found one of our passenger workers is using around 900MB of memory. Has anyone has problem with Passenger memory usage? We are using REE 1.8.7-2009.10."
Solr Master-Slave Replication
"We are interested in adding automatic failover to our Solr slave when the master fails. What are some strategies for doing this?"
Interesting Things
Git Push --force Blocked
If you find your git push being rejected, even when you use git push -f, it's probably because your git server is configured to not allow non fast-forward pushes. You'll need to change the server configuration to allow them.
spec --timeout
Be careful when running rspec with the --timeout option. When the timeout occurs the test process will be interrupted and it will print out a stack trace for wherever it was executing when it was interrupted. This can lead to a lot of confusion if you do not immediately realize it was the result of timing out and instead think that an exception actually occurred at that point.
