【问题标题】:Searching files with pre-commit使用预提交搜索文件
【发布时间】:2014-09-18 00:56:19
【问题描述】:

我正在尝试添加一个 git pre-commit 挂钩,它将检查所有更改的文件和新文件中的 TODO: 文本。

我试过了

#!/bin/sh

. git-sh-setup  # for die 
git-diff-index -p -M --cached HEAD -- | grep '^+' |
grep TODO: && die Blocking commit because string TODO: detected in patch
:

我在类似的问题中看到了,但没有运气。

【问题讨论】:

  • “运气不好”并不是非常有用的诊断信息。如果某些事情没有按您的预期工作,请说明如何它没有 - 例如,它是否输出任何错误消息?
  • 想通了。我已将pre-commit.sample 文件中的内容复制到纯文本文件中,而不仅仅是重命名。感谢@VonC 的帮助
  • @jesusjjf 好的,我已将您的结论包含在答案中以提高知名度。

标签: git terminal grep pre-commit-hook


【解决方案1】:

首先,钩子必须在.git/hook文件夹中,名称为pre-commit(执行权限:chmod +x .git/hooks/pre-commit

OP jesusjjf 确认 in the comments 是问题所在:

我已将 pre-commit.sample 文件中的内容复制到纯文本文件中,而不仅仅是重命名。

其次,这里有一些脚本示例:


You have another example 使用类似的技术,使用git rev-parsegit diff-index,以及empty tree I mentioned before

#!/bin/sh

if git rev-parse --verify HEAD >/dev/null 2>&1; then
    against=HEAD
else
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

for FILE in `git diff-index --name-status $against -- | cut -c3-` ; do
    # Check if the file contains 'debugger'
    if [ "grep 'debugger' $FILE" ]
    then
        echo $FILE ' contains debugger!'
        exit 1
    fi
done
exit 

The comments on this gist提及:

在我的系统上,if [ "grep 'debugger' $FILE" ] 的计算结果始终为 true
将其更改为 if grep -q 'debugger' "$FILE" 可以解决此问题。


more recent example:

#!/bin/bash

# Pre commit hook that prevents FORBIDDEN code from being commited.
# Add unwanted code to the FORBIDDEN array as necessary

FILES_PATTERN='\.(rb|js|coffee)(\..+)?$'
FORBIDDEN=( debugger ruby-debug )

for i in "${FORBIDDEN[@]}"
do
  git diff --cached --name-only| grep ".js" |xargs sed 's/ //g'|grep "ha_mobile.debug=true" && \
        echo 'COMMIT REJECTED Found ha_mobile.debug=true references. Please remove them before commiting' && exit 1

  git diff --cached --name-only | \
        grep -E $FILES_PATTERN | \
        GREP_COLOR='4;5;37;41' xargs grep --color --with-filename -n $i && \
        echo 'COMMIT REJECTED Found'  $i 'references. Please remove them before commiting' && exit 1
done

exit 0

【讨论】:

  • 用禁止文本数组尝试了第二个,但仍然没有运气。我的预提交文件是否必须作为 repo 的一部分提交才能触发?
  • @jesusjjf no:它需要在repo/.git/hooks 文件夹中,称为pre-commit,并且是可执行的。在开头添加一个 echo 以检查它是否已执行。钩子永远不会提交(或不应该:stackoverflow.com/a/3703207/6309)或在 repos 之间共享(推/拉)。
  • @jesusjjf 通过“没有运气”,我假设钩子没有被执行,对吧?你在什么操作系统上?你用的是什么 git 版本?
  • 别忘了:chmod +x .git/hooks/pre-commit
  • @npc 我同意,我已在答案中添加了该步骤以提高可见性。
【解决方案2】:

这个位循环遍历已暂存的文件,是的,但它随后会 greps 整个文件,而不管它的哪些部分已暂存!

   git diff --cached --name-only | \
       grep -E $FILES_PATTERN | \
       echo 'COMMIT REJECTED Found'  $i 'references. Please remove them before commiting' && exit 1

这不好 - 不要测试没有暂存的字符串。

此解决方案测试一个或多个 FORBIDDEN 字符串仅针对暂存的代码,而不是整个文件

预提交

#!/bin/bash

RESTORE='\033[0m'
RED='\033[00;31m'
YELLOW='\033[00;33m'
BLUE='\033[00;34m'

FORBIDDEN=( 'TODO:' 'DO NOT COMMIT' 'console.log' 'die' )
FOUND=''

for j in "${FORBIDDEN[@]}"
do
  for i in `git diff --cached --name-only`
  do

    # the trick is here...use `git show :file` to output what is staged
    # test it against each of the FORBIDDEN strings ($j)

    if echo `git show :$i` | grep -q "$j"; then

      FOUND+="${BLUE}$i ${RED}contains ${RESTORE}\"$j\"${RESTORE}\n"

    fi
  done
done

# if FOUND is not empty, REJECT the COMMIT
# PRINT the results (colorful-like)

if [[ ! -z $FOUND ]]; then
  printf "${YELLOW}COMMIT REJECTED\n"
  printf "$FOUND"
  exit 1
fi

# nothing found? let the commit happen
exit 0

【讨论】:

  • git show 的有趣用法,比我的回答更准确。 +1
猜你喜欢
  • 1970-01-01
  • 2019-03-01
  • 2014-06-29
  • 1970-01-01
  • 2017-09-10
  • 2010-11-26
  • 1970-01-01
  • 2021-11-09
  • 2016-03-31
相关资源
最近更新 更多