有(某种)一种方法可以做到这一点。我不会,但如果你真的想这样做,请按照这些思路进行。
首先,您需要将现有的两个项目分开:
此外,您希望第一组可用于重新格式化。
这可以通过 git stash 完成,正如我在对 How do I properly git stash/pop in pre-commit hooks to get a clean working tree for tests? 的回答中所展示的那样(不过,请参阅那里关于 git stash 中的错误的警告)。
基本上,您希望到达脚本中运行测试的位置:
# Run tests
status=...
一旦处于这种状态,您可以通过格式化程序运行工作树项目,git add 将结果放入预提交挂钩中(正如您已经发现的那样)。这将避免格式化“另一个”块,因为它不在工作目录版本中。然后,您可以让提交继续进行(即,脚本的其余部分不适用于此处)。
现在的问题是从存储中恢复工作树版本。因为您修改了索引,所以即使在提交完成后也无法返回:
# Restore changes
git reset --hard -q && git stash apply --index -q && git stash drop -q
相反,您想要找到隐藏索引 (stash^1) 和隐藏工作树 (stash) 之间的差异,并将其应用于新的 HEAD 提交。在不使用 git 管道命令的情况下,至少有两种方法可以做到这一点。由于重新格式化提交的版本,两者都可能导致冲突:
-
git diff stash^1 stash | git apply --reject(最终是git stash drop)
git stash branch tempbranch; git commit -m for-cherry-pick; git checkout prev-branch; git cherry-pick -n tempbranch; git branch -D tempbranch
方法 1 更简单但很混乱,因为会导致合并冲突的更改会被放入“拒绝”文件中。方法 2 使用合并机制,因此如果需要,更改会获得冲突标记。 (如果没有冲突,-n 会阻止提交,这样您就可以自己处理真实的消息,而不是复制虚拟的 for-cherry-pick 消息。)
当然,我还没有测试过这些。此外,还有一些方法可以在不使用git stash 的情况下执行此操作,例如将git add-ed 文件的索引版本检出到单独的目录中,在那里格式化内容,然后将格式化的版本添加回来,这样就没有此过程会影响当前工作目录。无论如何,如果您真的决心这样做,这可能会更好。这是 that 方法的脚本(也没有经过真正的测试——它需要添加一些健壮性,可能使用 -z 和 xargs -0 来处理包含空格的文件名,在 diff 的检出中-index 输出部分):
# make a directory for formatting files
WORKDIR=$(mktemp -d -t reformat) || exit 1
# clean it up when we leave
trap "rm -rf $WORKDIR 0 1 2 3 15"
# for files Added or Modified in the index, copy them to $WORKDIR
git --work-tree=$WORKDIR checkout -- \
$(git diff-index --cached --name-only --no-renames --diff-filter=AM HEAD)
# reformat files in the work-dir
(cd $WORKDIR; ...)
# for each file in the work-dir, re-"add" that version to this tree
# (this assumes the reformatter did not leave extraneous files!)
git --work-tree=$WORKDIR add --ignore-removal .
这是我的建议:与其在预提交挂钩中格式化代码,只需检查 它是否 已格式化。如果是这样,则允许提交。如果不是,拒绝它。这更符合预提交钩子的精神,它允许使用that other answer 中的脚本。基本上,在它说:
status=...
您只需运行一些东西来检查格式化程序是否会改变任何东西(也许通过允许格式化程序做它的事情,并查看结果是否与要提交的索引中的不同)。这让你得到你的地位。然后您执行脚本中的其余内容,使用 git reset --hard -q && git stash apply --index -q && git stash drop -q 将所有内容恢复到创建存储时的状态。