编辑过去提交的补丁
Editing patch of a past commit
我有一个过去的提交,其补丁中包含一行,这应该是较新提交的一部分。有什么办法可以将这条线从一个补丁移到另一个补丁吗?我正在尝试使用 git rebase --interactive
的 edit
选项,但我无法更改补丁。这甚至可能吗?
你可以得到你想要的,使用交互式变基。但请注意一个关键点:提交不是补丁!提交是 快照 。即使 git log -p
显示 每个提交作为补丁,每个提交都有一个 所有源代码的完整副本 。
git log -p
将提交显示为补丁的原因,即使它们是快照,也是显而易见的:有用 说 commit #12 与提交 #11 略有不同,区别 比起说:这是提交 #12,哈!你是靠你自己的,笨蛋! 所以 git log -p
通过提取提交 #11 和 提交 #12 来工作,比较两者,然后向你展示什么改变了。
您应该始终牢记这一点:提交是快照;但是 Git 喜欢 比较 两个快照以向您展示它们之间的变化。您可以选择任意两个快照进行比较,但是 git log -p
和其他 Git 命令将自动使用两个相邻的 parent/child 提交。 Rebase 的复制也是这样工作的:它比较 parent 和 child,看看要做什么。 (要比较您选择的两个提交,您可以使用 git diff
并简单地命名要比较的两个提交。)
您可能还想知道更改任何现有提交在技术上是不可能的。 Rebase 不能那样做,也不会尝试。 git rebase
所做的是 复制 旧的(有缺陷的)提交到 new-and-improved 的。旧的提交至少会保留一段时间,如果你的新的和改进的提交实际上是新的和更糟的,你可以找回它们。
综上所述,以下是使用交互式变基执行此操作的方法。首先选择一个提交 before 你需要改进的:
9abcdef Subject of last commit
00afde4 Second to last commit that should have more stuff
badc0de The commit that you dislike
ba5eba5 A commit you're OK with
在这里,提交 badc0de
是您想要替换为 new-and-improved 提交的那个。您想要将 在 badc0de
中所做的一些更改改为进入 00afde4
,因此您真的想用一个不同的提交替换 badc0de
, 和 00afde4
与另一个不同的提交做更多。然后,因为 9abcdef
说 my parent 是 00afde4
你将不得不复制 9abcdef
到一个新的和改进的提交其唯一的改进是 my parent 是 _______,其中空白通过制作 [=23= 的新改进版本来填补].
所以,现在您将 运行 git rebase -i ba5eba5
并在您的编辑器中得到一条指令 sheet,内容为:
pick badc0de The commit that you dislike
pick 00afde4 Second to last commit that should have more stuff
pick 9abcdef Subject of last commit
(请注意,虽然 git log
从 结束 开始并向后工作,但 git rebase -i
的指令 sheet 从第一次提交开始你会copy-but-change-while-copying并向前移动。)
因为我们在这里假设您要将 badc0de
中的行放入 00afde4
,您现在应该将三个 pick
命令中的这两个更改为 edit
,将 9abcdef
(您希望原封不动地复制)作为 pick
命令。将指令 sheet 写回到它所在的任何文件,然后退出编辑器以按照指令开始 Git。
Git 现在将复制提交 badc0de
,但随后停止以便您可以 更改 副本。从技术上讲,它实际上还没有 copied badc0de
— 它只是设置了一些东西,以便您接下来的操作 将 复制它 —但在我们即将看到的更复杂的情况下,它会创建一个临时副本。您现在处于 Git 所谓的 detached HEAD 模式——根本不在任何分支上——您所做的是 运行 您的编辑器编辑任何文件( s) 应该不同,更改它们,写出它们,然后退出你的编辑器。然后你 git add
每个这样的文件和 运行:
git commit --amend
这将 badc0de
推到 detached-HEAD 分支上,使 badc0de
提交的副本现在是 good犯罪。我们不知道它 将 有什么哈希 ID,但我们称它为 1111111
以供参考。
现在您已经 1111111
和 parent ba5eba5
以及您想要的快照,运行:
git rebase --continue
恢复交互式变基。 Git 现在继续将 00afde4
复制到新的临时提交。这次它确实必须制作临时副本,因为 00afde4
说 我的 parent 是 badc0de
,它需要一个说 我的 parent 是 1111111
。 Git 通过 比较 00afde4
和 badc0de
来创建这个临时副本,看看有什么变化,并对 1111111
进行相同的更改。我们不知道也不关心这个新的临时提交得到了什么哈希 ID,因为现在是时候再次启动你的编辑器并恢复你上次删除的缺失行了。
如果您忘记了缺失的行是什么,您可以轻松找到它们:使用 [=55= 将仍在您的存储库中的提交 badc0de
与其 parent 进行比较] 例如。使用编辑器将这些行放入 work-tree 文件中。 W找出文件,退出编辑器。 运行 git add
在这些文件上,然后再次 运行 git commit --amend
.
Git 现在将临时提交推开,进行类似于 00afde4
的新提交,除了:
- 它将
1111111
列为其 parent,并且
- 它恢复了
badc0de
中的行。
同样,我们不知道这个 将 有什么散列,但我们在这里称它为 2222222
以便我们讨论它。
现在您可以再次 运行 git rebase --continue
。此时唯一剩下的指令是pick 9abcdef
。因此 Git 将 9abcdef
与其 parent 00afde4
进行比较以查看发生了什么变化,对 2222222
中的快照进行相同的更改,并从那。让我们调用新副本 3333333
.
Git 现在有:
3333333 (copy of) Subject of last commit
2222222 (copy of) Second to last commit (now with more stuff)
1111111 (copy of) The commit that you disliked (but now improved)
ba5eba5 A commit you're OK with
提交 3333333
确实 与 9abcdef
相同, 除了 3333333
说 我的 parent 是 2222222
.
由于复制现已完成,git rebase
执行最后一个技巧:它使您的分支名称(无论名称是什么)标识副本 3333333
而不是原始 9abcdef
,并且通过检查 re-adjusted 分支退出分离的 HEAD 模式。所以现在如果你 Git 查看从当前开始的提交并向后工作,你会看到 3333333
,然后是 2222222
,然后是 1111111
,然后是 ba5eba5
, 等等。原始提交(您已用新的和改进的副本替换的提交)是不可见的。它们仍在 您的存储库中(大约一个月),但现在很难找到。
@karlosss git rebase -i commit-id-test
,在commit-id测试后会显示所有commit-id和commit-msg,然后你可以编辑commit-msg避免ctrl-c/v.
例如
pick 90b83db Replace QtMultimedia usage with 4A + gstreamer
pick f55e504 autobuild: introduce autobuild scripts
我有一个过去的提交,其补丁中包含一行,这应该是较新提交的一部分。有什么办法可以将这条线从一个补丁移到另一个补丁吗?我正在尝试使用 git rebase --interactive
的 edit
选项,但我无法更改补丁。这甚至可能吗?
你可以得到你想要的,使用交互式变基。但请注意一个关键点:提交不是补丁!提交是 快照 。即使 git log -p
显示 每个提交作为补丁,每个提交都有一个 所有源代码的完整副本 。
git log -p
将提交显示为补丁的原因,即使它们是快照,也是显而易见的:有用 说 commit #12 与提交 #11 略有不同,区别 比起说:这是提交 #12,哈!你是靠你自己的,笨蛋! 所以 git log -p
通过提取提交 #11 和 提交 #12 来工作,比较两者,然后向你展示什么改变了。
您应该始终牢记这一点:提交是快照;但是 Git 喜欢 比较 两个快照以向您展示它们之间的变化。您可以选择任意两个快照进行比较,但是 git log -p
和其他 Git 命令将自动使用两个相邻的 parent/child 提交。 Rebase 的复制也是这样工作的:它比较 parent 和 child,看看要做什么。 (要比较您选择的两个提交,您可以使用 git diff
并简单地命名要比较的两个提交。)
您可能还想知道更改任何现有提交在技术上是不可能的。 Rebase 不能那样做,也不会尝试。 git rebase
所做的是 复制 旧的(有缺陷的)提交到 new-and-improved 的。旧的提交至少会保留一段时间,如果你的新的和改进的提交实际上是新的和更糟的,你可以找回它们。
综上所述,以下是使用交互式变基执行此操作的方法。首先选择一个提交 before 你需要改进的:
9abcdef Subject of last commit
00afde4 Second to last commit that should have more stuff
badc0de The commit that you dislike
ba5eba5 A commit you're OK with
在这里,提交 badc0de
是您想要替换为 new-and-improved 提交的那个。您想要将 在 badc0de
中所做的一些更改改为进入 00afde4
,因此您真的想用一个不同的提交替换 badc0de
, 和 00afde4
与另一个不同的提交做更多。然后,因为 9abcdef
说 my parent 是 00afde4
你将不得不复制 9abcdef
到一个新的和改进的提交其唯一的改进是 my parent 是 _______,其中空白通过制作 [=23= 的新改进版本来填补].
所以,现在您将 运行 git rebase -i ba5eba5
并在您的编辑器中得到一条指令 sheet,内容为:
pick badc0de The commit that you dislike
pick 00afde4 Second to last commit that should have more stuff
pick 9abcdef Subject of last commit
(请注意,虽然 git log
从 结束 开始并向后工作,但 git rebase -i
的指令 sheet 从第一次提交开始你会copy-but-change-while-copying并向前移动。)
因为我们在这里假设您要将 badc0de
中的行放入 00afde4
,您现在应该将三个 pick
命令中的这两个更改为 edit
,将 9abcdef
(您希望原封不动地复制)作为 pick
命令。将指令 sheet 写回到它所在的任何文件,然后退出编辑器以按照指令开始 Git。
Git 现在将复制提交 badc0de
,但随后停止以便您可以 更改 副本。从技术上讲,它实际上还没有 copied badc0de
— 它只是设置了一些东西,以便您接下来的操作 将 复制它 —但在我们即将看到的更复杂的情况下,它会创建一个临时副本。您现在处于 Git 所谓的 detached HEAD 模式——根本不在任何分支上——您所做的是 运行 您的编辑器编辑任何文件( s) 应该不同,更改它们,写出它们,然后退出你的编辑器。然后你 git add
每个这样的文件和 运行:
git commit --amend
这将 badc0de
推到 detached-HEAD 分支上,使 badc0de
提交的副本现在是 good犯罪。我们不知道它 将 有什么哈希 ID,但我们称它为 1111111
以供参考。
现在您已经 1111111
和 parent ba5eba5
以及您想要的快照,运行:
git rebase --continue
恢复交互式变基。 Git 现在继续将 00afde4
复制到新的临时提交。这次它确实必须制作临时副本,因为 00afde4
说 我的 parent 是 badc0de
,它需要一个说 我的 parent 是 1111111
。 Git 通过 比较 00afde4
和 badc0de
来创建这个临时副本,看看有什么变化,并对 1111111
进行相同的更改。我们不知道也不关心这个新的临时提交得到了什么哈希 ID,因为现在是时候再次启动你的编辑器并恢复你上次删除的缺失行了。
如果您忘记了缺失的行是什么,您可以轻松找到它们:使用 [=55= 将仍在您的存储库中的提交 badc0de
与其 parent 进行比较] 例如。使用编辑器将这些行放入 work-tree 文件中。 W找出文件,退出编辑器。 运行 git add
在这些文件上,然后再次 运行 git commit --amend
.
Git 现在将临时提交推开,进行类似于 00afde4
的新提交,除了:
- 它将
1111111
列为其 parent,并且 - 它恢复了
badc0de
中的行。
同样,我们不知道这个 将 有什么散列,但我们在这里称它为 2222222
以便我们讨论它。
现在您可以再次 运行 git rebase --continue
。此时唯一剩下的指令是pick 9abcdef
。因此 Git 将 9abcdef
与其 parent 00afde4
进行比较以查看发生了什么变化,对 2222222
中的快照进行相同的更改,并从那。让我们调用新副本 3333333
.
Git 现在有:
3333333 (copy of) Subject of last commit
2222222 (copy of) Second to last commit (now with more stuff)
1111111 (copy of) The commit that you disliked (but now improved)
ba5eba5 A commit you're OK with
提交 3333333
确实 与 9abcdef
相同, 除了 3333333
说 我的 parent 是 2222222
.
由于复制现已完成,git rebase
执行最后一个技巧:它使您的分支名称(无论名称是什么)标识副本 3333333
而不是原始 9abcdef
,并且通过检查 re-adjusted 分支退出分离的 HEAD 模式。所以现在如果你 Git 查看从当前开始的提交并向后工作,你会看到 3333333
,然后是 2222222
,然后是 1111111
,然后是 ba5eba5
, 等等。原始提交(您已用新的和改进的副本替换的提交)是不可见的。它们仍在 您的存储库中(大约一个月),但现在很难找到。
@karlosss git rebase -i commit-id-test
,在commit-id测试后会显示所有commit-id和commit-msg,然后你可以编辑commit-msg避免ctrl-c/v.
例如
pick 90b83db Replace QtMultimedia usage with 4A + gstreamer
pick f55e504 autobuild: introduce autobuild scripts