git 预提交挂钩以同时格式化和重新添加文件
git pre-commit hook to format and re-add files at the same time
我们目前正在使用 git 钩子(如下)在我们的源代码上 运行 astyle,然后再允许用户提交。这有一个警告,即用户必须提交,格式化他们的代码,然后再次提交,这有点麻烦。理想情况下,我们希望挂钩格式化代码,然后将格式化的代码包含在原始提交中。我试过重新添加更改的文件,但它会导致引用错误(很明显)。我还尝试在预提交挂钩中获取历史记录并尝试退出挂钩并重新 运行 git 提交命令但没有成功。
# Run astyle on changed .cs files, ignoring $ignored
res=$(exec git diff --cached --name-only | \
grep -Ev $ignored | \
xargs astyle --options=conf/astylerc | \
tail -n 1)
num_formatted=$(echo $res | cut -b 1) # We are only interested in the number preceeding 'formatted'.
[[ $num_formatted -ne 0 ]] && echo "WARNING: Code has been automatically formatted. Please re-add and re-commit" && exit 1 || echo "No code to format! Continuing commit"
有人有什么想法吗?
在你的预提交挂钩中,你需要添加你的文件,所以如果你的挂钩是这样的:
#!/bin/bash
echo 1 > file
exit 0
那么您需要修改它以添加:
#!/bin/bash
echo 1 > file
git add file
exit 0
要获取所有已修改文件的列表,您可以使用 git-ls-files:
git ls-files -m
但是,如果您可以从您的代码中获取修改了哪些文件的列表,或者再次添加所有文件,那就更好了。 git diff-tree -r --name-only --no-commit-id <tree-ish>
应该可以帮助您获取所有文件的列表。
基本上,修改后再次添加文件是可行的,因为直到您的预提交挂钩运行后才会发生提交,因此此时工作树中暂存的任何内容都会被提交。
根据 this 回答编辑。
您可以格式化文件并将其添加回挂钩中。问题是您可能对暂存文件进行了未暂存修改。要以干净的方式执行此操作,您可以从索引中获取文件作为 tmp,格式化 tmp 并使用格式化的 tmp 替换索引中的条目。这是应该解决问题的方法:
# Regexp for grep to only choose some file extensions for formatting
exts="\.\(ext\|ext2\)$"
# The formatter to use
formatter=`which your_formatter`
# Check availability of the formatter
if [ -z "$formatter" ]
then
1>&2 echo "$formatter not found. Pre-commit formatting will not be done."
exit 0
fi
# Format staged files
for file in `git diff --cached --name-only --diff-filter=ACMR | grep $exts`
do
echo "Formatting $file"
# Get the file from index
git show ":$file" > "$file.tmp"
# Format it
"$formatter" -i "$file.tmp"
# Create a blob object from the formatted file
hash=`git hash-object -w "$file.tmp"`
# Add it back to index
git update-index --add --cacheinfo 100644 "$hash" "$file"
# Remove the tmp file
rm "$file.tmp"
done
# If no files left in index after formatting - fail
ret=0
if [ ! "`git diff --cached --name-only`" ]; then
1>&2 echo "No files left after formatting"
exit 1
fi
您可以使用 here. Then run the formatter on just the staged changes and pop the stash. Below pre-commit
hook uses clang-format-diff
中描述的技术仅存储未暂存的更改
#!/bin/sh
# stash unstaged changes
git commit --no-verify -m 'Save index'
old_stash=$(git rev-parse -q --verify refs/stash)
git stash push -m 'Unstaged changes'
new_stash=$(git rev-parse -q --verify refs/stash)
git reset --soft HEAD^
# format staged changes
git diff -U0 --no-color --staged HEAD -- '*.java' | $PWD/clang-format-diff.py -i -p1
git add -u
if [ "$old_stash" != "$new_stash" ]; then # if unstaged changes were stashed reapply to working tree
git stash pop
fi
exit 0
我们目前正在使用 git 钩子(如下)在我们的源代码上 运行 astyle,然后再允许用户提交。这有一个警告,即用户必须提交,格式化他们的代码,然后再次提交,这有点麻烦。理想情况下,我们希望挂钩格式化代码,然后将格式化的代码包含在原始提交中。我试过重新添加更改的文件,但它会导致引用错误(很明显)。我还尝试在预提交挂钩中获取历史记录并尝试退出挂钩并重新 运行 git 提交命令但没有成功。
# Run astyle on changed .cs files, ignoring $ignored
res=$(exec git diff --cached --name-only | \
grep -Ev $ignored | \
xargs astyle --options=conf/astylerc | \
tail -n 1)
num_formatted=$(echo $res | cut -b 1) # We are only interested in the number preceeding 'formatted'.
[[ $num_formatted -ne 0 ]] && echo "WARNING: Code has been automatically formatted. Please re-add and re-commit" && exit 1 || echo "No code to format! Continuing commit"
有人有什么想法吗?
在你的预提交挂钩中,你需要添加你的文件,所以如果你的挂钩是这样的:
#!/bin/bash
echo 1 > file
exit 0
那么您需要修改它以添加:
#!/bin/bash
echo 1 > file
git add file
exit 0
要获取所有已修改文件的列表,您可以使用 git-ls-files:
git ls-files -m
但是,如果您可以从您的代码中获取修改了哪些文件的列表,或者再次添加所有文件,那就更好了。 git diff-tree -r --name-only --no-commit-id <tree-ish>
应该可以帮助您获取所有文件的列表。
基本上,修改后再次添加文件是可行的,因为直到您的预提交挂钩运行后才会发生提交,因此此时工作树中暂存的任何内容都会被提交。
根据 this 回答编辑。
您可以格式化文件并将其添加回挂钩中。问题是您可能对暂存文件进行了未暂存修改。要以干净的方式执行此操作,您可以从索引中获取文件作为 tmp,格式化 tmp 并使用格式化的 tmp 替换索引中的条目。这是应该解决问题的方法:
# Regexp for grep to only choose some file extensions for formatting
exts="\.\(ext\|ext2\)$"
# The formatter to use
formatter=`which your_formatter`
# Check availability of the formatter
if [ -z "$formatter" ]
then
1>&2 echo "$formatter not found. Pre-commit formatting will not be done."
exit 0
fi
# Format staged files
for file in `git diff --cached --name-only --diff-filter=ACMR | grep $exts`
do
echo "Formatting $file"
# Get the file from index
git show ":$file" > "$file.tmp"
# Format it
"$formatter" -i "$file.tmp"
# Create a blob object from the formatted file
hash=`git hash-object -w "$file.tmp"`
# Add it back to index
git update-index --add --cacheinfo 100644 "$hash" "$file"
# Remove the tmp file
rm "$file.tmp"
done
# If no files left in index after formatting - fail
ret=0
if [ ! "`git diff --cached --name-only`" ]; then
1>&2 echo "No files left after formatting"
exit 1
fi
您可以使用 here. Then run the formatter on just the staged changes and pop the stash. Below pre-commit
hook uses clang-format-diff
#!/bin/sh
# stash unstaged changes
git commit --no-verify -m 'Save index'
old_stash=$(git rev-parse -q --verify refs/stash)
git stash push -m 'Unstaged changes'
new_stash=$(git rev-parse -q --verify refs/stash)
git reset --soft HEAD^
# format staged changes
git diff -U0 --no-color --staged HEAD -- '*.java' | $PWD/clang-format-diff.py -i -p1
git add -u
if [ "$old_stash" != "$new_stash" ]; then # if unstaged changes were stashed reapply to working tree
git stash pop
fi
exit 0