如何在Git预提交钩子中创建临时干净工作区运行单元测试?
需求与问题
我希望预提交钩子中的单元测试能在忘记暂存单元测试所需的修改或文件时失败,但Git忽略的文件/文件夹(比如Node.js项目里的node_modules目录)除外。看起来git stash可以帮我创建这种临时状态,同时测试后必须能完全恢复到原有状态。
为了明确想要的具体行为,我编写了如下bash脚本:
#!/bin/bash mkdir temporary-repo && cd temporary-repo || exit 1 git init > /dev/null 2>&1 printf '%s' "0" > ignored printf '%s' "ignored" > .gitignore printf '%s' "0" > modified-staged printf '%s' "0" > modified-unstaged printf '%s' "0" > modified-unstaged-undo printf '%s' "0" > modified-unstaged-update git add . && git commit -m "Initial commit" > /dev/null 2>&1 printf '%s' "1" > new-staged printf '%s' "1" > modified-staged printf '%s' "1" > new-unstaged-undo printf '%s' "1" > new-unstaged-update printf '%s' "1" > modified-unstaged-undo printf '%s' "1" > modified-unstaged-update git add . printf '%s' "0" > new-unstaged-undo printf '%s' "0" > modified-unstaged-undo printf '%s' "1" > new-unstaged printf '%s' "1" > modified-unstaged printf '%s' "2" > new-unstaged-update printf '%s' "2" > modified-unstaged-update before="$(git status)" ##################### # CREATE STASH HERE # ##################### echo "--- Created stash ---" test "1" = "$(cat new-unstaged-undo)" || echo "ERR: new-unstaged-undo != 1" test "1" = "$(cat modified-unstaged-undo)" || echo "ERR: modified-unstaged-undo != 1" test "1" = "$(cat new-staged)" || echo "ERR: new-staged != 1" test "1" = "$(cat modified-staged)" || echo "ERR: modified-staged != 1" test -f new-unstaged && echo "ERR: new-unstaged should not exist" test "0" = "$(cat modified-unstaged)" || echo "ERR: modified-unstaged != 0" test "1" = "$(cat new-unstaged-update)" || echo "ERR: new-unstaged-update != 1" test "1" = "$(cat modified-unstaged-update)" || echo "ERR: modified-unstaged-update != 1" test "0" = "$(cat ignored)" || echo "ERR: ignored != 0" ################## # POP STASH HERE # ################## echo "--- Popped stash ---" test "0" = "$(cat new-unstaged-undo)" || echo "ERR: new-unstaged-undo != 0" test "0" = "$(cat modified-unstaged-undo)" || echo "ERR: modified-unstaged-undo != 0" test "1" = "$(cat new-staged)" || echo "ERR: new-staged != 1" test "1" = "$(cat modified-staged)" || echo "ERR: modified-staged != 1" test "1" = "$(cat new-unstaged)" || echo "ERR: new-unstaged != 1" test "1" = "$(cat modified-unstaged)" || echo "ERR: modified-unstaged != 1" test "2" = "$(cat new-unstaged-update)" || echo "ERR: new-unstaged-update != 2" test "2" = "$(cat modified-unstaged-update)" || echo "ERR: modified-unstaged-update != 2" test "0" = "$(cat ignored)" || echo "ERR: ignored != 0" after="$(git status)" diff -y <(echo "$before") <(echo "$after") cd .. && rm -rf temporary-repo
尝试1
# Create stash git stash -k -u # Pop stash git stash pop
失败测试输出:
--- Created stash --- --- Popped stash --- ERR: new-unstaged-undo != 0 ERR: modified-unstaged-undo != 0 ERR: new-unstaged-update != 2 ERR: modified-unstaged-update != 2 On branch master On branch master Changes to be committed: Changes to be committed: (use "git restore --staged <file>..." to unstage) (use "git restore --staged <file>..." to unstage) modified: modified-staged modified: modified-staged > modified: modified-unstaged modified: modified-unstaged-undo modified: modified-unstaged-undo modified: modified-unstaged-update < new file: new-staged new file: new-staged new file: new-unstaged-undo < new file: new-unstaged-update < Changes not staged for commit: | Unmerged paths: (use "git add <file>..." to update what will be committed) | (use "git restore --staged <file>..." to unstage) (use "git restore <file>..." to discard changes in working | (use "git add <file>..." to mark resolution) modified: modified-unstaged | both modified: modified-unstaged-update modified: modified-unstaged-undo | both added: new-unstaged-undo modified: modified-unstaged-update | both added: new-unstaged-update modified: new-unstaged-undo < modified: new-unstaged-update < Untracked files: Untracked files: (use "git add <file>..." to include in what will be committ (use "git add <file>..." to include in what will be committ new-unstaged new-unstaged
尝试2
# Create stash stash=$(git stash create -q) git stash store "$stash" git stash show -p | git apply --reverse git diff --cached | git apply # Pop stash git reset --hard -q git stash apply --index -q git stash drop -q
失败测试输出:
--- Created stash --- ERR: new-unstaged should not exist --- Popped stash --- On branch master On branch master Changes to be committed: Changes to be committed: (use "git restore --staged <file>..." to unstage) (use "git restore --staged <file>..." to unstage) modified: modified-staged modified: modified-staged modified: modified-unstaged-undo modified: modified-unstaged-undo modified: modified-unstaged-update modified: modified-unstaged-update new file: new-staged new file: new-staged new file: new-unstaged-undo new file: new-unstaged-undo new file: new-unstaged-update new file: new-unstaged-update Changes not staged for commit: Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git add <file>..." to update what will be committed) (use "git restore <file>..." to discard changes in working (use "git restore <file>..." to discard changes in working modified: modified-unstaged modified: modified-unstaged modified: modified-unstaged-undo modified: modified-unstaged-undo modified: modified-unstaged-update modified: modified-unstaged-update modified: new-unstaged-undo modified: new-unstaged-undo modified: new-unstaged-update modified: new-unstaged-update Untracked files: Untracked files: (use "git add <file>..." to include in what will be committ (use "git add <file>..." to include in what will be committ new-unstaged new-unstaged
尝试1能创建运行单元测试所需的理想状态,但无法恢复到原有状态;尝试2能成功恢复原状态,却无法暂存/移除new-unstaged文件。
请问有没有办法通过Git实现我想要的行为?
内容的提问来源于stack exchange,提问作者Tobias Bergkvist
相关产品推荐
相关产品推荐

