将 Git 提交回溯到历史中的另一个分支

Move a Git commit retrospectively to another branch in the history

我不小心在开发分支上进行了一般更改,不久前已经将其合并到 master 分支:

* HEAD
* ...
*
* 2c884bc Updated Gradle Root Project Name
*   4926f6a Merge branch 'wip-dev-Logger'
|\
| * 43161fb Revised Logger
| * 13c8303 Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*

是否可以在不破坏 merge/branch 历史的情况下将提交 13c8303 从开发分支移至主分支?

它应该看起来像这样:

* HEAD
* ...
*
* 2c884bc Updated Gradle Root Project Name
*   4926f6a Merge branch 'wip-dev-Logger'
|\
| * 43161fb Revised Logger
* | 13c8303 Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*

git 中的单个提交是 不可变的,因为它们由哈希值标识:

  • 整个代码树
  • 提交消息、日期和作者身份信息
  • 在合并提交的情况下标识其父项或多个父项的哈希值

同时,分支可以随意更改,因为它们只是指向特定提交的可移动指针。

所以你显示的结果是不可能的,因为如果哈希 13c8303 标识的提交有不同的父项,它会有不同的哈希。由 43161fb4926f6a 标识的提交也将有不同的父项,因此散列不同 - 对于从您要创建的历史点“转发”的所有提交,依此类推。

可以使用 git rebase 命令创建替代历史记录,但是 每个工作副本和每个分支 在您进行更改后都需要更新以引用新的历史记录。如果你做对了,它看起来像这样:

* HEAD
* ...
*
* 56fa78b Updated Gradle Root Project Name
* 12cd34e Merge branch 'wip-dev-Logger'
|\
| * ef78ab9 Revised Logger
* | 12ab34d Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*

如果您尝试使用原始历史记录中稍后的分支而不将其变基到新历史记录,您最终会在更改后得到所有提交的两个版本 - 并且可能会发生很多冲突当您尝试将它们重新合并在一起时。

根据@IMSop的回答,我想出了以下解决方案:

  1. 在我的例子中,除了 master 之外没有其他分支,而且我还没有将我的任何错误推送到远程

如果您有一个未合并的分支指向较新的提交,请确保您知道如何处理即将到来的额外困难。

  1. git rebase --root --interactive --rebase-merges
  2. 更改编辑器中的提交顺序
...

pick 4b0dcb8 Switched to Java 17
label branch-point
pick 13c8303 Switched to JDA 4.4.0_351                       <--- COMMIT TO MOVE ---
pick 43161fb Revised Logger
label wip-dev-Logger
reset branch-point # Switched to Java 17
pick 599c72e Added Answerer interface
merge -C 4926f6a wip-dev-Logger # Merge branch 'wip-dev-Logger'
pick 2c884bc Updated Gradle Root Project Name

...

pick 4b0dcb8 Switched to Java 17
label branch-point
pick 43161fb Revised Logger
label wip-dev-Logger
reset branch-point # Switched to Java 17
pick 599c72e Added Answerer interface
pick 13c8303 Switched to JDA 4.4.0_351                       <--- COMMIT TO MOVE ---
merge -C 4926f6a wip-dev-Logger # Merge branch 'wip-dev-Logger'
pick 2c884bc Updated Gradle Root Project Name

...
  1. 保存并关闭编辑器。如果您没有触及可能与此合并冲突的移动提交中的任何文件,一切都应该正常工作。

  2. 确认使用git log --graph --oneline:

* HEAD
* ...
*
* c5d2985 Updated Gradle Root Project Name
*   31a26e4 Merge branch 'wip-dev-Logger'
|\
| * 13e0a2c Revised Logger
* | 5cebef6 Switched to JDA 4.4.0_351
* | 599c72e Added Answerer interface
|/
* 4b0dcb8 Switched to Java 17
*
* ...
*