Git 配置目录范围,包含多个存储库
Git config with directory scope, containing multiple repositories
情况如下:
- 我有多个 域,我在其中编写代码,例如专业和空闲时间。这些由我计算机上的不同目录表示。
- 这些域中的每一个都包含多个 Git 存储库,在一个域目录内的分层目录结构中。
对于每个域,我想使用不同的电子邮件地址作为 author/committer 信息的一部分。也就是说,我希望在我的业余项目中列出我的私人地址,在我的专业项目中列出我的公司地址。
git config
知道 3 个范围:存储库、全局和系统范围。 我基本上需要的是存储库和全局之间的第 4 个作用域,代表一组存储库(或只是文件系统中的一个目录)。
似乎 git config
不允许这样做。当然,我可以为每个存储库设置电子邮件地址,但我想在每次设置或克隆存储库时避免这个手动步骤。一种选择是编写一个包装 git init/clone
和 git config
的脚本,还有其他想法吗?
作为一个简单的解决方案,使用类似 autoenv 的东西(对不起自我广告)来设置环境变量的邮件地址:
echo 'export GIT_AUTHOR_NAME="Your name"' > professional/.env
echo 'export GIT_AUTHOR_EMAIL="you@example.com"' >> professional/.env
cd professional
我想出的解决方案的灵感来自 。由于它不能直接适用于我的情况,我修改了 hook 的 bash 脚本并改进了几个部分*。
假定主目录的目录结构如下:
~
.gitconfig // [init] templatedir
.git-template
hooks
post-checkout // our bash script
MyDomain
.gitconfig // [user] name, email
最初我让 Git 知道我的模板目录在哪里。在 Windows 上,您可能需要改为指定绝对路径 (C:/Users/MyUser/.git-template
)。
git config --global init.templatedir '~/.git-template'
在 ~/MyDomain/.gitconfig
中,我存储了该目录 (domain) 的配置,它应该应用于它及其子目录中的所有存储库。
cd ~/MyDomain
git config --file .gitconfig user.name "My Name"
git config --file .gitconfig user.email "my@email.com"
有趣的部分是 post-checkout
bash 脚本,它定义了 post-checkout 钩子。我使用自定义 user.inferredConfig
标志仅执行一次(在 git clone
上),而不是重复执行(在 git checkout
上)。当然也可以创建一个单独的文件来表示该状态。
#!/bin/bash
# Git post-checkout hook for automated use of directory-local git config
#
# Check for custom git-config flag, to execute hook only once on clone, not repeatedly on every checkout
if grep -q "inferredConfig" .git/config
then
exit
fi
# Automatically set Git config values from parent folders.
echo "Infer Git configuration from directory..."
# Go upwards in directory hierarchy, examine all .gitconfig files we find
# Allows to have multiple nested .gitconfig files with different scopes
dir=$(pwd)
configFiles=()
while [ "$dir" != "/" ]
do
# Skip first directory (the newly created Git repo)
dir=$(dirname "$dir")
if [ -f "$dir/.gitconfig" ]
then
configFiles+=("$dir/.gitconfig")
fi
done
# Iterate through configFiles array in reverse order, so that more local configurations override parent ones
for (( index=${#configFiles[@]}-1 ; index>=0 ; index-- )) ; do
gitconfig="${configFiles[index]}"
echo "* From $gitconfig:"
# Iterate over each line in found .gitconfig file
output=$(git config --file "$gitconfig" --list)
while IFS= read -r line
do
# Split line into two parts, separated by '='
IFS='=' read key localValue <<< "$line"
# For values that differ from the parent Git configuration, adjust the local one
parentValue=$(git config $key)
if [ "$parentValue" != "$localValue" ]
then
echo " * $key: $localValue"
git config "$key" "$localValue"
fi
done <<< "$output"
# Set custom flag that we have inferred the configuration, so that future checkouts don't need to do it
git config user.inferredConfig 1
done
*:对原始代码的更改包括:
- 在路径中使用空格(在 Windows 上特别有趣)
- 正确解析
.gitconfig
中的键值对 (don't read lines with for
, iterate with while read
instead)
- 从根目录到本地目录检查
.gitconfig
个文件,反之亦然
- 仅在初始克隆时调用挂钩,而不是在每次结帐时调用挂钩
- 输出应用于
git clone
的配置设置
基于,我想我找到了一种工作方式。
首先为您的 "custom-scopes" 创建不同的配置文件(例如专业、空闲时间等)并为每个范围添加您想要的 user-config
# ~/all-projects.gitconfig
[user]
name = TheOperator
。
# ~/professional.gitconfig
[user]
email = yourname@yourwork.com
.
# ~/freetime.gitconfig
[user]
email = yourname@private-email.com
比你在标准 gitconfig 中添加这样的行:
# ~/.gitconfig
[include]
path = all-projects.gitconfig
[includeIf "gitdir/i:c:/work/"]
path = professional.gitconfig
[includeIf "gitdir/i:c:/freetime/"]
path = freetime.gitconfig
"gitdir/i" 之后的目录应该与您的项目组的父目录相匹配。
在我的示例中,您应该将 git-repos 存储为 freetime-domains,例如"c:/freetime/my-freetime.domain/.git"
情况如下:
- 我有多个 域,我在其中编写代码,例如专业和空闲时间。这些由我计算机上的不同目录表示。
- 这些域中的每一个都包含多个 Git 存储库,在一个域目录内的分层目录结构中。
对于每个域,我想使用不同的电子邮件地址作为 author/committer 信息的一部分。也就是说,我希望在我的业余项目中列出我的私人地址,在我的专业项目中列出我的公司地址。
git config
知道 3 个范围:存储库、全局和系统范围。 我基本上需要的是存储库和全局之间的第 4 个作用域,代表一组存储库(或只是文件系统中的一个目录)。
似乎 git config
不允许这样做。当然,我可以为每个存储库设置电子邮件地址,但我想在每次设置或克隆存储库时避免这个手动步骤。一种选择是编写一个包装 git init/clone
和 git config
的脚本,还有其他想法吗?
作为一个简单的解决方案,使用类似 autoenv 的东西(对不起自我广告)来设置环境变量的邮件地址:
echo 'export GIT_AUTHOR_NAME="Your name"' > professional/.env
echo 'export GIT_AUTHOR_EMAIL="you@example.com"' >> professional/.env
cd professional
我想出的解决方案的灵感来自
假定主目录的目录结构如下:
~
.gitconfig // [init] templatedir
.git-template
hooks
post-checkout // our bash script
MyDomain
.gitconfig // [user] name, email
最初我让 Git 知道我的模板目录在哪里。在 Windows 上,您可能需要改为指定绝对路径 (C:/Users/MyUser/.git-template
)。
git config --global init.templatedir '~/.git-template'
在 ~/MyDomain/.gitconfig
中,我存储了该目录 (domain) 的配置,它应该应用于它及其子目录中的所有存储库。
cd ~/MyDomain
git config --file .gitconfig user.name "My Name"
git config --file .gitconfig user.email "my@email.com"
有趣的部分是 post-checkout
bash 脚本,它定义了 post-checkout 钩子。我使用自定义 user.inferredConfig
标志仅执行一次(在 git clone
上),而不是重复执行(在 git checkout
上)。当然也可以创建一个单独的文件来表示该状态。
#!/bin/bash
# Git post-checkout hook for automated use of directory-local git config
#
# Check for custom git-config flag, to execute hook only once on clone, not repeatedly on every checkout
if grep -q "inferredConfig" .git/config
then
exit
fi
# Automatically set Git config values from parent folders.
echo "Infer Git configuration from directory..."
# Go upwards in directory hierarchy, examine all .gitconfig files we find
# Allows to have multiple nested .gitconfig files with different scopes
dir=$(pwd)
configFiles=()
while [ "$dir" != "/" ]
do
# Skip first directory (the newly created Git repo)
dir=$(dirname "$dir")
if [ -f "$dir/.gitconfig" ]
then
configFiles+=("$dir/.gitconfig")
fi
done
# Iterate through configFiles array in reverse order, so that more local configurations override parent ones
for (( index=${#configFiles[@]}-1 ; index>=0 ; index-- )) ; do
gitconfig="${configFiles[index]}"
echo "* From $gitconfig:"
# Iterate over each line in found .gitconfig file
output=$(git config --file "$gitconfig" --list)
while IFS= read -r line
do
# Split line into two parts, separated by '='
IFS='=' read key localValue <<< "$line"
# For values that differ from the parent Git configuration, adjust the local one
parentValue=$(git config $key)
if [ "$parentValue" != "$localValue" ]
then
echo " * $key: $localValue"
git config "$key" "$localValue"
fi
done <<< "$output"
# Set custom flag that we have inferred the configuration, so that future checkouts don't need to do it
git config user.inferredConfig 1
done
*:对原始代码的更改包括:
- 在路径中使用空格(在 Windows 上特别有趣)
- 正确解析
.gitconfig
中的键值对 (don't read lines withfor
, iterate withwhile read
instead) - 从根目录到本地目录检查
.gitconfig
个文件,反之亦然 - 仅在初始克隆时调用挂钩,而不是在每次结帐时调用挂钩
- 输出应用于
git clone
的配置设置
基于,我想我找到了一种工作方式。
首先为您的 "custom-scopes" 创建不同的配置文件(例如专业、空闲时间等)并为每个范围添加您想要的 user-config
# ~/all-projects.gitconfig
[user]
name = TheOperator
。
# ~/professional.gitconfig
[user]
email = yourname@yourwork.com
.
# ~/freetime.gitconfig
[user]
email = yourname@private-email.com
比你在标准 gitconfig 中添加这样的行:
# ~/.gitconfig
[include]
path = all-projects.gitconfig
[includeIf "gitdir/i:c:/work/"]
path = professional.gitconfig
[includeIf "gitdir/i:c:/freetime/"]
path = freetime.gitconfig
"gitdir/i" 之后的目录应该与您的项目组的父目录相匹配。 在我的示例中,您应该将 git-repos 存储为 freetime-domains,例如"c:/freetime/my-freetime.domain/.git"