给定子目录的不同.gitconfig是什么?

72

我使用两个不同的Git电子邮件,一个用于工作,另一个用于公共项目。最初我认为我可以在存放所有公共仓库的文件夹中创建一个单独的.gitconfig,并在其中使用不同的电子邮件地址,这样Git就会遵循它,但不幸的是似乎并不起作用。有什么简单的设置方式吗?我想避免在每个公共仓库中具体更改电子邮件。


3
Git 2.13 引入了条件包含。请参见此答案 - John Lindal
7个回答

110
自 git 2.13 以来,最好的方法是使用条件包含
例如(从答案此处复制):
全局配置文件 ~/.gitconfig
[user]
    name = John Doe
    email = john@doe.tld

[includeIf "gitdir:~/work/**"]
    path = ~/work/.gitconfig

工作相关配置 ~/work/.gitconfig

[user]
    email = john.doe@company.tld

4
这比其他答案中的Shell自定义更整洁,谢谢。 - Greg
6
这可能是显而易见的,但仍然很有趣:当将多个git仓库分组超出一个非git仓库的目录时,效果只会在git仓库内部可见,而不会在父级目录中显示。 - chronicc
我能否在includeIf中使用通配符来使用任何子目录的配置?我想将存储库组织在文件夹中,而不是直接检出它们到“〜/工作/”,但可能是在“〜/工作/项目/”或“〜/工作/论文”中。 - blkpingu
4
"Conditional includes"是非常强大的。上面的例子之所以可以使用是因为gitdir以斜杠结尾:如果模式以斜杠结尾,**将自动添加。例如,模式foo/变成foo/**。换句话说,它会递归地匹配"foo"及其内部的所有内容。 - Chris Crewdson
1
@chronicc 谢谢!这对我来说不是很明显,你的评论让我省去了一些沮丧。 - m00am
我更倾向于只包括**。 这样出错的机会较小,而且我更喜欢少些神奇操作。 - Tim Harper

9

如其他回答中所述,您无法为每个目录单独设置凭据。但是,git允许您对每个存储库进行这样的设置。

# Require setting user.name and email per-repo
$ git config --global user.useConfigOnly true

这样,当您第一次提交时,会出现一个错误提示您提供姓名和电子邮件。在您的存储库文件夹中添加您的凭据一次,然后从那时起,您将使用此身份验证进行提交:

$ cd path/to/repo
$ git config user.name My Name
$ git config user.email mail@example.com

这应该是答案。但是,为了使其正常工作,需要Git 2.8。 - dsclose
很不幸,这会重复命令。如果我有一个文件夹/job,并计划在接下来的一周左右创建100个新项目,那么我必须一遍又一遍地输入我的名字等信息100次。如果我可以为/job只做一次,然后它适用于所有现有或将来可能创建的子文件夹,那就更好了。 - theprogrammer

8

我有完全相同的问题。作为临时解决方案,我在.bashrc中添加了以下内容:

alias git='GIT_AUTHOR_EMAIL=$(
      p=$(pwd)
      while [[ $p != "$HOME" ]]; do
        [ -e $p/.gitemail ] && cat $p/.gitemail && break
        p=$(dirname $p)
      done) GIT_COMMITTER_EMAIL=$(
      p=$(pwd)
      while [[ $p != "$HOME" ]]; do
        [ -e $p/.gitemail ] && cat $p/.gitemail && break
        p=$(dirname $p)
      done) /usr/bin/git'
alias g=git

这样我就在父目录下有两个不同的.gitemail文件:
  • ~/work/.gitemail
  • ~/github/.gitemail
需要注意的是,我只是通过这种方式切换了user.email,其他所有内容都在~/.gitconfig中集中管理。这是一种解决方案,但并不理想。
希望StackOverflow上的某位用户有更好的想法...

这个很好用,即使使用 defunkt/hub 也是如此。我只是将路径 /usr/bin/git 更改为 hub,然后它就可以工作了 ^_^ - TrinitronX
这段代码中存在一个无限循环。更糟糕的是,如果你使用调用git的提示符,那么如果你在家目录之外,这将导致所有交互式登录shell进入无限循环!我已经创建了一个修复版本在这个gist中,它作为一个函数工作,并且简化了别名定义。 - TrinitronX
1
是的,回头看,我发布的bash代码并不是最好的解决方案。:)虽然@TrinitronX的bash脚本可能更干净,但我真的很喜欢zsh的配置文件允许更清洁的解决方案:https://dev59.com/dGsy5IYBdhLWcg3wxAuO#8645101 - pithyless
我还没有尝试过zsh,但它似乎很流行。我仍然喜欢纯bash,因为它迫使我编写的脚本通常在其他*nix平台上开箱即用。这篇文章的更新提醒我再次查看它,并意识到脚本中可能会导致无限循环的几个其他边缘情况(带有空格的目录,dirname结果为空或'.')。我已经更新了gist脚本来修复它们。 - TrinitronX

7

我已经转换到ZSH,这是我使用“配置文件”在目录更改时解决问题的修改版解决方案。这个解决方案的好处是可以用于其他设置。

将此代码复制到您的zsh配置中:

#
# Thanks to: Michael Prokop. 
# More documentation: 
# http://git.grml.org/?p=grml-etc-core.git;f=etc/zsh/zshrc;hb=HEAD#l1120
#
CHPWD_PROFILE='default'
function chpwd_profiles() {
    local -x profile

    zstyle -s ":chpwd:profiles:${PWD}" profile profile || profile='default'
    if (( ${+functions[chpwd_profile_$profile]} )) ; then
        chpwd_profile_${profile}
    fi

    CHPWD_PROFILE="${profile}"
    return 0
}
chpwd_functions=( ${chpwd_functions} chpwd_profiles )

chpwd_profile_default # run DEFAULT profile automatically

还有在您的zsh git自定义中:

zstyle ':chpwd:profiles:/home/user/work(|/|/*)'  profile work
zstyle ':chpwd:profiles:/home/user/fun(|/|/*)'   profile fun

# configuration for profile 'default':
chpwd_profile_default()
{
  [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
  print "chpwd(): Switching to profile: default"

  export GIT_AUTHOR_EMAIL="default@example.com"
  export GIT_COMMITTER_EMAIL="default@example.com"
}

# configuration for profile 'fun':
chpwd_profile_fun()
{
  [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
  print "chpwd(): Switching to profile: $profile"

  export GIT_AUTHOR_EMAIL="fun@example.com"
  export GIT_COMMITTER_EMAIL="fun@example.com"
}

# configuration for profile 'work':
chpwd_profile_work()
{
  [[ ${profile} == ${CHPWD_PROFILE} ]] && return 1
  print "chpwd(): Switching to profile: $profile"

  export GIT_AUTHOR_EMAIL="work@example.com"
  export GIT_COMMITTER_EMAIL="work@example.com"
}

“elsewhere in your zsh git customizations” 是什么意思?除了 ~/.zshrc,我需要有一个单独的文件吗? - avi
我刚刚将这个添加到默认的~/.zshrc文件中,它可以正常工作。 - Almir Sarajčić

4

建立一个集中式机制来创建仓库,例如在您的路径中的一些脚本等,通过以下方式实现:

repo create -t public -n name

或类似的东西。

repo 命令(只是一个示例,与 Android 的命令无关)会在必要的位置为您创建 repo,并读取配置文件并根据类型(公共或私有等)为该 repo 设置凭据(在该 repo 的 .git/config 文件中)。


3
真正的答案是不可能的。
然而,多亏了 @pithyless,而且因为我已经使用了一个自定义的 'c' 函数来切换目录,接着是自动的 ls,这就是我现在正在做的事情:
# cd + ls, and change git email when in personal projects folder 
function c {
  if [[ "`abspath $1`" == *"$HOME/Projects"* ]]; then
    export GIT_AUTHOR_EMAIL="personal@gmail.com"
  else
    export GIT_AUTHOR_EMAIL="me@work.com"
  fi
  cd "${@:-$HOME}" && ls;
}

5
未来的读者(因为这被标记为答案),自git 2.13版本起,您无需再执行此操作。使用条件包含:https://dev59.com/dGsy5IYBdhLWcg3wxAuO#60344116 - Chris Crewdson

0
我有同样的需求,但我希望所有.gitconfig部分都可以被覆盖,而不仅仅是user.email和user.name。
因为我没有找到任何东西,所以我做了这个:https://github.com/arount/recursive-gitconfig 这里是当前的代码,请参考github源代码获取最新更新:
# 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'

这让我能够根据我正在使用的存储库使用特定的 .gitconfig。

希望这能帮助到你们中的一些人


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接