如何在.gitconfig中引用其他配置值

时间:2019-01-15 01:32:06

标签: bash git git-config

TL; DR

如何在另一个配置值中引用一个.gitconfig配置值?

.gitconfig

[filter "myFilter"]
    foo = Hello world
    bar = echo $(git config filter.myFilter.foo)

重击

$(git config filter.myFilter.bar)
# should print "Hello world"

我的问题

我正在尝试编写一些smudge / clean过滤器(例如latest commit),以便在签出时将tabsize设置为4个空格,并在提交时将其还原到仓库中已有的内容。

SO答案表明:

  
git config --global filter.tabspace.smudge 'unexpand --tabs=4'
git config --global filter.tabspace.clean 'expand --tabs=4'

或等效的.gitconfig文件:

[filter "tabspace"]
    smudge = 'unexpand --tabs=4'
    clean = 'expand --tabs=4'

如果您知道所有远程回购都使用选项卡,则此方法很好。我想对此进行概括(并在此过程中,进一步了解git config),以便我可以设置一个值,而~/.gitconfig中的值将完成其余工作。


期望的行为

我的~/.gitconfig看起来像

#...

[filter "tabspace"]
    repoTabs = false
    repoTabSize = 4
    smudge = # TODO
    clean = # TODO

#...

当我克隆一个使用制表符或非4个空格的仓库时,我会运行

# for repos that use tabs
git config filter.tabspace.repoTabs true

# for repos that use 2 spaces
git config filter.tabspace.repoTabSize 2

,然后在.git/info/attributes创建一个看起来像

的文件
*.js    filter=tabspace
*.jsx   filter=tabspace
*.ts    filter=tabspace
*.tsx   filter=tabspace
*.json  filter=tabspace

部分解决方案

我要用于smudgeclean的脚本应该相对简单一些(我在~/.gitconfig文件中将它们分别写成一行,代替了两者) # TODO s)

# smudge
if [ `#filter.tabspace.repoTabs` == true ]; then
    expand --tabs=4
else
    unexpand --tabs=`#filter.tabspace.repoTabSize` | expand --tabs=4
fi

# clean
if [ `#filter.tabspace.repoTabs` == true ]; then
    unexpand --tabs=4
else
    unexpand --tabs=4 | expand --tabs=`#filter.tabspace.repoTabSize`
fi

我一生无法弄清的是如何在脚本中使用filter.tabspace.repoTabsfilter.tabspace.repoTabSize的值。

我的测试方法是设置smudge = #my-script-here,然后运行

$(git config filter.tabspace.smudge)

其中#my-script-here就像echo $(git config filter.tabspace.repoTabSize)一样,尝试了多次以单引号,双引号,转义双引号和反引号代替$()来包围值的各个部分。我尝试过的所有操作都会对$(git config filter.tabspace.repoTabSize)进行字面评估,或者会完全失败。

我也尝试过简单地使用repoTabSize,希望它只是插入作用域变量,但是没有这种运气。


作为健全性检查:

git config filter.tabspace.repoTabSize 2
echo $(git config filter.tabspace.repoTabSize)

# prints
2

我还检查了将值传递到if语句中是否满足我的需要,假设git checkoutgit commit通过filter.tabspace.smudge的值通过管道传递文件和filter.tabspace.clean

echo -e '\t'foo | if [ true ]; then expand --tabs=4; fi

# prints (with 4 spaces):
    foo

2 个答案:

答案 0 :(得分:0)

这是非常冗长的,所以我仍然想要一个更好的答案,但是使用eval和一些转义的双引号可以实现我想要的。

在我的部分解决方案脚本中,我需要替换:

`#filter.tabspace.repoTabs` -> $(eval "git config filter.tabspace.repoTabs")
`#filter.tabspace.repoTabSize` -> $(eval "git config filter.tabspace.repoTabSize")

然后,我需要将值包装在双引号中-这也意味着在eval表达式中转义双引号。

最终结果:

[filter "tabspace"]
    repoTabs = false
    repoTabSize = 4
    smudge = "if [ $(eval \"git config filter.tabspace.repoTabs\") == true ]; then expand --tabs=4; else unexpand --tabs=$(eval \"git config filter.tabspace.repoTabSize\") | expand --tabs=4; fi"
    clean = "if [ $(eval \"git config filter.tabspace.repoTabs\") == true ]; then unexpand --tabs=4; else unexpand --tabs=4 | expand --tabs=$(eval \"git config filter.tabspace.repoTabSize\"); fi"

顺便说一句,所引用的SO问题的答案并没有提供强制运行污迹的好方法。 This answer更好。

警告:如果您有未提交的文件,请不要这样做。

rm .git/index
git checkout HEAD -- "$(git rev-parse --show-toplevel)"

答案 1 :(得分:0)

这是比其他任何事情都更重要的shell编程问题。

请注意,git config --get会给您返回退出代码以告诉您是否设置了某些内容:

$ git config --get branch.master.merge; echo $?
refs/heads/master
0
$ git config --get branch.master.marge; echo $?
1

您可以添加--default <value>,但这会使退出代码无效:

$ git config --get --default simpson branch.master.marge; echo $?
simpson
0

还有git config --get -t <type> <name>,它根据提供的类型将实际设置转换为适当的值并产生该值,或产生错误(至stderr)并以失败退出并退出:

$ git config --get -t bool core.bare; echo $?
false
0
$ git config --get -t bool branch.master.merge; echo $?
fatal: bad numeric config value 'refs/heads/master' for 'branch.master.merge' in file .git/config: invalid unit
128

因此,在shell脚本中,您可以简单地测试是否根据您的决定来设置值,或者在尝试时使用单独的布尔值:

#! /bin/sh
do_tabs=$(git config --get -t bool --default false filter.tabspace.repotabs) || exit
if $do_tabs; then
    tabsize=$(git config --get -t int --default 8 filter.tabspace.repotabsize) || exit
fi

或:

#! /bin/sh
tabsize=$(git config --get -t int filter.tabspace.size)
case $? in
0) do_tabs=true;;
1) do_tabs=false;;
*) exit;;
esac

现在,无论哪种方式,您都有两个变量可以捕获期望值(“我们应该做这个制表符吗?”)和(如果是$ do_tabs)实际大小,因此现在您可以编写:

case "#1" in)
--smudge) is_smudge=true;;
--clean) is_smudge=false;;
*) echo "run with --smudge or --clean"; exit 1;;
esac

if $is_smudge; then
    if $do_tabs; then
        expand --$tabsize
    fi
else
    ...
fi

(以明显的方式填写其余部分)。生成的脚本可以通过以下方式调用:

[filter "tabspace"]
    smudge = script_name --smudge
    clean = script_name --clean

参数($1)确定操作模式,这两个设置来自配置文件,脚本根据需要读取stdin并写入stdout。

不过,我没有尝试再现您的完整代码,因为这里有些奇怪的事情:

  

unexpand --tabs = 4 |展开--tabs = [此处为任何数字]

unexpand程序将适当地用制表符替换前导空格,四个空格变成一个制表符,8变成2,依此类推; expand随后将替换为一定数量的空格。如果--tabs=的数字也为4,那么整个事情就不算大了。但是,如果--tabs=不同,则会使用仅空间文件(这似乎是您在所有工作树文件中所期望的文件),并在它们出现时更改个数是领先的空间。这似乎很奇怪。以系统其余部分通常期望的方式在每8个位置将硬标签放入文件中是否更有意义?如果是这样,则所有--unexpand调用都应该没有参数,并且--expand也不能带有参数,因为工作树中的文件始终只包含空格。