Git: maintaining work-life accounts

📅 2021-07-14🔃 2022-05-04⏳ 3 min read

Do you have work and personal emails? Ever wondered how to make Git automatically use the correct one? This simple trick will help enlarge you productivity x10!

🔗The Problem

Sometimes I contribute to open-source projects, so I need Git to use my personal email: bemyak@pm.me. However, I work on the same computer, and for work projects my company wants me to use the work email, which is completely reasonable.

I have all work-related projects checked out in ~/projects. Historically I had put my personal projects in the same folder, but then I realized that it completely ruins the search (grep) ability. Many work projects are interconnected, so it’s a common pattern to grep some variable in the whole ~/projects directory, but personal projects make this really noisy.

The solution I came up with was not-thought-through really: I had just moved personal stuff to ~/projects/.personal. This helped a lot: I use ripgrep for grep, and it ignores hidden directories by default, so I was happy. For a while.

🔗Git conditional includes (didn’t work)

After some time I realized that different emails in commit messages is a problem. Looking it up lead me to Git includeIf config option. However, it didn’t work we for nested paths.

The idea was to create two files that specify user.email and user.name:

~/projects/.personal/.gitconfig
[user]
    name = Sergei Gureev
    email = bemyak@pm.me

and a similar file for the ~/projects dir.

Then add this sections to ~/.gitconfig

~/.gitconfig
[includeIf "gitdir:~/projects/"]
        path = ~/projects/.gitconfig
[inclideIf "gitdir:~/projects/.personal"]
        path = ~/projects/.personal/.gitconfig

…and as mentioned, this didn’t work.

🔗Env variables

🔗direnv

The first key for solving the puzzle is to start using direnv. If you’re not using it, you should at least try it!

The idea is dead-simple: it contains a set of bash-hooks to load environment variables specified in .envrc files. The file is loaded when you navigate to a directory containing it or to any subdirectory of that directory. The variables are unloaded when you leave the directory.

It is commonly used it for maintaining project-specific vars like tokens. The setup is also simple, e.g. I’m using this for my fish shell:

~/.config/fish/conf.d/direnv.fish
if type -q direnv
        direnv hook fish | source
end

Note: There is a direnv plugin for oh-my-fish, but it doesn’t work well. Uninstall it and use the simple script from above.

Also, it’s usually a good idea to add .envrc file to the global gitignore, so that your secret tokens won’t be committed accidentally:

~/.gitconfig
[core]
    excludesfile = ~/.gitignore_global
~/.gitignore_global
.envrc

🔗GIT_AUTHOR

The rest is simple:

  • Configure your git to use work-related email by default:

    ~/.gitconfig
    [user]
      name = Sergei Gureev
      email = work_email@job.com
    
  • Add .envrc file to the directory containing your personal projects

    ~/projects/.personal/.envrc
    source_up
    export GIT_AUTHOR_EMAIL="bemyak@pm.me"
    export GIT_AUTHOR_NAME="Sergei Gureev"
    export GIT_COMMITTER_EMAIL="bemyak@pm.me"
    export GIT_COMMITTER_NAME="Sergei Gureev"
    

    source_up allows loading all parent envs. Make sure to include this line in every envrc file!

NB: specifying both AUTHOR and COMMITER is required! Otherwise, GPG-signing won’t work properly. You can verify both values with git log --format=full --show-signature

Done!