首页 > 解决方案 > Git:查找仅更改了 serialVersionUID 的文件

问题描述

我有一组自动生成的 java 文件,它们被检入到 git 中。每个文件包含该行

final static long serialVersionUID = -4268385597939353497L;

其中 serialVersionUID 之后的部分在每次重新生成时更改为随机数。

注意:这是一成不变的,我知道“没有将生成的代码检查到版本控制等中”。

如何识别更改了 serialVersionUID 的所有文件? 已更改意味着文件在工作副本中已被修改,但尚未提交。

我的目标是通过预提交挂钩还原这些文件。

我已经到了

git diff -U10000 --raw MyFile.java

这给了我整个文件的差异或

git diff -U0 --raw --word-diff=porcelain MyFile.java

这给了我一个“差异标题”加上一个更改列表。

标签: javagitgit-diff

解决方案


注意:这个特定的 StackOverflow 答案并不能解决您的问题(我实际上无法正确解决它,因为我没有 Java 解析器)。这完全是关于您将遇到的所有其他绊脚石,以及如何避免它们,以便您的任务实际上只是与 Java 相关的部分。

需要注意的是,这里的每个文件都有三个副本:

  • 您当前提交中的那个,HEAD:MyFile.javagit show HEAD:MyFile.java用来查看这个);
  • 提议的下一次提交中的那个,:MyFile.java(再次,用于git show查看它);和
  • 工作树中的那个,MyFile.java您可以直接查看和编辑。

git diff命令通常会选择三个中的两个进行比较。

git diff不带参数运行,或只选择文件(不是提交)的参数运行,将文件的索引副本与工作树副本进行比较。它不会提取当前提交的文件。索引副本是git commit将写入提交的副本,因此它实际上是您现在提议提交的内容。

Usinggit diff --cached告诉 Git 将文件中HEAD的文件与索引中的文件进行比较。Usinggit diff HEAD告诉 Git 将文件HEAD与工作树中的文件进行比较。因此,这些是您选择比较哪些文件的方式。但无论如何,如果让 Git 比较所有文件,每个文件git diff只选择一对文件,或者一组对。

如果你运行git commit -a——我建议你不要,在这里——这大致相当于git add -u && git commit,除了它用更新的文件建立一个临时索引。在这里的各种提交钩子中事情变得特别棘手,因为现在有多个不同的索引文件具有不同的建议下一个提交。这就是为什么我建议避免git commit -a在这里。处理和推理一个文件的三个副本已经足够困难,并且使用棘手的提交选项,例如-a--only--include抛出第四个甚至有时是第五个副本。

(Git 一次只能处理一个索引文件。标准git commit只有一个标准索引文件。标准索引文件具有将或将进入下一次提交的文件的副本。1 选项导致 Git 创建额外的临时索引文件,它在其中构建提议的新提交,然后在环境中使用 set 运行其余操作(包括您的挂钩),$GIT_INDEX_FILE以使这些子命令查看要使用的临时索引。如果一切顺利最后git commit进行新的提交,这些临时索引文件中的一个,根据选项和参数具有适当的内容,成为新索引,之后你回到正常情况,每个只有三个副本文件。)

由于您的计划是在预提交挂钩中工作,因此您可能应该HEAD文件与索引中的建议提交文件进行比较,即,您可能应该git diff --cached在此处使用。但是,如果您打算通过计算机程序来执行此操作,而不是作为人类闲暇时阅读的东西,那么您根本不应该使用git diff。前端git diff命令是供人类使用的,这就是为什么它对输出进行分页和着色,并执行所有那些只会惹恼计算机程序的事情。Git 将这些花哨的前端称为瓷器命令

每种git diff都由后端管道命令实现。将提交(技术上是一棵树)与索引进行比较的管道命令是git diff-index,它仍然需要--cached告诉它进行所需的比较:git diff-index --cached HEAD产生可预测的输出,不依赖于每个用户的首选寻呼机、颜色样式等.

(如果你写这个钩子专门为你自己使用,你可以使用git diff或者git diff-index因为你可以补偿你自己的个人git diff设置。但从某种意义上说,最好还是使用管道命令——那么就没有必要补偿为了任何东西。)

无论您在这里选择什么,您仍然必须编写自己的代码来解释差异输出。:MyFile.java相反,您可能会选择编写一个程序,该程序仅从当前提交和索引中提取两个感兴趣的文件 - <code>HEAD:MyFile.java 和,并在您自己的程序中比较它们,而不是使用git diff一点也不。您可以使用 提取文件git show,但这有一个小缺陷,即它是另一个瓷器命令。您可以使用git cat-file -p底层管道命令直接提取文件,而无需通过git show.

实际上解析 Java 代码将是最可靠的方法,这样您就不会被某种愚蠢的格式更改所绊倒。一种更hacky的方法,例如假设除了某一特定形式的一行之外的所有内容都必须匹配,这在 awk 中并不太困难(一次读取两个文件一行,检查两个文件中只有一行不同文件并且它具有预期的形式)。所有这些似乎都比尝试解析 diff 输出更简单,但如果你想解析 diff 输出,非 Git 非上下文 diff 可能更简单。

最后,关于:

我的目标是通过预提交挂钩还原这些文件。

这样做可以的(Git 会正确处理它,对于“正确”的一些定义),但对于许多 Git 用户来说,这也有点令人惊讶。像这样的 Git 钩子不应该改变事情。编写 Git 的人的目的是让像这样的 Git 挂钩仅用于验证事物。如果验证步骤失败,钩子应该退出非零,这将导致git commit停止。任何修复都应该通过一些非挂钩操作来完成。

请注意,它完全git commit --no-verify 跳过了预提交挂钩。


1从技术上讲,索引引用了每个文件的只读副本。因为这些副本是只读的,所以它们可以共享。所以“复制”一个索引很便宜,因为它实际上只是复制了所有的引用。此外,提议的新提交中的每个文件与某个现有提交中已经存在的文件 100% 逐位相同,实际上只是对该文件的引用,因为存储在每个提交中的每个文件本身都是完全读取的-只要。


推荐阅读