TL;DR
(您可能会误解这一点,因此最好跳到下一节;)
我想找到补丁(提交或暂存/非暂存工作区更改(会更改的(以前的(提交。
TL;DR:继续阅读,但跳过"背景">...
背景
我将在这里描述我的工作流程,以便您了解我需要什么。
在我的开发分支上,我经常在很多 WIP 提交中提交小的更改。当我对我的整体更改感到满意时,我会以交互方式重新设置所有这些 WIP 提交的基础,以构成一个干净的历史记录。我将提交压缩到其他提交中,并编写详细的提交消息。
在三种情况下,我想指出上一次提交应该被压缩到另一个提交中。
- 当我注意到我在以前的 WIP 提交之一中引入了一个错误时
- 当我想将最近的更改显式合并到某个 WIP 提交中时
- 提及在错误修复的提交消息中引入错误的提交 ID
然后我提交一个提交,注意必须将更改(错误修复(
压缩到的提交。历史记录可能如下所示:
[WIP] Fixed some bug [SQUASH with '[WIP] Made some sloppy change'] (A)
...
[WIP] Made some sloppy change (B)
...
(有时我在 4 小时内产生超过 15 次提交(
由于我经常做这样的小补丁,所以我想到了一个自动化的解决方案。
我想知道的
当补丁...
- 删除并添加行(更改(,我想获取引入或最近更改该行的提交
- 添加行,我想获取插入之前和之后的行的提交,这些行最近更改或引入
- 仅删除行,我想获取添加或最近修改这些行的提交
我如何手动执行此操作
TL;DR:跳过本节并继续阅读"示例..."部分...
在准备提交(A)
时,我以这种方式搜索提交(B)
:
- 检查本地更改并通过发出来记住受影响的行号
-
git diff
更改是否尚未提交 -
git log -1 -p
更改是否已提交
-
- 通过发出以下命令查找在制作补丁之前影响记忆行的提交
-
git blame HEAD -- path/to/file
更改是否尚未提交 -
git blame HEAD~1 -- path/to/file
更改是否已提交
-
之后,在这两种情况下,我都会使用 git log <COMMIT ID>
收到这些提交 ID 的提交消息
添加和更改示例(更改尚未提交(:
这是补丁 ( git diff
(
diff --git a/Gruntfile.js b/Gruntfile.js
index 9af9384..380726c 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -82,6 +82,7 @@ module.exports = function(grunt) {
less: {
build: {
options: {
+ dumpLineNumbers: "comments",
paths: ["target/"]
},
@@ -141,7 +142,7 @@ module.exports = function(grunt) {
src: {
files: 'src/**',
- tasks: ['copy:source-tree', 'copy:devel-source-tree']
+ tasks: ['copy:source-tree', 'copy:devel-source-tree', 'less']
}
}
});
这是git blame -L82,+8 HEAD -- Gruntfile.js
和git blame -L142,+8 HEAD -- Gruntfile.js
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 82) less: {
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 83) build: {
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 84) options: {
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 85) paths: ["target/"]
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 86) },
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 87)
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 88) files: {
f39f25c0 (Nobody 2014-05-17 16:08:20 +0200 89) "target/styles.css": "src/less/styles.less"
e2e46b59 (Nobody 2014-05-03 10:30:34 +0200 142) src: {
e2e46b59 (Nobody 2014-05-03 10:30:34 +0200 143) files: 'src/**',
e2e46b59 (Nobody 2014-05-03 10:30:34 +0200 144) tasks: ['copy:source-tree', 'copy:devel-source-tree']
f9a635c0 (Nobody 2014-04-21 16:03:38 +0200 145) }
f9a635c0 (Nobody 2014-04-21 16:03:38 +0200 146) }
f9a635c0 (Nobody 2014-04-21 16:03:38 +0200 147) });
5128dcdc (Nobody 2014-04-20 12:56:05 +0200 148)
f9a635c0 (Nobody 2014-04-21 16:03:38 +0200 149) grunt.task.loadTasks("tasks/");
这些是提交消息(git log --oneline -1 f39f25c0
和git log --oneline -1 e2e46b59
(
f39f25c [WIP] * Changed to less (left .css file)
e2e46b5 [WIP] * Changed watch configuration
现在我知道了,我必须分别提交两个大块头,提到单独的提交。
解决 方案
是的,我阅读了git-blame
手册页,但我没有找到开箱即用的合适选项(我确定我可能错过了一些东西(。
是的,我也尝试在互联网上搜索这个。但是,呵呵,我花了一页来描述它 - 我应该如何制定金色的谷歌搜索表达式来找到它?
是的,正如您将在下一节中看到的那样,我有自己的想法。
我的方法
我将创建一个脚本来解析git log -p
或git diff
生成的补丁。它将使用"我想知道的内容">部分中的规则输出补丁影响的所有行号。然后,bash 脚本通过检查git blame HEAD[~1]
输出来查找提交 ID,提取提交 ID。最后一步是获取提交消息。另一个步骤可能是,使用刚刚找到的提交消息装饰整个补丁输出(多个块和文件(。
(实际上目前我正在编写一个执行补丁解析的 Python 脚本(
替代方法
也许这可以通过从git blame -- <FILE>
和git blame HEAD -- <FILE>
中提取提交列并将两个输出都馈送到diff
中来实现,然后grep -C <N>
for 00000000
等以查找受影响的提交 ID。
但我认为这是脆弱的,不如上述方法可靠。我也需要解析责备差异的补丁。
(我已经尝试过了。最难的部分是差异输出解析。
尝试将其简化为一个问题。
是否有一个标准的 Git 工具,通过将 git blame 的强大功能与 git log 提供的数据相结合,通过显示通过应用提交更改的提交?
我希望我的问题足够清楚。 :)
要有分寸。
我确定,我是。
为了帮助后一部分,您应该真正研究git rebase -i --autosquash
。Autosquash 变基将查找特殊格式的提交,以便在您变基时自动重新排序您的提交,并将它们标记为 squash/fixup。从git help rebase
:
--autosquash, --no-autosquash
When the commit log message begins with "squash! ..." (or "fixup!
..."), and there is a commit whose title begins with the same ...,
automatically modify the todo list of rebase -i so that the commit
marked for squashing comes right after the commit to be modified,
and change the action of the moved commit from pick to squash (or
fixup).
This option is only valid when the --interactive option is used.
If the --autosquash option is enabled by default using the
configuration variable rebase.autosquash, this option can be used
to override and disable this setting.
至于自动查找最后的更改,自动执行将始终是脆弱的。
鉴于以下历史:
[WIP] Fixed sloppy change (A)
[WIP] Intermediate change (B)
[WIP] Sloppy change (C)
如果你有一个中间提交(B(修改了与(A(和(C(相同的行,但你不希望你的提交(A(与(B(合并,而是与旧的(C(合并,你很容易意外地压制错误的提交。
此外,通常情况下,您要合并到的提交不会与当前更改发生冲突的编辑,因此再多的魔法也无法使脚本预测您想要做什么。 因此,编写这部分脚本的价值微乎其微,相反,我发现使用基于 GUI 的历史浏览器极大地帮助了这一步(我在 Linux 上使用 gitg,在 Mac 上使用 gitx,但任何历史浏览器都可以(。