为所有子文件夹设置git配置值

139

我知道可以设置每个仓库的配置文件,这将覆盖用户级别的配置文件(即/path/to/my/repo/.gitconfig会覆盖~/.gitconfig)。是否可以设置Git配置文件以覆盖给定文件夹的所有子文件夹的用户级别设置?也就是说,我有一个

|--topLevelFolder1
|--\
|   ---.gitconfig_override
|--\
|   ---childFolder1
|       \---[...]
|--\
|   ---childFolder2
|       \---[...]
我希望 .gitconfig_override 中定义的设置可以应用于 childFolder1childFolder2 。我这样做的动机是:我的工作笔记本电脑也用于我个人项目的业余时间。所有的工作代码都嵌套在一个文件夹中。当我推送到工作 git 仓库时,我需要使用我的工作账户 - 工作登录名和工作电子邮件。当我向我的个人(github)仓库推送时,我想使用我的真实姓名和个人电子邮件。我考虑了其他可能的解决方案(以及问题):
- 为 "工作" 和 "玩耍" 创建单独的用户,根据需要设置它们的用户级别设置,并在切换上下文时作为适当的用户登录(麻烦,而且我很容易忘记切换) - 创建一个脚本来搜索 "workFolder" 中的 git 仓库,并添加/更新它们的 .gitconfig 文件以保存适当的详细信息(如果我创建一个仓库并忘记在推送之前运行脚本,我将以错误的身份推送) - “hack” git,使每次创建仓库时它都会检查文件路径,并在适当时更新 .gitconfig 文件(复杂,混乱,几乎肯定是错误的做法 - 而且,我不知道该如何着手!)
我查看了这个问题,它似乎只包含单个仓库的解决方案,而不是多个。希望有人会看到这个问题,并提供更好的解决方案。

你会在同一个代码库上与“工作中的你”和“个人中的你”一起工作吗?如果不是,你链接的问题中包含了我会给出的答案。你的--global用户设置应该包含你更常用的身份信息。每个需要使用另一个身份的代码库都应该相应地设置user.nameuser.email - Chris
1
我永远不会与两个不同的用户在同一个repo中工作 - 每个repo将是“工作”或“家庭” - 但问题在于(至少对于工作而言),我有大约35个repos,并且正在定期添加更多。我可以在每个现有repo中添加user.nameuser.email设置,并设置一个cron脚本以将它们添加到任何新添加的repo中,但如果我可以在单个位置中设置它们,则会更容易地“过滤掉”任何子文件夹中的任何repo。 - scubbo
1
@scubbo,请审核答案,因为 Git 已经发生了变化,可能会使不同的答案成为你问题的正确答案。 - ndemarco
1
谢谢提醒!我刚刚修改了被接受的答案。 - scubbo
4个回答

212
NateEag's edit所提到的,git的条件包含非常适合这个问题。由于那个答案适用于git版本< 2.13的用户,这里给那些使用更新版本的用户提供一个解决方案。
首先,在某个地方创建一个新的配置文件,其中包含你想要在子文件夹中生效的设置 - 假设原始问题中的文件夹是~/topLevelFolder1/.gitconfig_include 然后,在~/.gitconfig中添加以下内容:
[includeIf "gitdir:~/toplevelFolder1/"]
    path = ~/topLevelFolder1/.gitconfig_include

现在,~/topLevelFolder1 的任何子文件夹都将包含 ~/toplevelFolder1/.gitconfig_include 中的配置 - 没有必要手动更改每个子文件夹仓库中的 .git/config。(这不会覆盖子文件夹配置中的任何内容 - 它只是添加到其中,因为 "include" 意味着如此。)

备注:

  • ~/.gitconfig文件中,此设置应位于要覆盖的配置之后,因为includeIf将被后面的任何配置再次覆盖。
  • 只有当您在给定路径下的存储库中时,此设置才会包含该文件。如果您在任何非存储库子路径中,则会忽略它。
  • gitdir条件中的尾部斜杠(/)很重要。
  • 使用git config --list进行测试是很好的。您将在输出中看到includeIf行下面的任何覆盖。您还可以使用git config --get user.email检查特定条目。
  • Git for Windows上,使用~/指定相对于用户目录的路径,使用Windows风格的驱动器绝对路径,例如C:/,仅使用正斜杠。反斜杠和类似/c/的Unix风格挂载点不起作用。此外,在includeIf部分,您必须使用正确大小写指定路径,因为比较是区分大小写的。

