Git is complicated, and it seems like everyone has a set of customizations they use to try and make it easier to use. Sometimes it aliases for clarifying what exactly git checkout will do. Sometimes it’s a pre-built ~/.gitconfig file that has lots of tweaks and display customizations and options configured.

Over the years I’ve built up two that I use extremely frequently: git ui and git identity.

Git UI

There are a number of Git clients out there, and in my opinion Fork is the best one. I’ve been using it for several years and LOVE it. At one point I even advocated that it shouldn’t be free because good apps deserve to earn money.

Regardless of which Git app you use, I frequently find myself trolling around the command line doing stuff (cloning, pulling, etc) and then will come up against a task I want to do that, frankly, would be easier in an app. Interactive file staging is one such example. Enter git ui.

I created a file called git-ui.zsh and tossed it in my $PATH (~/Applications is where I happen to have it). This file is pretty simple:

GIT_FOLDER="$(git rev-parse --show-toplevel 2>/dev/null)"
if [ "$1" == "-r" ]; then
    find "$GIT_FOLDER" -name .git -execdir open -a "$EDITOR_GIT" . \;
else
    if [ -e "$GIT_FOLDER/.git" ]; then
        echo "Opening $GIT_FOLDER in $(basename $EDITOR_GIT)"
        open -a "$EDITOR_GIT" "$GIT_FOLDER"
    else
        echo "Could not find git repository in $(pwd) or any parent"
    fi
fi

As part of the setup, this script relies on an environment variable I defined in my ~/.zshrc called EDITOR_GIT:

export EDITOR_GIT="/Applications/Fork.app"

(I have several other EDITOR_... values defined, such as EDITOR_MD for markdown files, EDITOR_PLIST for property lists, etc. Then I’ve built up other commands for dealing with markdown and plist files specifically. This one uses EDITOR_GIT for working with git repositories.)

git-ui.zsh first uses git rev-parse to locate the top-level directory of whatever git repository you happen to be in. For example, if your git repo is cloned to ~/Code/MyRepo, then it will return /Users/yourname/Code/MyRepo, no matter which sub-directory of the repo you might be cd‘d into. This value gets stashed into the GIT_FOLDER variable.

Then, if you passed a -r flag to this command (git ui -r), it recursively finds all .git folders inside your git repository and asks them to open using your $EDITOR_GIT app. Otherwise, it looks for .git folder inside your repository root and, if it finds it, asks your $EDITOR_GIT to open up that folder. (open is a built-in command, and open -a means “Open the passed-in stuff using the specified application”)

By itself this script is cool, but when I also add an alias to my ~/.gitconfig, it gets better:

[alias]
	ui = !sh git-ui.zsh

(i.e. the ui subcommand is equivalent to invoking the git-ui.zsh script)

The end result is that I can be anywhere inside my git repo in Terminal and, upon realizing I need to do anything non-trivial, can type git ui to immediately pop up the current repository in my Git app-of-choice. I can also do git ui -r to open up all repositories in the current folder; I use this when I’ve got a folder of several related cloned repositories that I work with together.

Git Identity

The other main customization I’ve created is the identity command. Many developers have multiple Github accounts: they have a personal one for their own projects and a work one that is associated with their work for their current employer (for example). The problem arises when want to work with multiple repositories from the same host (github.com) but under different accounts. You want to work with Repository A under your personal account, and Repository B with your work account.

There are weird hacks you can do to your ~/.ssh/config file and custom hosts to make this work, but it’s a bit arcane, kind of weird to set up, and difficult to remember how it works. Fortunately, there’s a better way.

Git has a way to customize the command it uses to connect via SSH to the remote server, called core.sshCommand. If you change this, you can alter the way that git pushes and pulls from remotes. And since this is a configuration value, it can be specific on a per-repository basis.

What you want is to end up with an sshCommand that looks like this in your repository’s .git/config file:

[core]
	sshCommand = ssh -i ~/.ssh/id_myworksshkey -F /dev/null -o 'IdentitiesOnly yes'

If you have this, then pushes and pulls to the repository will only use your id_myworksshkey identity; it won’t try to fall back to another identity or the keychain. And since this setup is a bit awkward to remember, we can make an alias to simplify it in our ~/.gitconfig file:

[alias]
	identity = "!f() { git config core.sshCommand \"ssh -i $1  -F /dev/null -o 'IdentitiesOnly yes'\"; }; f"

Now I can create a repo and run git identity ~/.ssh/id_myworksshkey to configure it with the right identity for pushing and pulling!

(Side note: not all Git apps will correctly use the specified sshCommand for a repo, but Fork does!)


What handy git customizations have you come up with?