In my ~/.gitconfig
, I list my personal email address under [user]
, since that\'s what I want to use for Github repos.
But, I\'ve recently s
Since git 2.13, it is possible to solve this using newly introduced Conditional includes.
An example:
Global config ~/.gitconfig
[user]
name = John Doe
email = john@doe.tld
[includeIf "gitdir:~/work/"]
path = ~/work/.gitconfig
Work specific config ~/work/.gitconfig
[user]
email = john.doe@company.tld
Or you can add following information in your local .git/config
file
[user]
name = Your Name
email = your.email@gmail.com
If you do not want to have a default email address (email address links to a github user), you can configure that you want to be asked. How you can do that depends on the version of git you use, see below.
The (intended) drawback is that you have to configure your email address (and your name) once for every repository. So, you cannot forget to do it.
[user]
name = Your name
email = "(none)"
in your global configuration ~/.gitconfig
as stated in a comment by Dan Aloni in Orr Sella's blog post. When trying to do the first commit in a repository, git fails with the nice message:
*** Please tell me who you are.
Run
git config --global user.email "you@example.com"
git config --global user.name "Your Name"
to set your account's default identity.
Omit --global to set the identity only in this repository.
fatal: unable to auto-detect email address (got '(none)')
The name is taken from the global config when the email address is set locally (the message is not perfectly accurate).
The behaviour in versions < 2.7.0 was not intended and fixed with 2.7.0. You can still use a pre-commit hook as described in Orr Sella's blog post. This solution works also for other versions, but the other solutions not for this version.
Dan Aloni added an option to achieve that behaviour (see release notes). Use it with:
[user]
useConfigOnly = true
To make it work you may not give a name or email address in the global config. Then, at the first commit, you get an error message
fatal: user.useConfigOnly set but no name given
So the message is not very instructive, but since you set the option explicitly, you should know what to do. In contrast to the solution of versions < 2.7.0, you always have to set both name and email manually.
One command github accounts switch
This solution takes the form of a single git alias. Once executed, the current project user will be attached to another account
Generate ssh keys
ssh-keygen -t rsa -C "rinquin.arnaud@gmail.com" -f '/Users/arnaudrinquin/.ssh/id_rsa'
[...]
ssh-keygen -t rsa -C "arnaud.rinquin@wopata.com" -f '/Users/arnaudrinquin/.ssh/id_rsa_pro'
Link them to your GitHub / Bitbucket accounts
pbcopy < ~/.ssh/id_rsa.pub
add SSH key
github pagepbcopy < ~/.ssh/id_rsa_pro.pub
Step 1. Automatic ssh key switching.
We can configure ssh
to send a use a specific encryption key depending on the host
. The nice thing is that you can have several aliases for the same hostname
.
See this example ~/.ssh/config
file:
# Default GitHub
Host github.com
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa
# Professional github alias
Host github_pro
HostName github.com
User git
IdentityFile ~/.ssh/id_rsa_pro
git remote configuration
You can now use these aliases in the git remotes by changing git@github.com
by git@github_pro
.
You can either change your existing projects remotes (using something like git remote set-url origin git@github_pro:foo/bar.git
) or adapt them directly when cloning them.
git clone git@github.com:ArnaudRinquin/atom-zentabs.git
using alias, it become:
git clone git@github_pro:ArnaudRinquin/atom-zentabs.git
Step 2. Changing git user.email
Git config settings can be global or per project. In our case, we want a per project settings. It is very easy to change it:
git config user.email 'arnaud.rinquin@wopata.com'
While this is easy, it takes way to long for the developers we are. We can write a very simple git alias for that.
We are going to add it to the ~/.gitconfig
file.
[user]
name = Arnaud Rinquin
email = rinquin.arnaud@gmail.com
...
[alias]
setpromail = "config user.email 'arnaud.rinquin@wopata.com'"
Then, all we have to do is git setpromail
to have our email changed for this project only.
Step 3. One command switch please?!
Wouldn’t it be nice to switch from default account to a specified one with a single parameter-less command? This is definitely possible. This command will have two steps:
We already have a one command solution for the second step, but the first one is way harder. One command remote host change
Here comes the solution in the form of another git alias command to add to your ~/.gitconfig
:
[alias]
changeremotehost = !sh -c \"git remote -v | grep '$1.*fetch' | sed s/..fetch.// | sed s/$1/$2/ | xargs git remote set-url\"
This allows changing all remotes from one host to another (the alias). See the example:
$ > git remote -v
origin git@github.com:ArnaudRinquin/arnaudrinquin.github.io.git (fetch)
origin git@github.com:ArnaudRinquin/arnaudrinquin.github.io.git (push)
$ > git changeremotehost github.com github_pro
$ > git remote -v
origin git@github_pro:ArnaudRinquin/arnaudrinquin.github.io.git (fetch)
origin git@github_pro:ArnaudRinquin/arnaudrinquin.github.io.git (push)
Combine them all
We now just have to combine the two commands into one, this is quite easy. See how I also integrate bitbucket host switching.
[alias]
changeremotehost = !sh -c \"git remote -v | grep '$1.*fetch' | sed s/..fetch.// | sed s/$1/$2/ | xargs git remote set-url\"
setpromail = "config user.email 'arnaud.rinquin@wopata.com'"
gopro = !sh -c \"git changeremotehost github.com github_pro && git changeremotehost bitbucket.com bitbucket_pro && git setpromail\"
Source Link -Github
Source Link -Tutorial
After getting some inspiration from Orr Sella's blog post I wrote a pre-commit hook (resides in ~/.git/templates/hooks
) which would set specific usernames and e-mail addresses based on the information inside a local repositorie's ./.git/config
:
You have to place the path to the template directory into your ~/.gitconfig
:
[init]
templatedir = ~/.git/templates
Then each git init
or git clone
will pick up that hook and will apply the user data during the next git commit
. If you want to apply the hook to already exisiting repos then just run a git init
inside the repo in order to reinitialize it.
Here is the hook I came up with (it still needs some polishing - suggestions are welcome). Save it either as
~/.git/templates/hooks/pre_commit
or
~/.git/templates/hooks/post-checkout
and make sure it is executable: chmod +x ./post-checkout || chmod +x ./pre_commit
#!/usr/bin/env bash
# -------- USER CONFIG
# Patterns to match a repo's "remote.origin.url" - beginning portion of the hostname
git_remotes[0]="Github"
git_remotes[1]="Gitlab"
# Adjust names and e-mail addresses
local_id_0[0]="my_name_0"
local_id_0[1]="my_email_0"
local_id_1[0]="my_name_1"
local_id_1[1]="my_email_1"
local_fallback_id[0]="${local_id_0[0]}"
local_fallback_id[1]="${local_id_0[1]}"
# -------- FUNCTIONS
setIdentity()
{
local current_id local_id
current_id[0]="$(git config --get --local user.name)"
current_id[1]="$(git config --get --local user.email)"
local_id=("$@")
if [[ "${current_id[0]}" == "${local_id[0]}" &&
"${current_id[1]}" == "${local_id[1]}" ]]; then
printf " Local identity is:\n"
printf "» User: %s\n» Mail: %s\n\n" "${current_id[@]}"
else
printf "» User: %s\n» Mail: %s\n\n" "${local_id[@]}"
git config --local user.name "${local_id[0]}"
git config --local user.email "${local_id[1]}"
fi
return 0
}
# -------- IMPLEMENTATION
current_remote_url="$(git config --get --local remote.origin.url)"
if [[ "$current_remote_url" ]]; then
for service in "${git_remotes[@]}"; do
# Disable case sensitivity for regex matching
shopt -s nocasematch
if [[ "$current_remote_url" =~ $service ]]; then
case "$service" in
"${git_remotes[0]}" )
printf "\n»» An Intermission\n» %s repository found." "${git_remotes[0]}"
setIdentity "${local_id_0[@]}"
exit 0
;;
"${git_remotes[1]}" )
printf "\n»» An Intermission\n» %s repository found." "${git_remotes[1]}"
setIdentity "${local_id_1[@]}"
exit 0
;;
* )
printf "\n» pre-commit hook: unknown error\n» Quitting.\n"
exit 1
;;
esac
fi
done
else
printf "\n»» An Intermission\n» No remote repository set. Using local fallback identity:\n"
printf "» User: %s\n» Mail: %s\n\n" "${local_fallback_id[@]}"
# Get the user's attention for a second
sleep 1
git config --local user.name "${local_fallback_id[0]}"
git config --local user.email "${local_fallback_id[1]}"
fi
exit 0
EDIT:
So I rewrote the hook as a hook and command in Python. Additionally it's possible to call the script as a Git command (git passport
), too. Also it's possible to define an arbitrary number of IDs inside a configfile (~/.gitpassport
) which are selectable on a prompt. You can find the project at github.com: git-passport - A Git command and hook written in Python to manage multiple Git accounts / user identities.
You can also use git commit --author "Your Name <your@email.com>"
at the moment of doing a commit in a repo where you want to commit as a different user.