giant robots smashing into other giant robots

Written by thoughtbot

qrush

Font Battle 2011

A recent straw poll of text editor fonts at thoughtbot found these results. Not all thoughtbot precincts have reported in. Perhaps you’d like to explore some new font options for those walls of text you stare at for 8+ hours daily.

Some links to these fonts:

dancroak

Keeping a GitHub fork updated

I forked a GitHub repo thoughtbot/dotfiles to croaky/dotfiles and want to keep the fork updated.

Track

After I forked the repo to your Github account, I did this one time:

git clone git@github.com:croaky/dotfiles.git
cd dotfiles
git remote add upstream git@github.com:thoughtbot/dotfiles.git

Update

Each time I want to update, from my local master branch:

git fetch upstream
git rebase upstream/master

The goal of the rebase is to have a cleaner history if I have local changes or commits on the repo. It’s the difference between the the left and the right in the image below.

image

Commit rights upstream?

If I also have commit rights to the upstream repo, I can create a local upstream branch and do work that will go upstream there.

git checkout -b upstream upstream/master

Written by .

hgimenez

Streamline your git workflow with aliases

My git workflow is heavily influenced by articles such as Rein’s or the topic branches workflow on the excellent ProGit book. The idea is simple:

1. Start a story with a new branch.

From the master branch, run

git checkout -b feature_x

2. Hack and commit often in that branch

vi file.rb
git add -u
git add .
git status
git commit -m "Make changes"

3. Pull in upstream changes as often as possible

There are many ways to do this. I like this method because it doesn’t require me to checkout or merge the master branch. Instead, just fetch the references from the remote and rebase it against your feature branch. Note that the reference we’re rebasing against is origin/master, so that we only bring in changes from that branch.

git fetch
git rebase origin/master

4. Clean up the history by squashing commits

Once again we fetch changes from the remote, and then we do an interactive rebase against origin/master. This ensures that we don’t modify any changes that already found a home upstream.

git fetch
git rebase -i origin/master

5. Merge into master, run all tests and push upstream

We fetch and rebase again, just in case there have been changes since the last step, and then we merge it all into master and push it out if all tests pass.

git fetch
git rebase origin/master
git checkout master
git merge feature_x
rake
git push

I prefer not to delete the local or remote feature branches right away just in case. Instead, I’ll go on some cleanup missions every once in a while.

Working this way for a while, you start to identify repetitive keystrokes. You can cut down on these keystrokes with shell aliases or functions, or with git aliases. I like using git aliases because the commands themselves provide context: git related commands start with git.

Here are the aliases I use everyday that support this git workflow. Place these in your ~/.gitconfig.

[alias]
  c = commit -m
  a = add
  aa= !git add -u && git add . && git status
  cob = checkout -b
  up = !git fetch origin && git rebase origin/master
  ir = !git rebase -i origin/master
  done = !git fetch && git rebase origin/master && git checkout master && git merge @{-1} && rake && git push

Having those in place, let’s see what the very same workflow looks like:

1. Start a story with a new branch

git cob feature_x

2. Hack and commit often in that branch

vi file.rb
git aa
git c "Make changes"

3. Pull in upstream changes as often as possible

git up

4. Clean up the history by squashing commits

git ir

5. Merge into master, run all tests and push upstream

git done

Now we’re talking. From the convention of how we work with git, we’ve augmented our tools to make it a whole lot easier, and reduce the risk of modifying upstream history by always ensuring we never change it.

But aliases can take you even further. For one, I use a shell alias for git: g=git, so now the commands above simply look like g aa, g c "Make changes", etc. There are also a few useful tidbits you can use. One that comes in handy often is when you want to commit changes as part of the prior commit, and want to keep the original commit message. Similar to creating a new commit and then squashing them.

ca = commit --amend -C HEAD

What about when you’re ready to delete feature branches. You want to remove the local and remote references. Try g rmb feature_x:

rmb = !sh -c 'git branch -D $1 && git push origin :$1' -

Or if you want to see who has contributed to a project, add this alias and just ask with g who

who = shortlog -n -s --no-merges

Finally, it’s a good idea to clean up your git repo every once in a while. This alias will remove remote branch references that no longer exist, cleanup unnecessary git files, remove untracked files from the working tree and clear out your stash - all with a simple g cleanup (hat tip to @qrush)

cleanup = !git remote prune origin && git gc && git clean -dfx && git stash clear

There are many more possibilities. How about you: What are your most useful git aliases?

jdclayton

A Tmux Crash Course

I’ve been using Tmux for about six months now and it has become just as essential to my workflow as vim. Pane and window management, copy-mode for navigating output, and session management make it a no-brainer for those who live in the terminal (and especially vim). I’ve compiled a list of tmux commands I use daily to help me work more efficiently.

Tmux Panes

If a tmux command I mention is bound to a keyboard shortcut by default, I’ll note that in parenthesis.

Session Management

Sessions are useful for completely separating work environments. I have a ‘Work’ session and a ‘Play’ session; in ‘Work’, I keep everything open that I need during my day-to-day development, while in ‘Play’, I keep open current open-source gems or other work I hack on at home.

