githublink.vim Plugin

I use Vim as my primary editor. I also use GitHub for a lot of my projects. On more than one occasion, I have found myself wanting to share the line under my Vim cursor with a collaborator in the form of a github.com link. The manual process went something like this:

  • Go to github.com in a browser
  • Navigate to the correct repository and branch
  • Drill down to the file I was working on
  • Find the line in the file and click on the line number
  • Copy the URL and paste it in the email or instant message

Wouldn’t it be nice if you could just hit a hotkey and have Vim figure out the URL for you? I thought so too, so I started hacking on Vim plugin to do exactly that.

To use the plugin, install it, then start editing a file that’s part of a GitHub-hosted repository. Press \ g (backslash, followed by g) to display the URL of the current line. You still have to copy and paste the URL, but everything else is done for you. Update: the plugin now copies the URL to the clipboard for you if pbcopy is available.

Some of the constructs for the plugin are borrowed from rubytest.vim, so thanks to janx for the rubytest plugin. This is my first foray into Vim script, so if there are better ways of doing things, please share!

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.

Jenkins, Ant, and Closure

At work we use Closure to minifiy our JavaScript at deploy-time. We also use Jenkins (we actually named it Leeroy Jenkins, because I work at IGN) to automatically test and merge changes from our integration branch into our production branch. I wanted to configure Jenkins to build our JavaScript files with Closure to ensure they’re syntactically valid before merging them into the production branch.

My first thought was to write a Python script, but it seemed lame to have our static repository depend on Python, even though it comes pre-installed on most Linux distributions. Plus, I didn’t want to have to add a bin directory to the static repository. (We have a separate git repository for static CSS, JavaScript, and image files to keep the main code repository lightweight.) Running all the JavaScript files through Closure is a simple enough task that I should be able to write a shell one-liner and just stick it in our build.xml Ant file, right?

Continue reading

Resetting Whitespace-Only Changes in Git

I used find -exec with sed to do a repository-wide find/replace this morning. Unfortunately, some of the files in the repository didn’t have a newline at the end of the file, but sed added one. I wanted a one-liner to reset all the whitespace-only changes, and I found it on stackoverflow:

git diff -b --numstat \
| egrep $'^0\t0\t' \
| cut -d$'\t' -f3- \
| xargs git checkout HEAD --