使用场景

个人电脑里同时有公司的项目的源码和自己的开源项目的源码,而一般在公司使用的nameemail配置跟家用的都是区分开的。 如何实现,在进入公司项目的目录提交git commit时让Git自动使用公司邮箱和名称,而在进入其它目录时则保持家用的配置呢?

答案就是:Git Conditional Includes

使用Conditional Includes

老灯的需求比较简单,只有home和work两种情况。因此,配置如下:

~/repo/go/work 目录是公司项目的根目录,下面会有多层子目录。 除此之外,其它repo都默认是老灯自己的个人项目。

~/.gitconfig 作为配置的入口,根据条件引入其它配置:

# 默认的 user.name 和 user.email 配置
[include]
  path = ~/.gitconfig_home

# 如果是公司项目的目录,则使用另一个配置
[includeIf "gitdir:~/repo/go/work/"]
  path = ~/.gitconfig_work

这个配置非常简单,默认先导入~/.gitconfig_home中的Git配置, 如果repo是在~/repo/go/work/之下(包括其下所有子目录), 则导入 ~/.gitconfig_work 中的Git配置

~/.gitconfig_home 内容如下:

[user]
	name = 荒野無燈
	email = [email protected]
	signingkey = BE78EC4026F094F8

~/.gitconfig_work内容如下:

[user]
	name = 姓名
	email = myema[email protected]
	signingkey = xxxxxxxxxxxxxxx

Conditional Includes 主要支持三个关键字:gitdirgitdir/ionbranch

这里老灯只用到了 gitdir,它的忽略大小写版则是gitdir/i了。

这里有一些细节需要注意, Git文档说得很清楚:

gitdir: 关键字用于glob匹配模式. 如果 .git 目录匹配,则满足include的条件.

.git的位置可被自动检测,或者来自$GIT_DIR环境变量。

  • 如果 pattern 以 ~/开头,则~会被自动替换成 $HOME 的值。
  • 如果 pattern 以 ./开头,则会被自动替换包含当前配置文件的目录。
  • 如果 pattern 不是以~/, .//中的任意一个开头,则**/会被自动前置。比如foo/bar实际上是变成**/foo/bar,能匹配/any/path/to/foo/bar
  • 如果 pattern 以 / 结尾,则**会被自动添加上。比如foo/ 会变成 foo/**,换句话说,它会匹配foo以及递归地匹配其下的所有目录。因此我们没必要显式地写foo/**

另外, 老灯这里的情况比较简单,因此,其实只需要一个includeIf即可:

# 默认的 user.name 和 user.email 配置
[user]
	name = 荒野無燈
	email = [email protected]
	signingkey = BE78EC4026F094F8

# 如果是公司项目的目录,则使用另一个配置
[includeIf "gitdir:~/repo/go/work/"]
  path = ~/.gitconfig_work

当然,老灯用一个默认的include的好处是,分享 .gitconfig 给别人的时候, 就默认不会leak 用户名和email了。

本文参考

https://blog.jiayu.co/2019/02/conditional-git-configuration/

https://blog.thomasheartman.com/posts/modularizing-your-git-config-with-conditional-includes

https://git-scm.com/docs/git-config#Documentation/git-config.txt-codegitdircode

https://dzone.com/articles/how-to-use-gitconfigs-includeif