Chakrit Wichian
Posted on October 29, 2019
Have you ever had these problems like I did?
- You work with multiple groups or companies, or you want to separate your work commits from your personal commits.
- You want to GPG sign all your commits.
- You do not put your personal GPG keys on your work machine, and you do not put your work GPG keys on your personal machine.
- You use a different GPG identity (and perhaps, email) for different repository.
- You synchronize your dotfiles regularly. It contains your GPG configuration as well as your global .gitconfig and use the same dotfiles repository on both your work machine and your personal machine.
If you did you'll find out that you now have a conflict in your .config/git/config
file, namely in the [user]
section.
I have mine, looking something like this:
[user]
name = Chakrit Wichian
email = service@chakrit.example.net
signingkey = E888C1BC6A4DB2F4
So this tells git, for all my personal projects, to use my personal email and personal GPG key to sign it.
This all works nice and well but then, how do we setup our work accounts?
Previously I have used GNU Stow with multiple git
folder in my dotfiles repository and only stow
the one I needed into place.
# on personal machine
cd dotfiles && stow git-personal
# on work machine
cd dotfiles && stow git-work
Obviously, though, this approach has an annoying flaw: I cannot synchronize changes easily across all git installations I use.
That got me thinking. What is the BEST approach to this problem? Usually other configuration system have a way to include
files so that you can split them into bits and keep most of the shared configuration items the same in the main file and include the parts that are different from other files.
I could modify my workflow so that I have a main configuration that is shared for all installations and have another supplemental
configs just for the specific machine I happen to be on.
# shared configuration
cd dotfiles && stow git-base && cd ~
tree
.
└── .config
├── git
│ ├── config # ← contains an include directive.
│ └── ignore
└── hub
2 directories, 3 files
# selecting the right "extra" to install
cd dotfiles && stow git-company-x && cd ~
tree
.
└── .config
├── git
│ ├── config
│ ├── extras # ← contains extras, for company X
│ └── ignore
└── hub
2 directories, 4 files
So after realizing this, I began to search for git configuration documentation, seeing if this functionality is available.
To my surprise, the git manual on includes has an EVEN BETTER solution lying in wait for me with the includeIf
directive.
Conditional Includes
Git supports a neat way of specifying an includeIf
condition by selecting based on the location of the .git dir. And better yet, it also supports **
directory globbing.
This means that you can structure your workspace such that all of Company X's work are under a dir named company-x
and then using a condition matching **/company-x/**/.git
to match all git checkouts under that dir.
First, if you havn't already, you need to reorganize your repos based on where you work (or how you want to apply gitconfigs):
# example directory tree under your `git/` or something.
tree
.
├── company-x
│ ├── hello-world
│ └── awesome-project
└── personal
├── hello-world
└── awesome-learning
Second, create multiple git configuration files for each different situation.
# config.personal
[user]
name = Chakrit Wichian
email = service@chakrit.example.net
signingkey = E888C1BC6A4DB2F4
# config.company-x
[user]
name = Chakrit Wichian
email = chakrit@company-x.example.com
signingkey = 3CDC219617574C11
Third, in your main git configuration file, adds as many includeIf
directive as needed:
# default case
[include]
path = config.personal
# when working with company-x
[includeIf "gitdir:**/company-x/**/.git"]
path = config.company-x
Lastly, save all files and test them out!
cd chakrit/secret-project-x
git config user.email
service@chakrit.example.net # ← outputs personal email!
cd ../../company-x/awesome-product-y
git config user.email
chakrit@company-x.example.com # ← outputs work email!
Some other uses that I think is cool follows:
Automatically switching hub
context.
If the companies you work for uses GHE. You could point the hub
CLI to different domains base on where the repo is placed on your system.
# config.company-x
[hub]
host = git.company-x.example.com
# config.company-y
[hub]
host = git.company-y.example.com
Different signing settings base on branch.
Aside from the gitdir:
matching condition, you can also use onbranch:
to setup branch-specific configs!
If you have specific branch system setup, for example master
for production commits, you could set it up so that GPG signing is only done there and only require commits on that branch to have proper verification.
# config
[commit]
gpgsign = false
[includeIf "onbranch:master"]
path = config.master
# config.master
[commit]
gpgsign = true
Thanks for reading! Ping me on Twitter and say hi :)
Posted on October 29, 2019
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.