如何在某个提交后应用静态分析规则

How to apply static analysis rules after a certain commit

我继承了一个需要大量重构的大型项目。我想添加静态分析方法来关注质量。 因为我不想让它们应用 atm/right ,我想知道如何在 Maven 循环中仅对特定提交后创建的文件应用此类规则(如 pmd、findbugs、checkstyle ...) / 时间戳。

谢谢

我无法解决任何 Maven 方面的问题,但是 "files created after some commit" 的一般概念存在一个相当明显的问题,即:每个 Git 提交都是其自身的完整快照。您将如何判断哪些文件是何时创建的?

血统测试

判断某个提交(通过哈希 ID 或任何其他标识符)是否是某个其他提交的 后代 相对容易:

git merge-base --is-ancestor 8ac9f31 33071ac

告诉您提交图中是否由 8ac9f31 "comes before" 33071ac 标识的提交。对于这种事情,使用标签名称可能是明智的(轻量级或带注释的,从使用的角度来看这并不重要)。假设您将此标记命名为 "enable-static-analysis",并希望测试来自名为 $branch 的分支的某些分支提示提交是否在该点之后:

if git merge-base --is-ancestor enable-static-analysis $branch; then
    ... run static analysis software ...
fi

为了这个特定的目的,测试实际上是 而不是 <,也就是说,如果你用 8ac9f31 8ac9f31 重复它,答案将是 "yes, 8ac9f31 is an ancestor of 8ac9f31. If you need an exclusive less-than property, you can add " 和不等于”,例如:

if git merge-base --is-ancestor enable-static-analysis $branch &&
    [ $(git rev-parse enable-static-analysis) != $(git rev-parse $branch) ]; then

或者,如果标记适用于普通的单亲提交,则在测试中使用它自己的直接祖先(这不太明显但效率更高):

# We do not want to run this on a newly created branch whose
# current commit *is* the static-analysis enablement commit,
# hence the hat suffix:
if git merge-base --is-ancestor enable-static-analysis^ $branch

但这只会让你得到 "commit comes after" 部分,而不是 "files created since" 部分。

快照问题

从根本上说,问题是您无法知道提交 $descendant 中的文件 path/to/file.ext 是否与提交 $ancestor 中的文件 path/to/file.ext 有任何关系。此外,如果 $descendant 中的 path/to/file.ext 通过从 some/other/file.extpath/to/othername.otherext 重命名(有或没有任何修改)到达那里怎么办?

实际上,Git 也没有。默认情况下,Git 为 git diff 目的所做的是 假设 这两个文件是 "same entity" 如果它们具有相同的路径名,除非你使用 -B 标志来 git diff。同时,如果某些路径名在祖先中为 missing,而其他一些路径名在后代中为 new,则该路径对成为候选路径重命名检测。重命名检测基于相似性索引进行工作。如果添加 -B 选项,那么在有问题的两个提交中,具有 相同 路径名的两个文件是 "broken apart" 如果相同的相似性指数低于某些临界点。如果打开重命名检测,任何未配对的文件——包括由于 -B 导致的配对中断的任何文件——都将通过重命名相似性测试 运行,如果它们通过,则将两条路径连接起来作为 "renamed file"。您可以通过 运行ning git diff-tree -r -M --name-status $ancestor $descendant 找到 Git 对此的决定并解析其输出(如果以编程方式执行此操作,也可以考虑添加 -z)。

这取决于你是要这么花哨,还是以不同的方式花哨(可能的方式主要受限于你的想象力,以及你愿意为此投入多少计算资源;maven 本身可能提供更多方式,特别是如果它有 "manifest" 个文件)。或者您可以使用简单但显然有些缺陷的 "did the path name exist before" 测试来确定 path/to/file.ext 是否是 "created since" 祖先提交:

oldhash=$(git rev-parse --verify --quiet $ancestor:$path)

如果成功,则该路径之前确实存在,并且您现在在 $oldhash 中拥有 blob 的哈希 ID。这会让你知道文件是否已经改变:如果是这样,它从解析 $descendant:$path 作为修订说明符的新散列将不同。

(除了重命名问题,如果 $path 存在于 $ancestor 中,但在某些中间提交中被完全删除,然后在后代提交中或之前重新创建,这显然会失败。这种情况 可检测的,通过从 `git rev-list --ancestry-path $ancestor..$descendant 遍历祖先路径中的每个提交,除了你会在祖先路径 DAGlet(子图)中的分支合并结构的情况下,需要注意任何合并。这可能不值得做:Git 的相似性测试可能更可靠。)

如果将所有这些放在一起,您最终可能会想做:

git diff-tree -r --name-status $ancestor $descendant

也许还有一些额外的 --diff-filter and/or -M and/or -B 标志。任何状态为 A(已添加)的文件都将是要分析的文件。状态为 M 的文件也可能是不错的候选者:有人接触过它们,所以是时候让它们通过静态分析了。