挑选一个提交并保留原始的SHA代码。

90

我想精选一次从远程拉取的提交记录,并保留其原始SHA提交代码(我的当前分支基于此远程分支,我将其重置为先前状态)。


17
我认为你误解了提交哈希的真正含义。 - Carl Norum
4
为什么你想要保留原始的SHA哈希值? - siegi
这不是问题的答案,但是谷歌把我带到了这里,遇到了类似的问题,之后我发现我实际上想要执行 git merge --ff-only [分支名称] 而不是 cherry-pick - fuenfundachtzig
1
我想在保持两个仓库同步时做类似的事情,因为这是了解哪些提交被两个仓库共享并更快地找出尚未导入的提交的好方法。不幸的是,以下解决方案都无法在这种边缘情况下工作。请参见 https://dev59.com/mr3pa4cB1Zd3GeqPmNbY - Vadorequest
5个回答

123

git SHA哈希值是从不同的信息中计算出来的:

  1. 树对象:它基本上是在提交所在的分支中存储库的当前内容。
  2. 父提交对象的SHA值
  3. 提交消息
  4. 作者信息:姓名、电子邮件和时间戳。
  5. 提交者信息:姓名、电子邮件和时间戳。

即使您编辑了一个cherry-pick提交,以便树对象、提交消息、作者和提交者信息完全相同,但父提交对象(如果处理合并提交,则父提交对象将有多个)的SHA值始终会不同。因此,在cherry-pick后,您将无法生成相同的SHA哈希值(除非您找到SHA碰撞;))。


2
谢谢提供有用的信息 :) 实际上我使用命令 git branch master remote/master 创建了我的分支,并保留了原始 SHA... 然后我重置到特定的提交,现在我想要重置到另一个更近的提交,但它跳转到了存储库日志上的另一个点... - blameless75
实际上,当我尝试复制该提交时,与其相关的所有文件都出现了“被我们删除”的错误......这很奇怪... - blameless75
1
顺便提一下,提交者也会不同。 - Vanuan
2
即使您编辑了一个挑选的提交,以便树、提交消息、作者和提交者信息完全相同,父提交的SHA(如果处理合并提交,则为提交的父提交)也将始终不同。但这并不一定是正确的。如果您在打开新分支时进行提交,然后创建第二个分支并从第一个分支中挑选,那么两个提交将具有相同的父提交。但在这种情况下,它们仍将具有不同的SHA,因为提交者的提交时间会晚于挑选的提交。 - wbharding
2
@Vanuan 如果你只挑选自己的提交,那就不算。 - Aamir Rizwan
1
@AamirRizwan 时间戳仍然会不同,这是提交者信息的一部分。 - eis

25

SHA提交哈希是由存储库的状态组成的,使用了整个历史记录直到提交点(不包括分支)。这意味着,除非整个历史记录相同,否则在挑选时无法保留原始哈希值,在那种情况下,挑选也没有意义。


实际上,这是版本库日志上的下一个提交。我试图将我的本地分支重置到该提交的 SHA,但是我的分支在完全不同的位置上... - blameless75
更准确地说,SHA哈希值并不代表整个存储库的状态,而是代表一个提交及其整个历史记录。存储库可能有不同的分支和提交... - siegi
@ siegi 谢谢,已添加。我当时想到的是“该时间点整个存储库的状态”,但是分支也被排除在外。 - eis

7
根据您对其他答案的评论,我认为您只是想将其重置为某个远程提交。您可以使用git reset --hard <SHA>来完成此操作。警告:这将会删除工作目录中的所有未提交更改,并且此分支中的所有提交将不再可用。 如果这不是您想要的(或者您不确定),请更清楚地描述您所做的事情以及您想要做什么或正在尝试完成的任务。

这对于那些只看到命令并尝试运行它的人来说有些危险。 - chaosink
1
@chaosink,感谢您指出这一点,我尝试编辑答案以强调潜在的数据丢失。不过有两点需要注意:首先,我们应该**永远不要**盲目执行从网上找到的任何内容,除非我们理解或者至少能够评估其带来的影响。其次,您可以使用git reflog来恢复至少提交的更改。 - siegi

7

打开交互式重置("git rebase -i")并在末尾粘贴一个新条目,其中包含您想要添加到头部的确切版本。

示例:

打开交互式重置会话:

$ git rebase -i HEAD~4

屏幕现在显示的是[类似于]这样的内容:
pick efdd0ece Linked how to make a pull requests in README
pick 790a3be8 adjust pytest pins to fix testing infra
pick 5bb90d8f drop 3.4 support
pick 839dc8ba v2.22.0
pick b97fb61a Print the type of the password instead of the password itself

你当前的 HEAD 是最后一条记录。在底部添加一个新的记录(仅“pick”和你想要插入的确切修订版本;无需描述):

pick efdd0ece Linked how to make a pull requests in README
pick 790a3be8 adjust pytest pins to fix testing infra
pick 5bb90d8f drop 3.4 support
pick 839dc8ba v2.22.0
pick b97fb61a Print the type of the password instead of the password itself
pick 2a173c2a6491aae0772640ba7946a08315d18eb8

保存并关闭。该特定修订版本现在将成为您的HEAD:

$ git log --oneline | head -n 6
2a173c2a Some commit
b97fb61a Print the type of the password instead of the password itself
839dc8ba v2.22.0
5bb90d8f drop 3.4 support
790a3be8 adjust pytest pins to fix testing infra
efdd0ece Linked how to make a pull requests in README

如其他回答所述,您仍需遵守规则。这仅适用于一种非常狭窄的情况,即您拥有完全相同的分支、父级和提交者(例如,在代码审查流程中,您有一堆提交排队等待,开发人员可以将它们推上去并将其下来,而不必首先将它们提交到存储库中);实际上只有时间戳可能已更改的情况下才能生效。在这种情况下,您可以强制相同的修订版本以强制时间戳保持不变。

在大多数其他情况下,父级通常会有所不同,光是这一点就意味着您迫使某个特定修订版本的愿望将死亡。如果任何非时间戳因素不同,Git都会自动修复修订版本以确保其正确性。


6

在之前的回答中,我没有找到提到它的地方,所以请注意,如果你在提交父级上挑选(cherry-picking),添加--ff标志实际上可以保留原始的SHA。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接