Can I specify multiple users for myself in .gitcon

2018-12-31 16:57发布

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 started using git for work, too. My company's git repo allows me to commit, but when it sends out announcements of new changesets, it says they are from Anonymous because it doesn't recognize the email address in my .gitconfig - at least, that's my theory.

Is it possible to specify multiple [user] definitions in .gitconfig? Or is there some other way to override the default .gitconfig for a certain directory? In my case, I check out all work code in ~/worksrc/ - is there a way to specify a .gitconfig for only that directory (and its subdirectories)?

标签: git
19条回答
一个人的天荒地老
2楼-- · 2018-12-31 17:21

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.

查看更多
永恒的永恒
3楼-- · 2018-12-31 17:21

I made a bash function that handle that. Here is the Github repo.

For record:

# Look for closest .gitconfig file in parent directories
# This file will be used as main .gitconfig file.
function __recursive_gitconfig_git {
    gitconfig_file=$(__recursive_gitconfig_closest)
    if [ "$gitconfig_file" != '' ]; then
        home="$(dirname $gitconfig_file)/"
        HOME=$home /usr/bin/git "$@"
    else
        /usr/bin/git "$@"
    fi
}

# Look for closest .gitconfig file in parents directories
function __recursive_gitconfig_closest {
    slashes=${PWD//[^\/]/}
    directory="$PWD"
    for (( n=${#slashes}; n>0; --n ))
    do
        test -e "$directory/.gitconfig" && echo "$directory/.gitconfig" && return 
        directory="$directory/.."
    done
}


alias git='__recursive_gitconfig_git'
查看更多
墨雨无痕
4楼-- · 2018-12-31 17:22

May be it is simple hack, but it is useful. Just generate 2 ssh keys like below.

Generating public/private rsa key pair.
Enter file in which to save the key (/Users/GowthamSai/.ssh/id_rsa): work
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in damsn.
Your public key has been saved in damsn.pub.
The key fingerprint is:
SHA256:CrsKDJWVVek5GTCqmq8/8RnwvAo1G6UOmQFbzddcoAY GowthamSai@Gowtham-MacBook-Air.local
The key's randomart image is:
+---[RSA 4096]----+
|. .oEo+=o+.      |
|.o o+o.o=        |
|o o o.o. +       |
| =.+ .  =        |
|= *+.   S.       |
|o*.++o .         |
|=.oo.+.          |
| +. +.           |
|.o=+.            |
+----[SHA256]-----+

Same way create one more for personal. So, you have 2 ssh keys, work and company. Copy work.pub, work, personal.pub, personal to ~/.ssh/ Directory.

Then create shell script with the following lines and name it as crev.sh (Company Reverse) with following content.

cp ~/.ssh/work ~/.ssh/id_rsa
cp ~/.ssh/work.pub ~/.ssh/id_rsa.pub

Same way, create one more called prev.sh (Personal Reverse) with the following content.

cp ~/.ssh/personal ~/.ssh/id_rsa
cp ~/.ssh/personal.pub ~/.ssh/id_rsa.pub

in ~/.bashrc add aliases for those scripts like below

alias crev="sh ~/.ssh/crev.sh"
alias prev="sh ~/.ssh/prev.sh"
source ~/.bashrc

When ever you wanna use company, just do crev, and if you wanna use personal do prev :-p.

Add those ssh keys to your github accounts. Make sure, you don't have id_rsa generated perviously, because those scripts will overwrite id_rsa. If you have already generated id_rsa, use that for one of the account. Copy them as personal and skip generation of personal keys.

查看更多
妖精总统
5楼-- · 2018-12-31 17:26

With conditional includes in Git 2.13, it is now possible to have multiple user/email coexist on one machine with little work.

user.gitconfig has my personal name and email. work-user.gitconfig has my work name and email. Both files are at ~ path.

So my personal name/email applies by default. For c:/work/ dir, my work name/email is applied. For c:/work/github/ dir, my personal name/email is applied. This works as the last setting gets applied.

# ~/.gitconfig
[include]
    path = user.gitconfig
[includeIf "gitdir/i:c:/work/"]
    path = work-user.gitconfig
[includeIf "gitdir/i:c:/work/github/"]
    path = user.gitconfig

gitdir is case-sensitive and gitdir/i is case-insensitive.

"gitdir/i:github/" would apply the conditional include for any directory with github in its path.

查看更多
高级女魔头
6楼-- · 2018-12-31 17:28

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

  1. copy default public key pbcopy < ~/.ssh/id_rsa.pub
  2. login to your GitHub acount
  3. paste the key in the add SSH key github page
  4. copy other public key pbcopy < ~/.ssh/id_rsa_pro.pub
  5. repeat and adapt steps 2 to 4 for every other account

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 origin set-url 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:

  • change current project remotes to the chosen aliases
  • change current project user.email config

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 -Tutorial

查看更多
听够珍惜
7楼-- · 2018-12-31 17:28

Something like Rob W's answer, but allowing different a different ssh key, and works with older git versions (which don't have e.g. a core.sshCommand config).

I created the file ~/bin/git_poweruser, with executable permission, and in the PATH:

#!/bin/bash

TMPDIR=$(mktemp -d)
trap 'rm -rf "$TMPDIR"' EXIT

cat > $TMPDIR/ssh << 'EOF'
#!/bin/bash
ssh -i $HOME/.ssh/poweruserprivatekey $@
EOF

chmod +x $TMPDIR/ssh
export GIT_SSH=$TMPDIR/ssh

git -c user.name="Power User name" -c user.email="power@user.email" $@

Whenever I want to commit or push something as "Power User", I use git_poweruser instead of git. It should work on any directory, and does not require changes in .gitconfig or .ssh/config, at least not in mine.

查看更多
登录 后发表回答