3

TL;博士

(你可能会误解这一点,所以最好跳到下一节;)

我想找到(以前的)提交一个补丁(提交或分阶段/非分阶段工作区更改)会改变。

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如果更改已经提交

之后,在这两种情况下,我都会使用这些提交 ID 获得提交消息git log <COMMIT 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 -por生成的补丁git diff。它将使用“我想知道的”部分中的规则输出补丁影响的所有行号。然后一个 bash 脚本通过检查输出来查找提交 ID git blame HEAD[~1],提取提交 ID。最后一步是获取提交消息。另一个步骤可能是用刚刚找到的提交消息装饰整个补丁输出(多个块和文件)。

(实际上目前我正在编写一个 Python 脚本来进行补丁解析)

替代方法

也许这可以通过从git blame -- <FILE>and中提取提交列git blame HEAD -- <FILE>并将两个输出输入diff,然后grep -C <N>ing for00000000等来找到受影响的提交 ID 来完成。

但我认为这很脆弱,不如上述方法可靠。而且我也需要解析责备差异的补丁。

(我已经尝试过了。最难的部分是 diff 输出解析。)

尝试将其简化为一个问题。

是否有一个标准的 Git 工具,通过显示通过应用提交更改的提交,将 git blame 的功能与 git log 提供的数据相结合?

我希望我的问题足够清楚。:)

要具体。

我确定,我是。

4

1 回答 1

2

为了帮助完成后一部分,您应该真正研究git rebase -i --autosquash. Autosquash rebase 将查找特殊格式的提交,以便在您 rebase 时自动重新排序您的提交并将它们标记为 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,但任何历史浏览器都可以)。

于 2014-05-24T14:16:04.590 回答