将.git/hooks放入项目存储库(例如,使用符号链接)被认为是一种糟糕的做法吗?如果是,将相同的钩子传递给不同的Git用户的最佳方式是什么?
当前回答
我基本上同意Scy的观点,还有一些额外的建议,足以让它值得一个单独的答案。
首先,您应该编写一个脚本来创建适当的符号链接,特别是当这些钩子是关于执行策略或创建有用的通知时。如果人们只需要输入bin/create-hook-symlinks,而不是自己动手,他们就更有可能使用这些hook。
其次,直接符号链接钩子可以防止用户添加自己的个人钩子。例如,我非常喜欢预提交钩子样本,它可以确保我没有任何空白错误。解决这个问题的一个好方法是在存储库中放入钩子包装器脚本,并将所有钩子符号链接到它。
然后包装器可以检查$0(假设它是一个Bash脚本;类似于argv[0],否则)来找出它被调用为哪个钩子,然后在存储库中调用适当的钩子,以及适当的用户钩子,这将不得不重命名,并将所有参数传递给每个钩子。简单的例子:
#!/bin/bash
if [ -x $0.local ]; then
$0.local "$@" || exit $?
fi
if [ -x tracked_hooks/$(basename $0) ]; then
tracked_hooks/$(basename $0) "$@" || exit $?
fi
安装脚本会将所有已经存在的钩子移到一边(在它们的名称后面附加.local),并将所有已知的钩子名称符号链接到上面的脚本:
#!/bin/bash
HOOK_NAMES="applypatch-msg pre-applypatch post-applypatch pre-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-receive update post-receive post-update pre-auto-gc"
# assuming the script is in a bin directory, one level into the repo
HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks
for hook in $HOOK_NAMES; do
# If the hook already exists, is executable, and is not a symlink
if [ ! -h $HOOK_DIR/$hook -a -x $HOOK_DIR/$hook ]; then
mv $HOOK_DIR/$hook $HOOK_DIR/$hook.local
fi
# create the symlink, overwriting the file if it exists
# probably the only way this would happen is if you're using an old version of git
# -- back when the sample hooks were not executable, instead of being named ____.sample
ln -s -f ../../bin/hooks-wrapper $HOOK_DIR/$hook
done
其他回答
我基本上同意Scy的观点,还有一些额外的建议,足以让它值得一个单独的答案。
首先,您应该编写一个脚本来创建适当的符号链接,特别是当这些钩子是关于执行策略或创建有用的通知时。如果人们只需要输入bin/create-hook-symlinks,而不是自己动手,他们就更有可能使用这些hook。
其次,直接符号链接钩子可以防止用户添加自己的个人钩子。例如,我非常喜欢预提交钩子样本,它可以确保我没有任何空白错误。解决这个问题的一个好方法是在存储库中放入钩子包装器脚本,并将所有钩子符号链接到它。
然后包装器可以检查$0(假设它是一个Bash脚本;类似于argv[0],否则)来找出它被调用为哪个钩子,然后在存储库中调用适当的钩子,以及适当的用户钩子,这将不得不重命名,并将所有参数传递给每个钩子。简单的例子:
#!/bin/bash
if [ -x $0.local ]; then
$0.local "$@" || exit $?
fi
if [ -x tracked_hooks/$(basename $0) ]; then
tracked_hooks/$(basename $0) "$@" || exit $?
fi
安装脚本会将所有已经存在的钩子移到一边(在它们的名称后面附加.local),并将所有已知的钩子名称符号链接到上面的脚本:
#!/bin/bash
HOOK_NAMES="applypatch-msg pre-applypatch post-applypatch pre-commit prepare-commit-msg commit-msg post-commit pre-rebase post-checkout post-merge pre-receive update post-receive post-update pre-auto-gc"
# assuming the script is in a bin directory, one level into the repo
HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks
for hook in $HOOK_NAMES; do
# If the hook already exists, is executable, and is not a symlink
if [ ! -h $HOOK_DIR/$hook -a -x $HOOK_DIR/$hook ]; then
mv $HOOK_DIR/$hook $HOOK_DIR/$hook.local
fi
# create the symlink, overwriting the file if it exists
# probably the only way this would happen is if you're using an old version of git
# -- back when the sample hooks were not executable, instead of being named ____.sample
ln -s -f ../../bin/hooks-wrapper $HOOK_DIR/$hook
done
预提交npm包很好地处理了这个问题,允许你在包中指定预提交钩子。json文件。
这里有一个脚本add-git-hook.sh,您可以在存储库中作为常规文件发布它,并可以执行它来将Git钩子附加到脚本文件中。调整使用哪个钩子(pre-commit, post-commit, pre-push,等等),并在cat中定义钩子。
#!/usr/bin/bash
# Adds the git-hook described below. Appends to the hook file
# if it already exists or creates the file if it does not.
# Note: CWD must be inside target repository
HOOK_DIR=$(git rev-parse --show-toplevel)/.git/hooks
HOOK_FILE="$HOOK_DIR"/post-commit
# Create script file if doesn't exist
if [ ! -e "$HOOK_FILE" ] ; then
echo '#!/usr/bin/bash' >> "$HOOK_FILE"
chmod 700 "$HOOK_FILE"
fi
# Append hook code into script
cat >> "$HOOK_FILE" <<EOF
########################################
# ... post-commit hook script here ... #
########################################
EOF
该脚本具有可执行权限或者用户可以直接运行它。我使用它在提交后自动在其他机器上进行git-pull。
我回答了一个更简单的问题,这个问题不是他们问的,也不是OP想要的。在下面的评论中,我对在存储库中交付钩子脚本与在外部管理它们的用例和参数发表了看法。
看起来很多帖子都过时了,至少如果你在python生态系统中使用预提交(+我发现在稍微旧版本的git中更改git钩子路径会失败,例如2.3)。使用.pre-commit-config。Yaml在你的repo根目录的hooks目录下,最简单的解决方案是运行:
pre-commit install -f --config hooks/.pre-commit-config.yaml
对于基于PHP composer的PHP项目,您可以自动分发给工程师。下面是一个pre-commit和commit-msg钩子的例子。
创建一个hooks文件夹,然后在你的作曲家。json文件:
},
"scripts": {
"post-install-cmd": [
"cp -r 'hooks/' '.git/hooks/'",
"php -r \"copy('hooks/pre-commit', '.git/hooks/pre-commit');\"",
"php -r \"copy('hooks/commit-msg', '.git/hooks/commit-msg');\"",
"php -r \"chmod('.git/hooks/pre-commit', 0777);\"",
"php -r \"chmod('.git/hooks/commit-msg', 0777);\"",
],
然后你甚至可以在项目继续时更新它们,因为每个人都在定期运行composer安装。
推荐文章
- Visual Studio代码如何解决合并冲突与git?
- 无法推送到远程分支,无法解析到分支
- Git:如何将数据库重置为特定的提交?
- 如何在合并期间使用Git和命令行保存本地文件或远程文件?
- 能够用一个命令推到所有git遥控器?
- 重新基于Git合并提交
- 忽略已经签入目录的内容?
- 如何从windows cmd保存git提交消息?
- (Mac) -bash: __git_ps1:命令未找到
- 如何删除多个已删除的文件在Git仓库
- 使用vimdiff查看所有' git diff '
- 如何拉特定的目录与git
- 本地存储库中的文件与源文件之间的差异
- 将Git存储库内容移动到另一个存储库,保存历史记录
- 如何在GitHub上创建自己的存储库?