检查为 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,只有文件 foobar 会被列入白名单。

正在检测模式

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

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