[git] How to tell git to use the correct identity (name and email) for a given project?

I use my personal laptop for both work and personal projects and I would like to use my work email address for my commits at work (gitolite) and my personal email address for the rest (github).

I read about the following solutions which are all either global or temporary:

One solution is to run manually a shell function that sets my environment to work or personal, but I am pretty sure that I will often forget to switch to the correct identity resulting in committing under the wrong identity.

Is there a way of binding a certain repository, project name, etc. to an identity (name, email)? What do people do?

This question is related to git github gitolite git-config

The answer is


I very like the way of Micah Henning in his article (see Setting Up Git Identities) on this subject. The fact that he apply and force the identity to each repository created/cloned is a good way not to forget to set this up each time.

Basic git configuration

Unset current user config in git:

$ git config --global --unset user.name
$ git config --global --unset user.email
$ git config --global --unset user.signingkey

Force identity configuration on each new local repository:

$ git config --global user.useConfigOnly true

Create Git alias for identity command, we will use later:

$ git config --global alias.identity '! git config user.name "$(git config user.$1.name)"; git config user.email "$(git config user.$1.email)"; git config user.signingkey "$(git config user.$1.signingkey)"; :'

Identities creation

Create an identity with GPG (use gpg or gpg2 depending on what you got on your system). Repeat next steps for each identities you want to use.

Note: [keyid] here is the identifier of created secret key. Example here:

sec   rsa4096/8A5C011E4CE081A5 2020-06-09 [SC] [expires: 2021-06-09]
      CCC470AE787C057557F421488C4C951E4CE081A5
uid                 [ultimate] Your Name <youremail@domain>
ssb   rsa4096/1EA965889861C1C0 2020-06-09 [E] [expires: 2021-06-09]

The 8A5C011E4CE081A5 part after sec rsa4096/ is the identifier of key.

$ gpg --full-gen-key
$ gpg --list-secret-keys --keyid-format LONG <youremail@domain>
$ gpg --armor --export [keyid]

Copy the public key block and add it to your GitHub/GitProviderOfChoice settings as a GPG key.

Add identity to Git config. Also repeat this for each identity you want to add:

Note: here I use gitlab to name my identity, but from your question it can be anything, ex: gitolite or github, work, etc.

$ git config --global user.gitlab.name "Your Name"
$ git config --global user.gitlab.email "youremail@domain"
$ git config --global user.gitlab.signingkey [keyid]

Setup identity for a repository

If a new repo has no identity associated, an error will appear on commit, reminding you to set it.

*** Please tell me who you are.

## parts of message skipped ##

fatal: no email was given and auto-detection is disabled

Specify the identity you want on a new repository:

$ git identity gitlab

You're now ready to commit with the gitlab identity.


If you don't use the --global parameter it will set the variables for the current project only.


One solution is to run manually a shell function that sets my environment to work or personal, but I am pretty sure that I will often forget to switch to the correct identity resulting in committing under the wrong identity.

That was exactly my problem. I have written a hook script which warns you if you have any github remote and not defined a local username.

Here's how you set it up:

  1. Create a directory to hold the global hook

    mkdir -p ~/.git-templates/hooks

  2. Tell git to copy everything in ~/.git-templates to your per-project .git directory when you run git init or clone

    git config --global init.templatedir '~/.git-templates'

  3. And now copy the following lines to ~/.git-templates/hooks/pre-commit and make the file executable (don't forget this otherwise git won't execute it!)

#!/bin/bash

RED='\033[0;31m' # red color
NC='\033[0m' # no color

GITHUB_REMOTE=$(git remote -v | grep github.com)
LOCAL_USERNAME=$(git config --local user.name)

if [ -n "$GITHUB_REMOTE" ] && [ -z "$LOCAL_USERNAME" ]; then
    printf "\n${RED}ATTENTION: At least one Github remote repository is configured, but no local username. "
    printf "Please define a local username that matches your Github account.${NC} [pre-commit hook]\n\n"
    exit 1
fi

If you use other hosts for your private repositories you have to replace github.com according to your needs.

Now every time you do a git init or git clone git will copy this script to the repository and executes it before any commit is done. If you have not set a local username it will output a warning and won't let you commit.


