`.git/CHERRY_PICK_HEAD` 在提交时有什么区别?

What difference does `.git/CHERRY_PICK_HEAD` make when committing?

注意: 这是对我之前的 post(现已删除)的改写。改写意在给 post 一个不同的焦点。


运行宁 git cherry-pick 后,git 报告存在冲突。我解决了冲突,然后运行git cherry-pick --continue。此时,$GIT_EDITOR 弹出一个 COMMIT_EDITMSG 缓冲区,其中预填充了精心挑选的提交的原始消息以及一些附加信息,其中包括警告:

# It looks like you may be committing a cherry-pick.
# If this is not correct, please remove the file
#   .git/CHERRY_PICK_HEAD
# and try again.

我检查了如果我 "deleted"(实际上,只是暂时重命名).git/CHERRY_PICK_HEAD 文件会发生什么。这产生的直接外在效果是从我的 git 感知提示中删除 |CHERRY-PICKING 指示。

除了我的提示中的这一变化,以及 COMMIT_EDITMSG 缓冲区中的预填充信息可能存在一些差异之外,使用或不使用 .git/CHERRY_PICK_HEAD 执行提交会有什么不同文件到位了吗?


更准确地说,我试图在这里比较两种情况。

第一种情况,我运行

% git cherry-pick --continue

...并且(忽略前面引用的警告)我照常进行提交。

第二种情况,我运行

% rm .git/CHERRY_PICK_HEAD
% git commit

...并像往常一样继续提交。

(假设我在两种情况下使用相同的提交消息。)

这两种情况的最终结果有何不同?

答案取决于你在做什么。使用 --continue 完成序列 — 但如果序列只是一个 cherry-pick,则根本就不是真正的序列。

然而,无论如何,删除 .git/CHERRY_PICK_HEAD 肯定有一个额外的重要影响:完成 一个冲突的 cherry-pick re-uses 原始提交的 author-name-email-and-date 信息。您始终是任何新提交的提交者,但所有提交都不止一个 person-and-timestamp:每个新提交都有两个条目,一个用于 "committer"(您,刚刚进行提交),另一个用于"author"(无论谁写了原始提交,以及他们何时这样做)。 Cherry-pick 保留原始提交的作者信息。

音序器

git cherry-pickgit revert——实际上是同一个命令;仅恢复 "works backwards"——使用 Git 调用的 序列器 。也就是说,您可以一次选择多个提交:

git cherry-pick notthis..that thistoo

挑选所有提交 "after" notthis,直到并包括 that,以及一个特定的提交 thistoo。例如,您可能决定 cherry-pick feature/X 上从 develop 增长的每个提交,加上一个错误修复提交 fix-1234,用于测试目的:

git checkout master
git checkout -b testbranch
git cherry-pick develop..feature/X fix-1234

无论如何,这里的要点是这可能 cherry-pick 十几个或更多提交,并且在此过程中的某个地方可能存在合并冲突,这需要 git cherry-pick 停止并获得帮助。

旁白:这里的模型——Unix/Linux 命令行——是你在一个叫做 shell 的 command-interpreter 中输入一个命令. shell 将 human-interface 的控制权交给新命令,新命令会保留它直到命令完成并退出。一旦命令退出,命令本身就没有任何痕迹:任何永久都必须保存在文件中。

所以:如果 cherry-pick 必须停止,它如何知道从哪里恢复?答案是将信息保存在文件中。如果您正在 cherry-pick 单个提交,Git 仅保存 CHERRY_PICK_HEAD 文件,该文件记录了正在 cherry-pick 提交的 ID。但是,如果您 cherry-picking 多个 提交,Git 将冲突的提交保存为单个提交, 将剩余信息保存在排序目录中(其位置随时间移动了一些)。

运行 git cherry-pick --continue 指示(新的、单独的实例)cherry pick 命令从前一个停止的地方开始。 Git会先给你运行一个git commit,然后定位排序信息,尽可能多的完成这个序列,在下一次冲突时再次停止,或者完成所有的cherry-picks.

运行 git commit 相反,Git 会注意到 CHERRY_PICK_HEAD 文件并使用它,如您所见。当提交完成时,该命令退出并且不对定序器执行任何操作。如果 sequencer 数据遗留,您现在可以 git cherry-pick --continue: Git 会注意到提交已经完成,只需继续/完成 sequencer 操作。

请注意,您可以使用 git cherry-pick --abort 而不是完成操作。这将终止操作并将事情恢复到开始之前的状态。从 Git 2.19 开始,您可以改为使用 git cherry-pick --quit 停止(a la --abort)但是 not 将事情恢复到您之前的状态开始了。也就是说,它会停止任何未来的 cherry-picking 操作,而不会撤消您目前所做的操作。 (2.19之前没有这个操作。)

git status 命令现在会注意到是否有正在进行的序列,并报告您正在执行您正在执行的任何操作。 (与 Git 1.7 时代相比,这是一个很大的改进,当时它没有。)

正如我评论的那样,git cherry-pick --quit 也删除了 .git/CHERRY_PICK_HEAD,但是,此外,消息“如果这不正确,请删除文件 .git/CHERRY_PICK_HEAD”将随着 Git 2.29(2020 年第 4 季度):更新了对两个伪引用的访问以正确使用引用 API.

commit b8825ef, commit b6d2558, commit c8e4159, commit 3f9f1ac (21 Aug 2020) by Han-Wen Nienhuys (hanwen)
(由 Junio C Hamano -- gitster -- in commit e699684 合并,2020 年 8 月 31 日)

builtin/commit: suggest update-ref for pseudoref removal

Signed-off-by: Han-Wen Nienhuys

When pseudorefs move to a different ref storage mechanism, pseudorefs no longer can be removed with 'rm'.
Instead, suggest a "update-ref -d" command, which will work regardless of ref storage backend.

新消息会提示:git update-ref -d CHERRY_PICK_HEAD