Skip to content

git-history

实验性:重写历史

概要

git history fixup <commit> [--dry-run] [--update-refs=(branches|head)] [--reedit-message] [--empty=(drop|keep|abort)]
git history reword <commit> [--dry-run] [--update-refs=(branches|head)]
git history split <commit> [--dry-run] [--update-refs=(branches|head)] [--] [<pathspec>...]

描述

通过重新排列或修改历史中的特定提交来重写历史。

此命令是实验性的。行为可能会更改。

此命令与 git-rebase(1) 相关,因为两个命令都可用于重写历史。但有几个主要区别:

  • git-history(1) 的大多数子命令可以在裸仓库中工作,因为它们不需要触及索引或工作树。fixup 子命令是一个例外,因为它从索引读取暂存的更改。
  • git-history(1) 目前不执行任何 githooks(5)。这将来可能会改变。
  • git-history(1) 默认更新原始提交的所有后代分支以指向重写的提交。

总体而言,git-history(1) 旨在提供一种更固执的方式来修改提交历史,与 git-rebase(1) 相比通常更易于使用。

如果您想将一系列提交重新应用到不同的基础,请使用 git-rebase(1);如果想一次编辑一系列提交,请使用交互式变基。

限制

此命令(尚)不能处理包含合并的历史。您应该改用带有 --rebase-merges 标志的 git-rebase(1)

此外,该命令不支持可能导致合并冲突的操作。此限制是设计使然,因为历史重写不打算成为有状态的操作。一旦 Git 了解一等冲突,此限制就可以解除。

使用带有 --empty=dropfixup 时,尚不支持删除根提交。

命令

  • fixup <commit> - 将当前暂存的更改应用到指定的提交。这本质上类似于 git commit --fixup=<commit> 后跟 git rebase --autosquash <commit>~。通过在 HEAD 提交、目标提交和从暂存更改生成的树之间执行三向合并,将更改应用到目标提交。 默认情况下,目标提交的提交消息和作者身份会被保留,除非您指定 --reedit-message。 如果应用暂存的更改会导致冲突,命令将中止并报错。原始提交的所有后代分支都会更新以指向重写的历史。

  • reword <commit> - 重写指定提交的提交消息。此提交的所有其他详细信息保持不变。此命令将启动带有该提交当前消息的编辑器。

  • split <commit> [--] [<pathspec>...] - 通过选择将移入新的拆分提交的块,交互式地将 <commit> 拆分为两个提交。这些块将被写入成为先前提交父提交的新提交。原始提交保持不变,只是其父提交将是新拆分的提交。 拆分提交的提交消息将通过启动配置的编辑器来询问。提交的作者身份将与原始提交相同。

选项

  • --dry-run - 不更新任何引用,而是以 git-update-ref(1) 可以消费的格式打印任何引用更新。

  • --reedit-message - 打开编辑器以修改目标提交的消息。

  • --empty=(drop|keep|abort) - 控制提交因修复变为空时发生的情况。这可能在两种情况下发生:

    • 修复目标本身变空,因为暂存的更改恰好抵消了该提交引入的所有更改。
    • 后代提交在重放期间变空,因为它引入了刚刚修复到祖先中的相同更改。 使用 drop(默认)时,空提交从重写的历史中删除。 使用 keep 时,空提交按原样保留在重写的历史中。 使用 abort 时,如果任何提交将变空,命令将停止并报错。
  • --update-refs=(branches|head) - 控制命令将更新哪些引用(如果有)。使用 branches 时,指向原始提交后代提交的所有本地分支将被重写。使用 head 时,仅当前 HEAD 引用将被重写。默认为 branches

示例

修复提交

$ git log --oneline --stat
abc1234 (HEAD -> main) third
 third.txt | 1 +
def5678 second
 second.txt | 1 +
ghi9012 first
 first.txt | 1 +

$ echo "change" >>unrelated.txt
$ git add unrelated.txt
$ git history fixup ghi9012

$ git log --oneline --stat
jkl3456 (HEAD -> main) third
 third.txt | 1 +
mno7890 second
 second.txt | 1 +
pqr1234 first
 first.txt     | 1 +
 unrelated.txt | 1 +

暂存的 unrelated.txt 添加已被合并到 first 提交中。所有后代提交都已在重写的历史之上重放。

拆分提交

$ git log --stat --oneline
3f81232 (HEAD -> main) original
 bar | 1 +
 foo | 1 +
 2 files changed, 2 insertions(+)

$ git history split HEAD
diff --git a/bar b/bar
new file mode 100644
index 0000000..5716ca5
--- /dev/null
+++ b/bar
@@ -0,0 +1 @@
+bar
(1/1) Stage addition [y,n,q,a,d,p,?]? y

diff --git a/foo b/foo
new file mode 100644
index 0000000..257cc56
--- /dev/null
+++ b/foo
@@ -0,0 +1 @@
+foo
(1/1) Stage addition [y,n,q,a,d,p,?]? n

$ git log --stat --oneline
7cebe64 (HEAD -> main) original
 foo | 1 +
 1 file changed, 1 insertion(+)
d1582f3 split-out commit
 bar | 1 +
 1 file changed, 1 insertion(+)

Git

git(1) 套件的一部分

基于 CC BY-NC-SA 3.0 许可发布