【问题标题】:Checking whether any file staged for git commit does not match a whitelist检查为 git commit 暂存的任何文件是否与白名单不匹配
【发布时间】:2018-06-27 13:43:58
【问题描述】:

由于自动提交和推送的脚本存在一些问题,我想实现一个白名单。

计划是,只允许在路径中使用模式 '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”子句。 我找不到问题。谢谢

【问题讨论】:

  • 如果您在循环中打印出$file 的值,它是否具有您期望的值?
  • 是的。它具有该文件的正确路径。例如。 foo/file1.txt
  • 您正在检查字符串 foo bar 是否包含在您的文件名中。这是您想要的,还是要检查 either foo 或 bar 是否存在?
  • 顺便说一句,如果你想逐行读取git diff 的输出,for 循环是错误的做法;请参阅 DontReadLinesWithFor 和 BashFAQ #1,了解最佳实践替代方案的讨论。
  • @CharlesDuffy 我想测试foo,bar 或两者是否都在文件名中。

标签: bash git shell whitelist


【解决方案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 指定为外壳,这保证了[[ ]] 和&lt;(...) 等扩展可用——/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 和环境变量名用于它们自己的目的,并且具有至少一个小写字符的名称保留用于应用程序使用。 (请记住,设置 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

【讨论】:

    【解决方案2】:

    使用显式列表

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

    试试"$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
    

    【讨论】:

    • 仍然总是在 else 子句中
    • @CharlesDuffy。而已。使用您的解决方案解决了我的问题。谢谢。
    • @qwertbert23,...很高兴听到!由于此答案的作者尚未对其进行修改以接受该建议,因此我将添加自己的答案。
    猜你喜欢
    • 2013-06-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-07
    • 2018-02-28
    • 2019-05-06
    • 2010-10-13
    • 1970-01-01
    • 2022-10-05
    相关资源
    最近更新 更多