A couple days ago, I did a presentation on my dotfiles manager (dfm) at the local Perl Mongers meeting. It was a phenomenally rewarding experience. The Perl community has always been fun and engaging and this meeting was no different.
Here’s the source for the slides and a PDF rendering for ease of perusing. It’s a good overview of current usage as well as a laundry list of future features.
The sbt-scalatra-example project combines two great technologies. The first is Scalatra, a super light-weight web framework for Scala that’s modeled after Ruby’s Sinatra. The second is the simple-build-tool (sbt), a tool for building Scala applications that’s more like rake (config file written in real programming language) than make or ant/maven (config file written in an abstract form). I was able to run the example, but I wanted to try out deploying to dotcloud, and doing that requires a war file (according to the java service documentation).
The biggest thing I had to figure out is that as of version 0.10 of sbt, web application support is now in the xsbt-web-plugin plugin. Just knowing that would have saved me an hour this morning. Setting that up and tweaking a few other files means I can now do this:
123456789101112131415
$ sbt clean package-war
... snip ...
[info] Packaging /home/user/sbt-scalatra-example/target/scala-2.9.1.final/sbt-scalatra-example.war ...
[info] Done packaging.
[success] Total time: 13 s, completed Sep 23, 2011 3:57:00 PM
$ cp target/scala-2.9.1.final/sbt-scalatra-example.war dotcloud/ROOT.war
$ dotcloud create sbtscalatra
Created application "sbtscalatra"
$ cd dotcloud && dotcloud push sbtscalatra
... snip ...
Deployment finished. Your application is available at the following URLs
www: http://sbtscalatra-xxx.dotcloud.com/
Of course, this assumes you’ve installed sbt (brew install sbt on the mac) and signed up and configured Dotcloud.
I’m about to finish up my time here in beautiful North Carolina. The rental car is returned and I’m waiting for my plane to arrive and take me back to the west coast. It’s been a week chock full of great information. It’s a good thing that the conference was only three days long though, my brain is tired.
It’s going to take a while to process all the new data I have, but here are three highlights:
This was part of Ingy’s Postmodern Module Packaging. It’s a module that enables bundling together Module::Install tasks into reusable chunks. I think it’s finally time for me to learn how to use this system.
Miyagawa himself gave this talk, with an extra serving of enthusiasm about the tools that have grown up around his interface. He finished off with a demo of Plack::Middleware::InteractiveDebugger, which can pop up a little REPL in the browser window at any level of the stacktrace of an application error.
I’m quite a fan of optimizing my workspace and this talk was fuel for the fire. It was only 20 minutes long, so most of the information is on the companion website.
That’s it for now. I’ll post more as I keep processing…
These make it much easier to open files next to the file in the current buffer. For instance, if I run the command “vi /etc/puppet/manifests/modules/foo/bar.pp” and I need to edit a file in the same directory as bar.pp, I just type ,ew and at the bottom of my vim window this appears:
1
:e /etc/puppet/manifests/modules/foo/
With the cursor at the end, waiting for me to type the filename or just hit enter so I can use NERDTree to select a file visually. The other mappings open splits or tabs, allowing me to easily select where new file shows up.
This morning, I discovered an interesting side effect to this command. I ran “vi http://mbostock.github.com/d3/ex/unemployment.json” to see what the json data for this cloropleth was. Then, to see what the us-counties.json file had in it, I just hit ,ew and the following showed up at the bottom of my vim window:
1
:e http://mbostock.github.com/d3/ex/
Awesome.
One more thing. These mappings are directly from this vimcasts episode. If you haven’t watched all the vimcasts episodes, then you’re missing out on some great content.
After a few months of managing my dotfiles with git, I felt the need to organize my vim plugins a little better. I chose to use pathogen (created by Tim Pope), which allows me to keep each plugin in its own subdirectory. It fits well with using git to manage dotfiles because git has two ways of tracking content from other repositories. The first is submodules, which keep a remote URL and commit SHA1 so that the other content can be pulled in after cloning. The second is subtrees, which merges the history of the outside repository directly into a subdirectory. Here’s a quick list of the pros and cons of each strategy:
Submodules
Pros:
Each plugin is self contained and segregated from the rest of your files.
It’s easy to see what files came from other sources.
Cons:
Making tweaks to plugins is difficult; requires managing a fork of the upstream repo.
Submodules are difficult to update.
Initial clone takes longer as each submodule needs to be initialized and fetched.
Subtrees
Pros:
Only one command to get all your files.
Making tweaks to plugins is easy, just modify and commit.
Initial clone is faster.
Cons:
It’s more difficult to extract changes and submit them back upstream.
Plugin files are in your repository too, potentially confusing your history
Difficult to determine exactly where other content came from
After trying both out on a branch in my repository, I settled on using subtrees. Using them can be daunting, but there’s a fantastic wrapper called git-subtree that greatly simplifies the whole process.
For instance, to add vim-fugitive (another by Mr. Pope), all I ran was this command:
This results in a single commit that contains the squashed history of the vim-fugitive plugin and a merge commit which merges that squashed commit into my repository. Here’s what that looks like on github: ad19e02.
After that merge, the vim-fugitive files are now part of my repository. No extra steps are necessary to get those files after an initial clone.
While I was writing this, I noticed that there have been a few more commits on the main fugitive repo, so I ran the following command to merge in those changes:
It all works quite well. As of this post I have eleven plugins managed with subtrees and it only takes a couple seconds to clone my entire repo onto a new machine or VM.
Well, that’s a bit of a misnomer. You see, I don’t get “sick.” I get miserable. Being sick for most people is being laid out in bed with a head full of snot, hacking and coughing and blowing through two boxes of kleenex.
Not me.
I get miserable. What this usually means is that my nose needs to be emptied on an hourly basis and I have less of an appetite and I usually get tired faster. Do you see anything in that list that would excuse me from work? I certainly don’t. So I usually don’t get to stay home and get taken care of like I used to when I was a kid. Not that I’m complaining. Too much.
Anyway, that’s not why I wanted to post today.
Today, I went to Home Depot. If you knew me at all, you would know this is a rarity. I am much more likely to be found at an Apple store. It wasn’t a particularly comfortable experience. My dad would be comfortable in Home Depot1. He’s done some level of remodeling in each home my parents have owned and he was the main force behind the recent addition to their current house. So he’s the kind of guy who would walk in and go directly to the right aisle, pay and be back out in five minutes instead of wandering around until someone asks if he’s in the right store. He’s awesome.
I went to Home Depot for a very specific purpose.
I needed a putty knife and drop cloth to help repair holes in the drywall above our bed left there by the removal of a shelf. It’s the first step in getting the room ready to be painted. I’m a bit nervous about this project as it’s the biggest thing we’ve attempted since we bought our condo over four years ago, but I’m confident that we’ll figure out how to do it.
That’s not why I wanted to post today either.
I wanted to post today because posting is good for my writing muscles. And I need to exercise them. And just like the first run after not getting out for a while, it’s not going to be my best work. But at least I’ve got my shoes on again.
Come to think of it, he’d probably be comfortable in an Apple store too.↩
I have quite a few dotfiles. I have so many that keeping them in sync is impossible with conventional methods. So, I turned to my old friend: version control. For a while, I kept them in subversion at work. This worked well as that was where I spent most of my time. Recently, however, I’ve wanted those same dotfiles to be available at home and other non-work areas. So, I investigated moving them over to a git repository. Not only is git easier to set one up, but keeping multiple long running branches doesn’t make you want to shoot something.
So, I investigated how other people are doing the same thing. There are no shortage of dotfiles repos on github, so I checked out a dozen or so. I also found this area on swik that linked to several pertinent blog posts about this very topic.
I decided to go with the symlink strategy to avoid the “git clean” bug 1, but most of the dotfiles repositories used either a makefile, a shell script or a rakefile to do the actual symlinking. I wanted to make something more flexible, and that didn’t require me to use degenerate languages (make or shell) or something that wasn’t installed by default (ruby). Since perl is baked into most distributions, it seemed a good fit.
The end result of this effort is dfm, the dotfiles manager. This script handles the basic ‘install’ case while adding a few more features (like skipping files and recursing into subdirectories). It also has subcommands that make it easy to fetch updates and merge/install them. And finally, it has a passthrough that allows you to run any git command on the local repo without having to cd into it.
I’ve been using this system full time for about the last two months and it’s really been handy. I have two branches. One is a personal branch that I use on all of my non-work systems and a work branch that is based on the personal branch with the added utilities and configuration for work. This means I can share my personal dotfiles and still keep work stuff private.
In all of this, I also wanted to make something that was generally useful, so that other people could get up and running quickly with something similar. To this end, I’ve kept my master branch distilled down to the bare minimum to get up and running with dfm. Using dfm is just a matter of forking my repo and adding what you use. I also put a bunch of information about dfm and my dotfiles repository on the associated wiki on github.
I have quite a few ideas on where to go with this from here, but the basic functionality is there so I wanted to officially release it into the wild. Let me know if you find it useful or have something to contribute.
Have fun.
If you run “git clean”, it will keep going up the directory tree until it finds a git repo. If your home directory itself is the working copy, and you accidentally run “git clean”, it will nuke anything that isn’t tracked. Putting the dotfiles working copy in a subdirectory and symlinking avoids this.↩
In trying to finish transitioning from my old backup drive to my new backup mini thumper, I ran across a file with this content:
12345678
-take car in to get checked
-order lion king tickets
-clean room
+do laundry
+organize honeymoon
continue working on g4g saap psd
write more for guestlist application
call mom
It’s an old todo list. The modification date on the file is 8/10/02. Yup, exactly 8 years before my daughter was born.
I used to keep files like this around quite a bit. A minus sign means that I haven’t done that particular item and a plus means I’ve done it. I don’t know what the significance of a leading space is.
At this time in my life, I was:
just over three months away from getting married (on 11/9)
just under a month away from losing my job (on 9/2, because my employer went out of business)
and three days away from my 24th birthday
I’m glad to report that I did get the Lion King tickets (we went later that year), I did clean my room (at least as clean as it could get), and I’m sure I called my mom. I’m also glad I had organized the honeymoon by that time.
I’ve been using git for a while now, and I’m just getting to the point where I can think in it.
It’s the same as learning a new spoken language. I took three years of Spanish in high school, so I knew most of the rules and could translate back and forth to English, but I never really learned to think in Spanish (as opposed to thinking in English and then quickly translating). And, until you start thinking in Spanish, you are not on the path to full fluency and you’ll be constantly hampered whenever you try to talk with a native speaker.
I came to git from the world of subversion (a world that I’m quickly wishing I could fully leave). So my first forays into git-dom were guided by the SVN Crash Course. This allowed me to get access to git repositories quickly, but it kept me thinking in subversion. I wanted to use git more idiomatically. So I read and I read, I cloned and fetched and pushed and merged and after a while, I began to feel like I was really understanding git.
Last week, when I was chatting with a couple of my programmer geek friends about git and version control, I got to thinking about what has helped me the most in my learning experience. Here’s what I came up with.
Really understand how git stores its data.
Git stores it’s data as a directed acyclic graph, which is just about as simple as you can get. Commits point to their parent commit, which in turn point to their parent, and so on. A new node is created for every commit and a merge just points at all of its parents. Combine this knowledge with the fact that branches are just named pointers to nodes in this graph and you start to have more confidence when it comes time to change things around.
Learn the “get out of jail” command: git reset –hard
That’s all you need to undo almost anything you might have done. This command takes the current branch and points it at the commit you referenced.
For instance, if you want to revert a branch back to where it was at the last fetch:
1
$ git reset --hard origin/branchname
Or, if you decide that the last three commits should be forgotten:
1
$ git reset --hard HEAD~3
Or, if you don’t like the result of that interactive rebase:
1234
$ git branch before
$ git rebase -i HEAD~3
# decide the rebase was bad
git reset --hard before # all better
Don’t be afraid to experiment.
One of the best things about a distributed version control system is that you are free to mess around with your repository all you want and no one will know about it. Go ahead. Rebase your commits to be cleaner, rearrange branches to make them easier to work with, or rewrite every commit because you forgot to set your email address. It doesn’t matter at all until you share those changes with other people.
Also, almost nothing in git will delete data. In truth, it’s rather hard to permanently remove a commit. Because of this, even if something happens that you don’t like, you can use ‘git reset’ to make it all go away. For instance, if you have a repository with a dozen commits and you want to change the committer email, when the commits are rewritten, the old commits are still there in the database, waiting to be resurrected if you change your mind.
This book was instrumental in helping me move from beginner to intermediate. I recommend reading it cover to cover, even if you don’t ever plan on writing a hook or running ‘git filter-branch’. Just seeing how it all fits together helps inform day to day decisions when using git.