如何使用Git cherry-pick命令挑选特定提交并将其添加到当前代码库中,同时保留原始历史记录?

6

我做了以下事情:

git fetch upstream
git cherry-pick xyz

选定的提交已经被成功地应用,除了在其中一个文件中,它与我之前在另一个提交中已经完成的更改完全相同,因此这些更改没有重新应用。
就代码方面而言,一切都很好,但我想在我的历史记录中有提交哈希值。在我的历史记录中,它显示为一个新名称。这是可能的吗?据我所阅读的git合并“ours”策略似乎通常是可能的,但如何仅针对单个提交执行此操作?
我这样做是为了以后更容易确定upstream拥有的提交与我没有的提交。目前在github的network视图中,我看到挑选的提交是一个独立的东西,我没有。
附加信息: CharlesB说的对我有意义。但是merge -s ours如何实现这种魔法呢?在这种情况下,对于我来说,cherry-pick并不重要。因为我想要采取的更改只是一个,位于upstream/master的顶端。所以只是为了尝试一下,我执行了:git merge -s ours upstream/master 现在执行git log --graph --pretty=oneline --abbrev-commit,我看到了这样的东西:
*   9e8108b Merge remote-tracking branch 'mgencur/master' for better github netw
|\  
| * aa7117d Fix displaying watchers/watching for incorrect user // this commit magically appeared after merge -s ours
* | ff05f8c Fix displaying watchers/watching for incorrect user // this is commit from cherry-pick of aa7117d
* | b7ca8ec older commit in my fork
* | <more commits in my fork>
|/  
* 94d6870 Fix obtaining available users for testing purposes
* <older commits of upstream/master>

在执行git merge -s ours之前,相同的命令看起来像这样:

* ff05f8c Fix displaying watchers/watching for incorrect user // this is commit from cherry-pick of aa7117d
* b7ca8ec older commit in my fork
* <more commits in my fork>
* 94d6870 Fix obtaining available users for testing purposes
* <older commits of upstream/master>

从选择了提交aa7117d之后可以看出,在我的分支仓库中并没有显示aa7117d已经被应用。但是在合并之后,它被标记为已经被合并,尽管我的文件没有任何改变。

这让我想到,确实有可能声明一些提交包含在一个分支中,尽管它们没有像上游那样被精确地应用。

更新2:我看到了问题How to merge a specific commit in Git和它最佳的答案。因此,也希望能解释为什么不可能或者未实现。


你似乎对 cherry-pick 和 merge 有些困惑。前者将指定的提交应用到当前分支上。就像是导出补丁文件并应用补丁一样,仅此而已。后者也会创建一个新的提交,但该提交具有两个父提交。因此,在另一个分支上没有提交被打补丁,更像是将两个开发分支合并成一个。这就是为什么你在历史记录中看到原始哈希字符串,但那只是因为它们确实还在那里,没有修改过其原始状态。 - Michael Wild
@Michael-Wild,是的,我想要一种合并/挑选组合的方式。 - akostadinov
1
那绝对行不通。这不是 Git 的工作方式。哈希唯一地标识了一个提交,如果你改变它的父提交,哈希必须改变。这就是为什么在 Git 中提交哈希被称为密码安全。如果你可以验证分支头的哈希值,你已经有效地验证了它的整个历史记录。任何修改该历史记录的操作都将改变哈希值。没有例外。 - Michael Wild
@Michael-Wild,谢谢你的评论,我觉得所有的事情都已经落实了。如果你愿意写一个答案,我会给你信用。 - akostadinov
2个回答

4
提交哈希值在定义上对于每个提交是唯一的。
当进行cherry-pick操作时,即使应用相同的修改,也会创建一个新的提交,因为它具有不同的父提交。
但是,您可以请求git在cherry-pick提交消息中添加一条消息:
"cherry-picked from commit "
来自文档
-x
记录提交时,在原始提交消息中追加一行,以指示从哪个提交挑选了此更改(“(cherry picked from commit ...)”)。仅针对没有冲突的cherry pick执行此操作。如果您正在从私有分支cherry-pick,则不要使用此选项,因为该信息对接收者无用。另一方面,如果您正在两个公开可见的分支之间进行cherry-pick操作(例如,从开发分支向旧版本的维护分支回溯修复),添加此信息可能会很有用。

请查看我的问题中的“附加信息”。在我看来,似乎可以将某些提交声明为应用于当前分支,尽管它们实际上并不相同。也许不是使用cherry-pick命令? - akostadinov
我不明白你所说的“声明提交应用于当前分支”的意思。你是指在合并操作中选择要包含/排除的提交吗? - CharlesB
请查看“ours”合并策略的说明。我希望它们显示为已应用的合并操作。我猜可以通过一些分支和合并操作来实现。但如果“cherry-pick”命令可以自动化完成就太酷了。 - akostadinov

3

Git不允许您这样做。 Git哈希唯一标识提交和其所有历史记录。这意味着,当您挑选一个提交时,您会将一个补丁应用于另一个历史记录,因此除非哈希值冲突(极其罕见),否则哈希值不同。

你仍然看到原始哈希数的原因是在执行合并时情况有所不同。合并不是一个具有单个父提交的常规提交。相反,它具有两个(甚至更多)父提交,将分离的开发线程汇集在一起。因此保留了合并头的原始历史记录。


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