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
I have mine, looking something like this:
[user] name = Chakrit Wichian email = firstname.lastname@example.org 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.
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 = email@example.com signingkey = E888C1BC6A4DB2F4 # config.company-x [user] name = Chakrit Wichian email = firstname.lastname@example.org 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 email@example.com # ← outputs personal email! cd ../../company-x/awesome-product-y git config user.email firstname.lastname@example.org # ← outputs work email!
Some other uses that I think is cool follows:
# config.company-x [hub] host = git.company-x.example.com # config.company-y [hub] host = git.company-y.example.com
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 :)