Git预提交钩子(pre-commit hook):防止提交更改特定文件。

5

我在项目中有几个 .json 文件,其中包含多个键(key)。这些键不应该被版本控制所记录。为了避免在持续集成过程中出现构建失败的情况,我用虚假的键替换了这些实际键。

然而,开发人员需要在测试应用程序之前将这些文件复制/粘贴到他们的笔记本电脑上。

现在的问题是,开发人员可能会忘记并错误地将它们提交到 git 中。我想运行一个 pre-commit 脚本,检查修改后的文件,并在其中添加一个文件时取消提交操作。

有没有办法可以做到这一点呢?

2个回答

9

通过使用 pre-commit 钩子,在开发者端防止此类问题的出现。请注意,git commit --no-verify 将绕过此安全机制。

下面的代码会禁止对文件 dir/key1.jsonkey2.json 进行任何更改。

#!/bin/sh

# full paths from the repo root separated by newlines
MUST_NOT_CHANGE='dir/key1.json
key2.json'

if git rev-parse --verify HEAD >/dev/null 2>&1
then
  against=HEAD
else
  # Initial commit: diff against an empty tree object
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

exec 1>&2

if git diff --cached --name-only $against |
   grep --quiet --line-regexp --fixed-strings "$MUST_NOT_CHANGE"
then
  echo Commit would modify one or more files that must not change.
  exit 1
else
  exit 0
fi

下面的 pre-receive 钩子必须安装在你的中央仓库上,它会拒绝任何试图修改受保护文件的推送。
#!/bin/sh

# full paths from the repo root separated by newlines
MUST_NOT_CHANGE='dir/key1.json
key2.json'

z40=0000000000000000000000000000000000000000

while read old_value new_value ref_name
do
  if [ "$old_value" = $z40 ]; then
    # New branch: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
  else
    against=$old_value
  fi

  if git diff --name-only $against..$new_value |
     grep --quiet --line-regexp --fixed-strings "$MUST_NOT_CHANGE"
  then
    echo "$ref_name" may commit key, rejected ... >&2
    exit 1
  fi
done

实际应用中:

$ git push origin master
Counting objects: 10, done.
Delta compression using up to 40 threads.
Compressing objects: 100% (6/6), done.
Writing objects: 100% (10/10), 820 bytes | 410.00 KiB/s, done.
Total 10 (delta 1), reused 0 (delta 0)
remote: refs/heads/master may commit key, rejected ...
To '<URL>'
 ! [remote rejected] master -> master (pre-receive hook declined)
error: failed to push some refs to '<URL>'

哇,太棒了Greg。谢谢你给我所有的细节。只有一个问题,第一个块中的against和第二个块中的z40是什么?应该硬编码还是以某种方式检索? - Hesam
1
使用 against 处理分支尚不存在的情况,但 git diff 需要 某些东西 以进行差异比较。pre-receive 的 githooks 文档解释了由四十个零组成的虚拟 SHA1 表示该引用尚不存在。 - Greg Bacon

2

啊,太棒了。我会测试一下。谢谢你的指导。 - Hesam
请注意,开发人员仍然可以使用no-verify绕过此设置。如果您想绝对确保他们无法提交更改,那么您需要一个服务器端的pre-receive hook。 - g_bor
我认为你可以通过否定整个表达式,也可以用!git diff --cached --name-only | grep -qE $FILES_PATTERNgit diff检查压缩成一行。 - ahong

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接