通过修改提交进行差异化

Make a diff with amend commit

我想知道是否可以在两次提交之间显示 diff amend 之一?换句话说,git 是否将修改后的提交保存在某处的历史记录中?

修改后的提交与任何其他提交没有什么不同。从这个意义上说,完全有可能区分 'normal' 提交和修改后的提交。

In other words does git save amended commits in history somewhere?

没有某个列表包含所有已修改的提交,没有。修改后的提交就像所有其他提交一样存在于历史记录中。

当你修改一个提交时,它基本上被删除并被一个新的(它也得到一个新的提交哈希)替换,该新的具有原始提交的更改+修改后的更改。

git reflog 中您可以看到您最近的操作,并且确实显示了对提交的修改。来自那里的引用可用于例如撤消 git commit --amend。有关详细信息,另请参阅 How to undo "git commit --amend" done instead of "git commit"

我不认为我理解这个问题,但我认为部分原因是因为我认为你对 git commit --amend 的作用有错误的想法。

git 中的提交实际上无法更改。 git commit --amend 所做的就是使用故意更改的父 ID 编写 new 提交。

让我们看一下进行新提交的正常过程。

在进行新提交之前,您修改了工作树中的一些文件,然后使用 git add 暂存这些更改,以便提交新版本的文件。 git add 将文件的新版本放入 git 的 "index",即其暂存区。

上一次提交中已经存在的文件已经在暂存区中。因此,您将进行的新提交将包含所有原始文件,除了您更改的任何内容然后 git add-ed 将是新版本而不是旧版本。

现在您 运行 git commit(没有 --amend)并且 git 执行以下操作:

  • 收集提交消息(来自 -m-F 或 运行 编辑器);
  • 获取您的姓名和电子邮件,以及当前时间;
  • 获取当前提交(不是新提交)的 SHA-1 ID;
  • 使用暂存区写一个"tree"对象:这是将与新提交关联的源代码树;
  • 使用所有这些信息(作者+提交者、树、父 ID 和您的消息)创建一个提交对象——这个新的提交对象有一个新的唯一 SHA-1 ID;
  • 最后,将新的ID写入分支,让分支标签指向新的ID,而不是原来最尖端的分支。

最后一步 "grows the branch",这样如果你以前有一些提交,就像这样:

... <- E <- F <- G   <-- master

你现在又多了一个:

... <- E <- F <- G <- H   <-- master

分支名称(master 或其他名称)现在指向您最新的提交 H,并且 H 指向 使用的内容 是你最新的提交 G.

如果你使用 git commit --amend,git 只改变这个序列一点点:而不是让新的提交 (H) 指向当前的 (G), git 使新的一分回到当前的父级(在本例中,F):

                G
              /
... <- E <- F <- H   <-- master

现在 master(或您所在的任何分支)指向 H,后者指向 F,依此类推。

如果您 运行 git log,git 从当前提交 (H) 开始并记录它,然后移动到其父项 (F) 并记录它,等等。提交 G 似乎消失了。

G 的 SHA-1 ID 仍然存在(默认情况下为 30 天),在 "reflogs" 中。 HEAD 有一个 reflog,你当前的分支也有一个。如果你在分支 master 上并且你刚刚完成 H,那么 master@{1}master 的前一个提示,即提交 G。或者,如果您将 SHA-1 ID 保存在屏幕上的某处,您可以剪切并粘贴它以查看提交 G.

( --amend 开关也可以修改合并提交。这与上面的工作方式完全相同,只是意味着 git 必须复制 all 从旧分支提示到新分支提示的父 ID。)