如何找到跨文件重命名和重新排序添加特定 Gradle 构建依赖项的 Git 提交?

Posted

技术标签:

【中文标题】如何找到跨文件重命名和重新排序添加特定 Gradle 构建依赖项的 Git 提交?【英文标题】:How can I find the Git commit that added a specific Gradle build dependency across file renames and reorderings? 【发布时间】:2021-08-03 03:13:55 【问题描述】:

我正在使用Spring Boot 和Java 实现一个多项目Gradle 项目,并使用Git 进行版本控制。其中一个子项目依赖于特定的库(我们称之为com.example:mylib),在该特定子项目的build.gradle 文件中声明。这个库是不久前添加的,我想找到添加它的提交,以便我可以了解添加它的原因以及是否仍然需要它。我的库代码中没有导入,但由于 Spring Boot 的 auto-configuration 部分基于类路径上的库,因此在我的代码中没有直接使用不足以确定是否使用或如何使用该库.

为了给这个场景添加一个皱纹,自项目启动以来发生了各种项目重组:子项目已多次重命名、移动到子项目等。构建文件本身也进行了重组和重新排序。此外,Gradle 文件已从 Groovy (build.gradle) 切换到 Kotlin (build.gradle.kts),然后又切换回来。

build.gradle

// ...
dependencies 
    // ...
    compile 'com.example:mylib'
    // ...

// ...

build.gradle.kts

// ...
dependencies 
    // ...
    implementation("com.example:mylib:1.0.5")
    // ...

// ...

我知道一些手动方法可以追溯并找到更改。例如,我可以使用git blame 并通过对行的更改返回,在重命名和重组发生时手动切换文件。但是,当发生大量更改时,这些方法可能会有点耗时且乏味。

如何快速轻松地找到添加库的提交?

【问题讨论】:

试试git log -S "com.example:mylib" @ElpieKay 除非您愿意,否则我会将其扩展为完整的答案。 @ElpieKay 您可以添加--reverse 以获取第一次出现在顶部的参考。或者为了聪明一点,只在参考文献第一次出现时显示,你可以git log -S nimbusds --pretty=format:"%H" | tail -1 | xargs git log -1 没关系。如果可行,请随时将其添加到答案中。 【参考方案1】:

git bisect 可用于以自动方式快速查找更改。

鉴于develop有库依赖,而abc123是添加库依赖之前的提交,下面会找到添加依赖的提交:

git bisect start
git bisect new develop
git bisect old abc123
echo "! grep -rI --include \*.gradle\* mylib ." > /tmp/bisect.sh 
chmod u+x /tmp/bisect.sh 
git bisect run /tmp/bisect.sh
git bisect reset

git bisect start 开始一个新的 bisect 会话。然后,我们需要识别至少一个旧提交和一个新提交——也就是说,一个更改前的提交(“旧”)和一个更改后的提交(“新”)。 git bisect new developdevelop 指定为“新”提交,git bisect old abc123 将“abc123”指定为“旧”提交。 (请注意,标准术语是坏/好,不是新/旧,但由于这更多的是变化而不是破损,我选择使用alternate terms“旧”和“新”而不是标准术语.)

然后,Git 将采用二进制搜索算法,在旧提交和新提交的大约一半左右切换到提交。

输出:

Bisecting: 818 revisions left to test after this (roughly 10 steps)
[1234567890abcdef1234567890abcdef12345678] Committed some stuff

此时,您可以手动识别此提交是旧的还是新的 (git bisect old/git bisect new),并使用 Git 二进制搜索其对引入更改的提交的方式。但是,我们可以通过使用 git bisect run <scriptname.sh> 让 Git 使用脚本检查每个潜在的提交来自动化这个过程。如果脚本返回退出代码 0,则将其标识为“旧”;如果存在 1 到 127 之间的代码(125 除外),则它是“新的”。

