我在一个多项目Gradle项目中工作,该项目使用Spring Boot和Java实现,并使用Git进行版本控制。其中一个子项目依赖于一个特定的库(我们称之为com.example:mylib
),该库在该特定子项目的build.gradle
文件中声明。这个库是不久前添加的,我想找到添加它的提交,这样我就可以了解添加它的原因,以及是否仍然需要它。在我的代码中没有该库的导入,但由于Spring Boot的自动配置在一定程度上是基于类路径上的库来工作的,因此我的代码内没有直接使用不足以确定是否使用或如何使用该库。
更糟糕的是,自项目开始以来,已经发生了各种项目重组:子项目被多次重命名、移动到子项目等。构建文件本身也进行了重组和重新排序。此外,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 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
CCD_ 9开始新的平分会话。然后,我们需要识别至少一个旧的和一个新的提交——也就是说,一个在更改之前的提交("旧的")和一个在变更之后的提交("新的")。CCD_ 10指定CCD_;新的";commit和CCD_;abc123";作为";旧的";犯罪(请注意,标准术语是坏的/好的,而不是新的/旧的,但由于这更多的是一种改变而不是破坏,我选择使用替代术语"旧的"one_answers"新的"来代替标准术语。)
Git将采用二进制搜索算法,大约在旧&新的提交。
输出:
Bisecting: 818 revisions left to test after this (roughly 10 steps)
[1234567890abcdef1234567890abcdef12345678] Committed some stuff
此时,您可以手动将此提交标识为旧的或新的(git bisect old
/git bisect new
),Git二进制文件会搜索到引入更改的提交。然而,我们可以通过让Git使用git bisect run <scriptname.sh>
用脚本检查每个潜在的提交来自动化这个过程。如果脚本返回退出代码0,则将其标识为"0";旧的";;如果它存在的代码在1和127之间(而不是125);新的";。
对于这种情况,我们可以使用命令grep -rI --include *.gradle* mylib .
。这使用grep递归地找到与包含术语"0"的模式CCD_ 17匹配的任何非二进制文件;mylib";。这将匹配build.gradle
和build.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
来结束平分会话,并更改回开始平分会话之前的分支。
git log -S
仅显示修订—给定文本字符串出现的次数。列表中的最后一项将是首次添加文本字符串的修订。在库的情况下,这将是它第一次添加的依赖项(假设构建文件是依赖项出现过的唯一位置)。
git log -S myLib
-S<string>
查找更改文件中指定字符串出现次数(即添加/删除)的差异。供编剧使用。
当您正在寻找一个精确的代码块(如结构),并想知道该块自第一次出现以来的历史时,它很有用:迭代地使用该功能将预映像中有趣的块反馈回
-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(-)