【问题标题】:Tool to find most recent commit that is changed by a previous change or change in workspace用于查找由先前更改或工作区更改更改的最新提交的工具
【发布时间】:2014-05-24 13:51:57
【问题描述】:

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 手册页,但我没有找到一个合适的选项来执行此操作(我确信我可能遗漏了一些东西)。

是的,我也试过在互联网上搜索这个。但是,嗯,我花了一页来描述它 - 我应该如何制定黄金 Google 搜索表达式来找到它?

是的,正如您将在下一节中看到的,我有自己的想法。

我的方法

我将创建一个脚本来解析git log -pgit diff 生成的补丁。 它将使用 “我想知道的” 部分中的规则输出补丁影响的所有行号。 然后 bash 脚本通过检查 git blame HEAD[~1] 输出来查找提交 ID,提取提交 ID。 最后一步是获取提交消息。 另一个步骤可能是,用刚刚找到的提交消息装饰整个补丁输出(多个块和文件)。

(其实我现在正在写一个 Python 脚本来做补丁解析)

替代方法

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

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

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

尽量减少到一个问题。

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

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

要具体。

我确定,我是。

【问题讨论】:

  • 请注意,我已经创建了一个很好的 Python 脚本,它可以解析补丁以找到我将手动查找的行。但它仍然需要一些努力(单元测试,也许是一些控制开关,干净的 CLI),我真的更喜欢一些开箱即用的可能带有一些单线管道的魔术来使用开箱即用的工具获取信息。

标签: git diff history patch blame


【解决方案1】:

为了帮助完成后面的部分,您应该仔细研究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,但任何历史浏览器都可以)。

【讨论】:

  • 首先,感谢您提醒我--autosquash 功能。 :) 第二:我已经通过示例历史改进了您的帖子,以便更容易理解您的测试。第三:我花了好几次尝试才明白你想说什么。如果它理解正确,这对我来说不是问题,因为我不想自动压缩而是找到提交。仍然由我来决定这是否是我所指的正确提交。 :)
  • 不管怎样,您强调一行中可能有两个“部分”,其中第二部分已添加到(B)中,但第一个部分已添加到(C)中。 (A) 应该修补 (C) 但我/该工具会发现提交 (B) 是错误的。漂亮的边框。我希望我一遇到它就会看到它。 :) 我可以想到一些检测会发现添加了一行的一部分(因为 diff 只看到行的变化)(有点像每个单词的差异)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-16
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-17
  • 2021-08-30
  • 1970-01-01
相关资源
最近更新 更多