对于这种情况,我们可以使用命令grep -rI --include \*.gradle\* mylib .。这使用grep 递归查找与包含术语“mylib”的模式*.gradle* 匹配的任何非二进制文件。这将匹配build.gradlebuild.gradle.kts,但会跳过许多我们不关心的其他文件(从而加快处理速度)。

但是,grep 命令返回我们想要的相反的退出代码。它在匹配时返回成功(“旧”)响应,但我们希望它是失败(“新”)响应。可以使用! 保留字:! grep -rI --include \*.gradle\* mylib . 将命令取反为所需值。

此命令存储在/tmp/bisect.sh 脚本中并可执行:

echo "! grep -rI --include \*.gradle\* mylib ." > /tmp/bisect.sh 
chmod u+x /tmp/bisect.sh 

现在我们有了脚本,我们将它传递给git bisect run 以获取添加依赖项的提交:

git bisect run /tmp/bisect.sh

输出:

abcdefg1234567890abcdefg1234567890abcdef is the first new commit
commit abcdefg1234567890abcdefg1234567890abcdef
Author: John Doe <john.doe@example.com>
Date:   Tue May 26 17:37:25 2020 -0400

    adding a new library for fun and profit
    
    1. add the library
    2. ???
    3. profit

 subproject1/build.gradle                           |   6 +-
 .../nested/subpackage/MyAwesomeClass.java          |  37 -------
 .../nested/subpackage/LessAwesomeClass.java        | 118 +++++++++++++++++++++
 .../nested/BoilerplateJunk.java                    |  32 ++++--
 subproject1/src/main/resources/application.yaml    |  12 +++
 .../another/subpackage/Whatever.java               |  28 +++++
 6 files changed, 189 insertions(+), 44 deletions(-)

最后,我们调用git bisect reset 来结束 bisect 会话并切换回我们在开始 bisect 会话之前所在的分支。

【讨论】:

【参考方案2】:

git log -S 仅显示给定文本字符串出现次数的修订版本。列表中的最后一项将是第一次添加文本字符串的版本。在库的情况下,这将是它第一次添加的依赖项(假设构建文件是该依赖项曾经出现的唯一位置)。

git log -S myLib

-S&lt;string&gt;

寻找改变文件中指定字符串出现次数(即添加/删除)的差异。供脚本编写者使用。

当您正在寻找一个确切的代码块(如结构)并想知道该代码块自诞生以来的历史时,它很有用:迭代地使用该功能来提供有趣的代码块preimage 回到-S,并继续直到你得到第一个版本的块。

二进制文件也会被搜索。

如果您只想输出第一次添加依赖项的修订版,可以通过一些命令管道来完成。一种方法是:

git log -S mylib --pretty=format:"%H" | tail -1 | xargs git log -1 --stat

输出:

commit abcdefg1234567890abcdefg1234567890abcdef
Author: John Doe <john.doe@example.com>
Date:   Tue May 26 17:37:25 2020 -0400

    adding a new library for fun and profit
    
    1. add the library
    2. ???
    3. profit

 subproject1/build.gradle                           |   6 +-
 .../nested/subpackage/MyAwesomeClass.java          |  37 -------
 .../nested/subpackage/LessAwesomeClass.java        | 118 +++++++++++++++++++++
 .../nested/BoilerplateJunk.java                    |  32 ++++--
 subproject1/src/main/resources/application.yaml    |  12 +++
 .../another/subpackage/Whatever.java               |  28 +++++
 6 files changed, 189 insertions(+), 44 deletions(-)

【讨论】:

以上是关于如何找到跨文件重命名和重新排序添加特定 Gradle 构建依赖项的 Git 提交?的主要内容,如果未能解决你的问题,请参考以下文章

Linux系统下文件名出现中文乱码如何重命名回来

如何批量重命名文件夹下的Excel文件

按特定条件复制和重命名 - 批量

js 如何批量重命名文件

怎么批量重命名多个文件夹里的图片

如何将命名向量作为行添加到数据框中,根据列名顺序重新排序?