【问题标题】:Git config with directory scope, containing multiple repositories具有目录范围的 Git 配置,包含多个存储库
【发布时间】:2018-03-07 22:25:04
【问题描述】:

情况如下:

  • 我有多个 用于编写代码,例如专业和空闲时间。这些由我计算机上的不同目录表示。
  • 这些域中的每一个都包含多个 Git 存储库,位于其中一个域目录内的分层目录结构中。

对于每个域,我想使用不同的电子邮件地址作为作者/提交者信息的一部分。也就是说,我希望我的私人地址列在我的空闲时间项目中,我的公司地址列在我的专业项目中。

git config 知道 3 个范围:存储库、全局和系统范围。 我基本上需要的是存储库和全局之间的第四个范围,代表一组存储库(或只是文件系统中的一个目录)。

似乎git config 不允许这样做。当然,我可以为每个存储库设置电子邮件地址,但我希望在每次设置或克隆存储库时避免这个手动步骤。一种选择是编写一个包含git init/clonegit config 的脚本,还有其他想法吗?

【问题讨论】:

标签: git directory repository git-config


【解决方案1】:

基于https://stackoverflow.com/a/44036640/2377961,我想我找到了一种可行的方法。

首先,您为“自定义范围”(例如专业、空闲时间等)创建不同的配置文件,并为每个范围添加所需的用户配置

# ~/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,例如"c:/freetime/my-freetime.domain/.git"

【讨论】:

  • 注意,你可以在“~/.gitconfig”中设置默认值:后面的值将覆盖文件中的早期值(至少在当前的Git实现中),所以“all-proects.gitconfig” " 是多余的
  • @Epic 你是对的,在我的示例中,可以将所有项目配置中的值添加到用户 .gitconfig 中。但是如果不止一个用户喜欢使用这个项目配置,那就太疯狂了(例如,如果 all-project 不包含“user.email”而是其他值,例如 textconv-Rules 等。
【解决方案2】:

我提出的解决方案灵感来自Scott Weldon's answer。由于它不直接适用于我的情况,我修改了钩子的 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 中,我存储了该目录()的配置,该配置应应用于其中的所有存储库及其子目录。

cd ~/MyDomain
git config --file .gitconfig user.name "My Name"
git config --file .gitconfig user.email "my@email.com"

有趣的部分是post-checkout bash 脚本,它定义了结帐后挂钩。我使用自定义user.inferredConfig 标志只执行一次(在git clone),而不是重复执行(在git checkout)。当然也可以创建一个单独的文件来表示该状态。

#!/bin/bash

# Git post-checkout hook for automated use of directory-local git config
# https://stackoverflow.com/a/40450106

# 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

*:对原代码的改动包括:

  1. 适用于路径中的空格(在 Windows 上尤其有趣)
  2. 正确解析来自.gitconfig 的键值对(don't read lines with foriterate with while read instead
  3. 检查.gitconfig 文件从根目录到本地目录,反之亦然
  4. 仅在初始克隆时调用挂钩,而不是在每次结帐时调用
  5. 输出应用于git clone 的配置设置

【讨论】:

    【解决方案3】:

    作为一个简单的解决方案,使用autoenv 之类的东西(对不起,自我宣传)使用环境变量设置您的邮件地址:

    echo 'export GIT_AUTHOR_NAME="Your name"' > professional/.env
    echo 'export GIT_AUTHOR_EMAIL="you@example.com"' >> professional/.env
    cd professional
    

    【讨论】:

    • 感谢您的提示。在这里,我想使用不需要外部工具的解决方案,但 autoenv 看起来在其他地方可能有用:)
    • autoenv 和 direnv 看起来很有趣!但是他们不是只在shell中工作吗?如果我使用 GUI git 客户端怎么办?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 2023-01-13
    • 2010-09-30
    • 2012-07-08
    相关资源
    最近更新 更多