检查为 git 提交暂存的任何文件是否与白名单不匹配
Checking whether any file staged for git commit does not match a whitelist
由于自动提交和推送的脚本存在一些问题,我想实现一个白名单。
计划是,只允许在路径中使用 'foo' 和 'bar' 模式提交。
#!/bin/sh
WHITELIST="foo bar"
WRKDIR=/home/athur/workwork/test/repo
cd $WRKDIR
git add -A
for file in `git diff --cached -p --name-status | cut -c3-`; do
if [[ "$file" == *"$WHITELIST"* ]] ; then
echo "$file is on whitelist"
else
echo "$file is not on whitelist. Commit aborted."
exit 1
fi
done
问题是,它总是使用 'else' 子句。
我找不到问题所在。谢谢
使用显式列表
这里的==
不是对称的,**
好像用错了。
尝试"$WHITELIST" == *"$file"*
。
(灵感来自 How do I check if a variable exists in a list in BASH)
请注意,使用您的 WHITELIST
,只有文件 foo
和 bar
会被列入白名单。
正在检测模式
如果您需要检测单个模式,您可能需要构造一个函数,例如:
for entry in $WHITELIST ; do
if [[ "$file" =~ $entry ]] ; then
return 0
fi
done
return 1
作为最佳实践方法,请考虑:
#!/usr/bin/env bash
# ^^^^ important: [[ ]] is not guaranteed to work with bin/sh
whitelist_re='(foo|bar)'
workdir=/home/athur/workwork/test/repo
cd -- "$workdir" || exit
git add -A
while IFS= read -r filename; do
if [[ $file =~ $whitelist ]]; then
echo "$file is on whitelist" >&2
else
echo "$file is not on whitelist; commit aborted." >&2
exit 1
fi
done < <(git diff --cached --name-only)
浏览更改:
- shebang 将
bash
指定为 shell,这保证了像 [[ ]]
和 <(...)
这样的扩展将可用——[=15 无法保证=].
- 使用
while read
循环而不是尝试使用 for
迭代面向行的数据;有关此更改背后原因的解释,请参阅 DontReadLinesWithFor。
- 白名单被指定为符合ERE的正则表达式,这样
=~
可以用来测试一个值是否匹配
- 我们不是使用
git diff --cached --name-status
然后使用 cut
删除事后状态数据,而是使用 --name-only
首先只生成名称。
- 使用小写变量名称符合 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html 中给出的约定,指定 POSIX 定义的工具将使用全大写 shell 和环境变量名称用于它们自己的目的,至少包含一个小写字符的名称保留供应用程序使用。 (请记住,设置 shell 变量会覆盖任何类似名称的环境变量,因此即使未使用
export
,这些约定也适用)。
顺便说一句,如果您只是想查明是否存在任何不匹配项,而不知道这些文件是哪些,您可以使用:
#!/bin/sh
# ^^ actually safe here, as no non-POSIX functionality is used
whitelist_re='foo|bar'
if git diff --cached --name-only | grep -qEv "$whitelist_re"; then
echo "At least one file is not on whitelist; commit aborted" >&2
exit 1
fi
由于自动提交和推送的脚本存在一些问题,我想实现一个白名单。
计划是,只允许在路径中使用 'foo' 和 'bar' 模式提交。
#!/bin/sh
WHITELIST="foo bar"
WRKDIR=/home/athur/workwork/test/repo
cd $WRKDIR
git add -A
for file in `git diff --cached -p --name-status | cut -c3-`; do
if [[ "$file" == *"$WHITELIST"* ]] ; then
echo "$file is on whitelist"
else
echo "$file is not on whitelist. Commit aborted."
exit 1
fi
done
问题是,它总是使用 'else' 子句。 我找不到问题所在。谢谢
使用显式列表
这里的==
不是对称的,**
好像用错了。
尝试"$WHITELIST" == *"$file"*
。
(灵感来自 How do I check if a variable exists in a list in BASH)
请注意,使用您的 WHITELIST
,只有文件 foo
和 bar
会被列入白名单。
正在检测模式
如果您需要检测单个模式,您可能需要构造一个函数,例如:
for entry in $WHITELIST ; do
if [[ "$file" =~ $entry ]] ; then
return 0
fi
done
return 1
作为最佳实践方法,请考虑:
#!/usr/bin/env bash
# ^^^^ important: [[ ]] is not guaranteed to work with bin/sh
whitelist_re='(foo|bar)'
workdir=/home/athur/workwork/test/repo
cd -- "$workdir" || exit
git add -A
while IFS= read -r filename; do
if [[ $file =~ $whitelist ]]; then
echo "$file is on whitelist" >&2
else
echo "$file is not on whitelist; commit aborted." >&2
exit 1
fi
done < <(git diff --cached --name-only)
浏览更改:
- shebang 将
bash
指定为 shell,这保证了像[[ ]]
和<(...)
这样的扩展将可用——[=15 无法保证=]. - 使用
while read
循环而不是尝试使用for
迭代面向行的数据;有关此更改背后原因的解释,请参阅 DontReadLinesWithFor。 - 白名单被指定为符合ERE的正则表达式,这样
=~
可以用来测试一个值是否匹配 - 我们不是使用
git diff --cached --name-status
然后使用cut
删除事后状态数据,而是使用--name-only
首先只生成名称。 - 使用小写变量名称符合 http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html 中给出的约定,指定 POSIX 定义的工具将使用全大写 shell 和环境变量名称用于它们自己的目的,至少包含一个小写字符的名称保留供应用程序使用。 (请记住,设置 shell 变量会覆盖任何类似名称的环境变量,因此即使未使用
export
,这些约定也适用)。
顺便说一句,如果您只是想查明是否存在任何不匹配项,而不知道这些文件是哪些,您可以使用:
#!/bin/sh
# ^^ actually safe here, as no non-POSIX functionality is used
whitelist_re='foo|bar'
if git diff --cached --name-only | grep -qEv "$whitelist_re"; then
echo "At least one file is not on whitelist; commit aborted" >&2
exit 1
fi