Handy git customizations
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?