27
gitdir条件中,末尾的斜杠 (/) 很重要。 - stefanct
2
这应该被标记为这个问题的正确答案。由于提到了includeIf(加上一点尝试和错误),我现在已经配置了我工作电脑上的一个特定文件夹树,其中每个Git操作都将我识别为我的个人帐户并使用我的个人SSH密钥,以及类似的用于个人电脑上的工作内容的文件夹。同时,每个系统的其余部分在两台机器上都使用适当的电子邮件、姓名和SSH密钥。我只希望我能给这个答案多投一次赞.. (: - user909694
2
如果git只是按照逻辑遍历树形目录,在每个父目录中查找.git目录,那该多好啊... - Ian Kemp
2
目标不是在文件存在时包含该文件,而是在位于给定路径下的存储库中包含该文件。 - phemmer
还有一件事。这个设置应该位于您想要覆盖的配置之后的/.gitconfig中。否则,includeIf将再次被/.gitconfig中的配置覆盖。 - Jinsoo Heo
显示剩余3条评论

40

编辑:Git 2.13引入了条件包含,旨在解决这个确切的问题。

为了历史和使用旧版本git的用户的缘故,我保留了原始答案。

====================================

根据阅读gitconfig手册,不支持您期望的确切行为。

然而,自从git 1.7.12版本以来,Git从四个不同的来源读取配置数据,其中两个是用户特定的:

$XDG_CONFIG_HOME/git/config~/.gitconfig~/.gitconfig中的条目会覆盖$XDG_CONFIG_HOME/git/config中的条目。

这意味着您可以将个人gitconfig存储在$XDG_CONFIG_HOME/git/config中,并在~/.gitconfig中放置特定于机器的覆盖项。例如:

[user]
    email = username@example.com

~/.gitconfig中应该涵盖您的电子邮件情况。

请注意,如果未设置$XDG_CONFIG_HOME,则git将查找~/.config/git/config

对我来说,这很有效,因为我只在工作机器上有两个个人存储库(我的emacs配置和我的dotfiles)。如果您经常向工作机器添加个人存储库,则可能不足够。

在那种情况下,自定义git initgit clone包装器是最好的选择。

您的$PATH上任何名称与“git-*”匹配的二进制文件都可以被称为git命令,因此您只需要一对shell脚本,调用所有传递的参数的原始命令,然后将正确的配置文件复制到.git/config中。


一些git设置可以通过设置环境变量来控制。它们会覆盖配置文件中的值。一个非常好用的工具,用于在目录层次结构中设置/取消设置环境变量是direnv。请查看下面的答案获取所有细节。 - Ajay M

16

您可以使用direnv命令设置应用于所有子文件夹的环境变量。您可以在该目录层次结构的任何位置。如果您要设置的git设置可以通过环境变量进行控制,那么您很幸运。

阅读 http://direnv.net/ 上的direnv基础页面以为您的shell设置它。对于zsh,只需将此行粘贴到我的.zshrc底部并重新启动shell即可。

eval "$(direnv hook zsh)"

检查您想要的 git 设置是否可以由环境变量控制。看起来您想要控制某个目录树下的 author.email,这是由环境变量 GIT_AUTHOR_EMAIL 控制的。请注意,环境变量优先于配置文件。Git 支持的完整环境变量列表在这里:https://git-scm.com/book/en/v2/Git-Internals-Environment-Variables

direnv 的页面所述,在层次结构的根目录下创建名为 .envrc 的文件;在您的情况下,是 topLevelFolder1

例如:

echo export GIT_AUTHOR_EMAIL=myotheremail@esp.com > .envrc

"Allow"这个envrc文件:direnv allow . 就这样!

每次你进入该层级,direnv都会查找所述的 .envrc 文件并加载它。

$ cd ~/topLevelFolder1/childFolder1/project_name
direnv: loading ../../../.envrc
direnv: export +GIT_AUTHOR_EMAIL

$ echo ${GIT_AUTHOR_EMAIL}
myotheremail@esp.com

跳出目录结构,direnv 将卸载那些变量。

cd ~
direnv: unloading

8
在git配置文件(.git/config~/.gitconfig等)中,[include]部分是您要查找的内容。
[include]
    path = /path/to/foo.inc ; include by absolute path
    path = foo ; expand "foo" relative to the current file
    path = ~/foo ; expand "foo" in your $HOME directory

请查看详细的答案: 是否可以在.gitconfig文件中包含一个文件 请参考git-config文档:http://git-scm.com/docs/git-config#_includes 编辑childFolder1/.git/configchildFolder2/.git/config中添加:
[include]
    path = ../.gitconfig_override

2
好的 - 所以这解决了只在一个地方(在 ../.gitconfig_override 中)定义 user.nameuser.email 的问题,但我不认为它实际上回答了原始问题?如果 childFolder1childFolder2parentFolder 的子文件夹,我正在寻找一种设置 parentFolder 中的配置值,以便过滤到根源于子文件夹的任何存储库的方法。 - scubbo
1
正如NateEag指出的,这只在Git 2.13中引入。(Git 2.13.0于2017年5月9日发布。)因此,如果有人阅读此答案并想知道为什么它对他们不起作用,可能是因为他们正在使用旧版本的Git。 - user82216
请注意,最近我遇到了一个问题,即这些条件包含似乎没有被尊重。问题在于git(至少是我的安装-2.17.0在MacOSX上)似乎需要在目录路径上添加尾随斜杠。 - scubbo

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