You need to use the local set command below:

local set

git config user.email [email protected]
git config user.name 'Mahmoud Zalt'

local get

git config --get user.email
git config --get user.name

The local config file is in the project directory: .git/config.

global set

git config --global user.email [email protected]
git config --global user.name 'Mahmoud Zalt'

global get

git config --global --get user.email
git config --global --get user.name

The global config file in in your home directory: ~/.gitconfig.

Remember to quote blanks, etc, for example: 'FirstName LastName'


As of Git 2.13 you can use an includeIf in your gitconfig to include a file with a different configuration based on the path of the repository where you are running your git commands.

Since a new enough Git comes with Ubuntu 18.04 I've been using this in my ~/.gitconfig quite happily.

[include]
  path = ~/.gitconfig.alias # I like to keep global aliases separate
  path = ~/.gitconfig.defaultusername # can maybe leave values unset/empty to get warned if a below path didn't match
# If using multiple identities can use per path user/email
# The trailing / is VERY important, git won't apply the config to subdirectories without it
[includeIf "gitdir:~/projects/azure/"]
  path = ~/.gitconfig.azure # user.name and user.email for Azure
[includeIf "gitdir:~/projects/gitlab/"]
  path = ~/.gitconfig.gitlab # user.name and user.email for GitLab
[includeIf "gitdir:~/projects/foss/"]
  path = ~/.gitconfig.github # user.name and user.email for GitHub

https://motowilliams.com/conditional-includes-for-git-config#disqus_thread

To use Git 2.13 you will either need to add a PPA (Ubuntu older than 18.04/Debian) or download the binaries and install (Windows/other Linux).


Edit the config file with in ".git" folder to maintain the different username and email depends upon the repository

  • Go to Your repository
  • Show the hidden files and go to ".git" folder
  • Find the "config" file
  • Add the below lines at EOF

[user]

name = Bob

email = [email protected]

This below command show you which username and email set for this repository.

git config --get user.name

git config --get user.email

Example: for mine that config file in D:\workspace\eclipse\ipchat\.git\config

Here ipchat is my repo name


If you use git config user.email "[email protected]" it will be bound to the current project you are in.

That is what I do for my projects. I set the appropriate identity when I clone/init the repo. It is not fool-proof (if you forget and push before you figure it out you are hosed) but it is about as good as you can get without the ability to say git config --global user.email 'ILLEGAL_VALUE'

Actually, you can make an illegal value. Set your git config --global user.name $(perl -e 'print "x"x968;')

Then if you forget to set your non-global values you will get an error message.

[EDIT] On a different system I had to increase the number of x to 968 to get it to fail with "fatal: Impossibly long personal identifier". Same version of git. Strange.


Examples related to git

Does the target directory for a git clone have to match the repo name? Git fatal: protocol 'https' is not supported Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) git clone: Authentication failed for <URL> destination path already exists and is not an empty directory SSL_connect: SSL_ERROR_SYSCALL in connection to github.com:443 GitLab remote: HTTP Basic: Access denied and fatal Authentication How can I switch to another branch in git? VS 2017 Git Local Commit DB.lock error on every commit How to remove an unpushed outgoing commit in Visual Studio?

Examples related to github

Does the target directory for a git clone have to match the repo name? Issue in installing php7.2-mcrypt How can I switch to another branch in git? How to draw checkbox or tick mark in GitHub Markdown table? How to add a new project to Github using VS Code git clone error: RPC failed; curl 56 OpenSSL SSL_read: SSL_ERROR_SYSCALL, errno 10054 How to add empty spaces into MD markdown readme on GitHub? key_load_public: invalid format git - remote add origin vs remote set-url origin Cloning specific branch

Examples related to gitolite

Specify an SSH key for git push for a given domain How to tell git to use the correct identity (name and email) for a given project?

Examples related to git-config

How to know the git username and email saved during configuration? How to save username and password in Git? git: fatal unable to auto-detect email address How to change my Git username in terminal? How do I commit case-sensitive only filename changes in Git? Unable to auto-detect email address git: 'credential-cache' is not a git command Is it possible to have different Git configuration for different projects? How to tell git to use the correct identity (name and email) for a given project? Is there a way to cache GitHub credentials for pushing commits?