检查是否为git commit暂存的任何文件与白名单都不匹配

时间:2018-06-27 13:43:58

标签: bash git shell 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'子句。 我找不到问题。谢谢

2 个答案:

答案 0 :(得分: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指定为外壳,这保证了[[ ]]<(...)之类的扩展名将可用-这是/bin/sh所没有的保证。
  • 使用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和环境变量名称用于自己的目的,并且至少使用一个小写字符的名称是保留供应用程序使用。 (请记住,设置外壳程序变量会覆盖任何同名的环境变量,因此即使不使用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

答案 1 :(得分:0)

使用明确列表

在这种情况下,==不是对称的,**似乎使用不当。

尝试"$WHITELIST" == *"$file"*

(受How do I check if a variable exists in a list in BASH启发)

请注意,使用您的WHITELIST,只会将文件foobar列入白名单。

检测图案

如果需要检测单个模式,则可能需要构造一个函数,例如:

for entry in $WHITELIST ; do 
  if [[ "$file" =~ $entry ]] ; then
    return 0
  fi
done
return 1