tmux new -s session_name
creates a new tmux session named session_name
tmux attach -t session_name
attaches to an existing tmux session named session_name
tmux switch -t session_name
switches to an existing session named session_name
tmux list-sessions
lists existing tmux sessions
tmux detach (prefix + d)
detach the currently attached session

Windows

Tmux has a tabbed interface, but it calls its tabs “Windows”. To stay organized, I rename all the windows I use; if I’m hacking on a gem, I’ll name the window that gem’s name. The same thing goes for client applications. That way, I can recognize windows by context and not what application it’s running.

tmux new-window (prefix + c)
create a new window
tmux select-window -t :0-9 (prefix + 0-9)
move to the window based on index
tmux rename-window (prefix + ,)
rename the current window

Panes

Panes take my development time from bland to awesome. They’re the reason I was able to uninstall MacVim and develop solely in iTerm2. I don’t have to switch applications to switch contexts (editing, reading logs, IRB, etc.) - everything I do, I do in a terminal now. People argue that OS X’s Cmd+Tab is just as fast, but I don’t think so.

tmux split-window (prefix + ")
splits the window into two vertical panes
tmux split-window -h (prefix + %)
splits the window into two horizontal panes
tmux swap-pane -[UDLR] (prefix + { or })
swaps pane with another in the specified direction
tmux select-pane -[UDLR]
selects the next pane in the specified direction
tmux select-pane -t :.+
selects the next pane in numerical order

Helpful Tmux commands

tmux list-keys
lists out every bound key and the tmux command it runs
tmux list-commands
lists out every tmux command and its arguments
tmux info
lists out every session, window, pane, its pid, etc.
tmux source-file ~/.tmux.conf
reloads the current tmux configuration (based on a default tmux config)

Must-haves

These are some of my must-haves in my tmux config:

# remap prefix to Control + a
set -g prefix C-a
unbind C-b
bind C-a send-prefix

# force a reload of the config file
unbind r
bind r source-file ~/.tmux.conf

# quick pane cycling
unbind ^A
bind ^A select-pane -t :.+

Workflow

During the day, I’ll work on one or two Rails apps, work on my dotfiles, run irssi, and maybe run vim in another window to take notes for myself. As I mentioned, I run all of this inside one tmux session (named work) and switch between the different windows throughout the day.

When I’m working on any Ruby work specifically, I’ll have a 75%/25% vertical split for vim and a terminal so I can run tests, interact with git, and code. If I run tests or ‘git diff’ and want to see more output than the 25% allots me, I’ll use tmux to swap the panes and then move into copy mode to see whatever I need to see.

Finally, I run iTerm2 in full-screen mode. Switching between OS X apps for an editor and a terminal is for chumps!

dancroak

Love, hate, & tmux

Many at thoughtbot run their editor+shell combos inside of tmux. Some remote pair program with ssh, vim, and tmux.

Getting started with tmux, these are the questions I’ve had.

How do I get started?

Install tmux, read the documentation, and fire it up.

brew install tmux
man tmux
tmux -u

Can I make the environment look good?

Yes. We have these lines in tmux.conf in thoughtbot/dotfiles:

# improve colors
set -g default-terminal "screen-256color"

# soften status bar color from harsh green to light gray
set -g status-bg '#666666'
set -g status-fg '#aaaaaa'

# remove administrative debris (session name, hostname, time) in status bar
set -g status-left ''
set -g status-right ''

What’s a prefix?

The “prefix” namespaces tmux commands. By default it is Ctrl+b. In our tmux.conf in thoughtbot/dotfiles, we bound it to Ctrl+a:

# act like GNU screen
unbind C-b
set -g prefix C-a

How can I scroll up to see my backtraces?

This was non-obvious to me.

Enter “copy mode”:

prefix+[

Use vim bindings to page up and down:

Ctrl+b
Ctrl+f

How can I copy text?

Add this to your tmux.conf:

# enable copy-paste http://goo.gl/DN82E
# enable RubyMotion http://goo.gl/WDlCy
set -g default-command "reattach-to-user-namespace -l zsh"

How can I make tmux act more like vim?

Add this to your tmux.conf to use vim’s home-row keys for movement between windows and panes:

# act like vim
setw -g mode-keys vi
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
bind-key -r C-h select-window -t :-
bind-key -r C-l select-window -t :+

How do I name sessions?

One day I might work on Airbrake. Another day, a client project. I’d like to name my tmux sessions so I can leave one, drop into another, and go back to the original with all my state maintained (files still open in my editor, console/logs I want open, etc.).

Create a new session:

tmux new -s airbrake

Attach to a session:

tmux attach -t airbrake

How do I split and move between windows?

Create a window:

prefix c

Move to window 1:

prefix 1

Move to window 2:

prefix 2

Kill a window:

prefix x

I believe in setting my mouse free but it takes time for muscle memory to make this fast.

How do I reload ~/.tmux.conf?

After editing ~/.tmux.conf, execute this from a shell:

tmux source-file ~/.tmux.conf

Give it a shot

I’ve had a love-hate relationship with tmux in my first week using it, but the brief moments of flow I’ve experienced so far are enough to keep trying it.

Give tmux a shot and if you have any other tips, I’d love to hear them.

Written by .