So, you are a proud OpenSource developer and work for a company using GitHub.com for GIT repository hosting?
While SSH auth to GitHub.com is based on public keys and it automatically chooses the right account you have to take care when you quickly clone a repository, change something and whoops your company has your private email address or hacker pseudo within their repository.
The scenario we are speaking about looks like following:
$HOME/
Projects/
acme/ ← use acme.config here with email="user@acme.com", name="John Barleycorn"
ui
backend
infra
foss/ ← use foss.config here with email="user@foss.org", name="Acid Burn"
bitcoin-miner
dotfiles
fancy-themes
Here we are using GIT’s global hooks and include.path
to setup repository-specific configs.
This guide is aimed at Linux users but should be able to be used on Unix (OSX) or Windows as well.
We're using a temporary config path here following FreeDesktop specifications. This is just used for the copy-and-paste in this tutorial and should not be put somewhere in a profile.
CONFIG_PATH="$HOME/.config/git"
mkdir -p $CONFIG_PATH/config
echo -e "[user]\nemail=user@fsf.org" > $CONFIG_PATH/foss.config
echo -e "[user]\nemail=user@acme.com" > $CONFIG_PATH/acme.config
mkdir -p $CONFIG_PATH/hooks
git config --global --replace-all core.hooksPath $CONFIG_PATH/hooks
Create $CONFIG_PATH/hooks/pre-commit
and don’t forget to chmod a+x $CONFIG_PATH/hooks/pre-commit
!
The lines with acme
and foss
will do the matching. Customize for the companies you're working for! Also keep in mind that include.path
might get overwritten and if no match takes please git will use the global config!
#!/bin/bash
# Config directory
CONFIG_PATH="$( cd "$(dirname ${BASH_SOURCE[-1]})/.." && pwd)"
# default config
GIT_INCLUDE_CONFIG=""
# Git Hooks documentation
# https://git-scm.com/docs/githooks
# If we have a local commit hook, execute it
localHook="${PWD}/.git/hooks/$(basename "${0}")"
if [[ -e "${localHook}" ]]; then
echo "Executing local hook"
$localHook "$@" || exit $?
fi
echo "Executing global hook"
case "${PWD}" in
*acme*) GIT_INCLUDE_CONFIG="acme.config";;
*foss*) GIT_INCLUDE_CONFIG="foss.config";;
esac
currentConfig=$(git config --local include.path || true)
if [[ -n "${currentConfig}" ]] && [[ ! -e "${currentConfig}" ]]; then
echo "${currentConfig} does not exist! Fix or remove by git config --local --replace-all include.path \"\"" >&2
exit 1
fi
# If we have a config to be applied
if [[ -n "${CONFIG_PATH}/${GIT_INCLUDE_CONFIG}" ]]; then
if [[ ! -e "${CONFIG_PATH}/${GIT_INCLUDE_CONFIG}" ]]; then
echo "${CONFIG_PATH}/${currentConfig} does not exist! Please fix ${BASH_SOURCE[-1]}!" >&2
exit 1
fi
if [[ "${currentConfig}" != "${CONFIG_PATH}/${GIT_INCLUDE_CONFIG}" ]]; then
echo "Applying config: ${CONFIG_PATH}/${GIT_INCLUDE_CONFIG}"
git config --local --replace-all include.path "${CONFIG_PATH}/${GIT_INCLUDE_CONFIG}"
fi
fi
TMP=$(mktemp -d) && cd $TMP
mkdir acme && cd acme
git init
echo "$RANDOM" > README.md
git add README.md
git commit -m "Initial Commit"
Now within the acme
-directory this should read:
git add README.md
git commit -m "Initial Commit"
Executing global hook
Applying config: /home/ctang/.config/git/acme.config
[master (root-commit) 3931374] Initial Commit
1 file changed, 1 insertion(+)
create mode 100644 README.md
The user.email
should now read from the acme.config
$ git config --get user.email
user@acme.com
The user.email can be locally overwritten git config --replace-all user.email ""
and reset by git config --unset user.email
(in repo.fodler)
With ZSH you could also take advantage of the GIT_CONFIG
environment variable when on directory change. If you are using bash you should change to a better shell ;) It’s much less of a hassle and a much cleaner solution for the problem.
chpwd_git() {
local configPath="$HOME/.config/git"
case "${PWD}" in
*acme*) export GIT_CONFIG="${configPath}/acme.config";;
*foss*) export GIT_CONFIG="${configPath}/foss.config";;
esac
}
chpwd_functions=("${chpwd_functions[@]}" "chpwd_git")
If a global hook exists local hooks will be ignored. Therefore we check for a local hook in the script and execute it as well.
Previous to GIT version 2 GIT was using Templates which still can be used to initialize repositories. But they are just copied when initailizing repositories. You can setup them as well. Note that the hooks path will be $CONFIG_PATH/templates/hooks
!
git config --global --replace-all init.templatedir $CONFIG_PATH/templates
Use commit hooks. They probably make your life as developer easier ;)
Also note: https://gist.github.com/jexchan/2351996