如何在Git中合并特定的提交

我从GitHub的存储库中分叉了一个分支并提交了一些特定于我的东西。现在我发现原始存储库有一个很好的功能,位于HEAD

我想只合并它没有以前的提交。我该怎么办?我知道如何合并所有提交:

git branch -b a-good-featuregit pull repository mastergit checkout mastergit merge a-good-featuregit commit -agit push
1035896 次浏览

#0”应该是你的答案。

应用由现有提交引入的更改。

不要忘记阅读bdonlan关于樱桃采摘后果的回答:
msgstr"从一个分支拉取所有提交,将指定的提交推送到另一个分支"哪里:

A-----B------C\\D

变成:

A-----B------C\\D-----C'

这个提交的问题是git认为提交包含所有历史记录

其中C'有一个不同的SHA-1 ID。
同样,从一个分支到另一个分支选择提交基本上涉及生成补丁,然后应用它,从而以这种方式丢失历史记录。

提交ID的这种变化破坏了git的合并功能(尽管如果很少使用,会有启发式方法来掩盖这一点)。
更重要的是,它忽略了函数依赖关系——如果C实际上使用了B中定义的函数,你永远不会知道.

您可以使用git chiry-Picch将单个提交本身应用于您当前的分支。

示例:git cherry-pick d42c389f

让我们试着举个例子并理解:

我有一个分支,比如大师,指向X,我有一个新的分支指向Y

哪里Y<提交ID>=分支提交-很少提交

现在假设对于Y分支,我必须关闭master分支和新分支之间的提交。以下是我们可以遵循的过程:

第一步:

git checkout -b local origin/new

其中本地是分支名称。可以给出任何名称。

第二步:

  git merge origin/master --no-ff --stat -v --log=300

将主分支的提交合并到新分支,并创建日志消息的合并提交,其中包含最多正在合并的实际提交的单行描述。

有关Git合并的更多信息和参数,请参阅:

git merge --help

此外,如果您需要合并特定的提交,那么您可以使用:

git cherry-pick <commit-id>

在我的用例中,我们对CI CD有类似的需求。我们使用带有开发和主分支的git flow。开发人员可以自由地将他们的更改直接合并到开发中或通过来自功能分支的拉取请求。但是要掌握,我们只能通过Jenkins以自动方式合并来自开发分支的稳定提交。

在这种情况下,选择樱桃不是一个好的选择。然而,我们从提交ID创建一个本地分支,然后合并该本地分支以掌握并执行mvn干净验证(我们使用maven)。如果成功,然后使用maven发布插件将生产版本工件发布到nexus,其中包含localCheckout=true选项和pushChange=false。最后,当一切成功时,将更改和标签推送到源。

示例代码片段:

如果手动完成,假设您在master上。但是在jenkins上,当您签出存储库时,您将在默认分支上(如果配置了master)。

git pull  // Just to pull any changes.git branch local-<commitd-id> <commit-id>  // Create a branch from the given commit-idgit merge local-<commit-id>  // Merge that local branch to master.mvn clean verify   // Verify if the code is build ablemvn <any args> release:clean release:prepare release:perform // Release artifactsgit push origin/master  // Push the local changes performed above to origin.git push origin <tag>  // Push the tag to origin

这将给你一个完全的控制与无畏的合并或冲突地狱。

如果有更好的选择,请随时提供建议。

前导答案描述了如何应用中的更改对当前分支的特定提交。如果这就是你所说的“如何合并”的意思,那么就按照他们的建议使用樱桃选择。

但是,如果您实际上想要一个合并,即您想要一个新的提交有两个父母-当前分支上的现有提交,以及您想要应用更改的提交-那么樱桃选择将无法实现这一点。

拥有真正的合并历史可能是可取的,例如,如果您的构建过程利用git祖先来根据最新标签自动设置版本字符串(使用git describe)。

您可以执行实际的git merge --no-commit,然后手动调整索引以删除您不想要的任何更改。

假设您在分支A上,并且您想在分支B的尖端合并提交:

git checkout Agit merge --no-commit B

现在您已设置为创建具有两个父级的提交,当前提示提交AB。但是,您可能应用了比您想要的更多的更改,包括B分支上早期提交的更改。您需要撤消这些不需要的更改,然后提交。

(可能有一种简单的方法可以将工作目录和索引的状态设置回合并前的状态,这样你就有了一个干净的石板,可以首先选择你想要的提交。但我不知道如何实现这个干净的石板。git checkout HEADgit reset HEAD都会删除合并状态,这与此方法的目的背道而驰。)

因此,手动撤消不需要的更改。例如,您可以

git revert --no-commit 012ea56

对于每个不需要的提交012ea56

当你完成调整后,创建你的提交:

git commit -m "Merge in commit 823749a from B which tweaked the timeout code"

现在你只有你想要的变化,祖先树显示你从技术上合并了B。

我曾经樱桃采摘,但发现我有一些神秘的问题。我遇到了雷蒙德·陈的博客,他在微软工作了25年,描述了一些情况,在某些情况下,挑选樱桃会导致问题。

其中一个经验法则是,如果你从一个分支挑选到另一个分支,然后在这些分支之间合并,你可能迟早会遇到问题。

以下是Raymond Chen关于这个主题的博客:https://devblogs.microsoft.com/oldnewthing/20180312-00/?p=98215

我对雷蒙德的博客唯一的问题是他没有提供一个完整的工作示例。所以我将尝试在这里提供一个。

上面的问题询问如何将良好的功能分支中HEAD指向的提交合并到大师

以下是如何做到这一点:

  1. 找到大师a-good-功能之间的共同祖先分支。
  2. 从该祖先创建一个新分支,我们称之为新分支补丁.
  3. Cherry选择一个或多个提交到这个新的补丁分支。
  4. 将补丁分支合并到两者大师a-good功能分支。
  5. 大师分支现在将包含提交,大师良好的功能分支也将有一个新的共同祖先,如果稍后执行进一步合并,这将解决任何未来的问题。

以下是这些命令的示例:

git checkout master...a-good-feature  [checkout the common ancestor]git checkout -b patchgit cherry-pick a-good-feature  [this is not only the branch name, but also the commit we want]git checkout mastergit merge patchgit checkout a-good-featuregit merge -s ours patch

可能值得注意的是,合并到良好的功能分支的最后一行使用了“是我们的”合并策略。这样做的原因是我们只需要在良好的功能分支中创建一个指向新的共同祖先的提交,并且由于代码已经在该分支中,我们希望确保没有任何合并冲突的机会。如果你正在合并的提交不是最近的,这变得更加重要。

围绕部分合并的场景和细节可能会变得非常深刻,所以我建议阅读Raymond Chen博客的所有10个部分,以充分了解可能出错的地方,如何避免它,以及为什么它有效。

假设您想将提交e27af03从分支X合并到master。

git checkout mastergit cherry-pick e27af03git push

我们将不得不使用git cherry-pick <commit-number>

场景:我在一个名为发布的分支上,我只想添加从主分支到发布分支的一些更改。

步骤1:签出要添加更改的分支

git checkout release

第2步:获取要添加的更改的提交号

例如

git cherry-pick 634af7b56ec

步骤3:git push

注意:每次合并都会创建一个单独的提交编号。不要为不起作用的合并获取提交编号。相反,您要添加的任何常规提交的提交编号。

如果您已将更改提交到主分支。现在您想将相同的提交移动到发布分支。检查提交的提交ID(例如:xyzabc123)。

现在尝试以下命令

git checkout release-branchgit cherry-pick xyzabc123git push origin release-branch

我建议一个解决方案。那就是手动更改并通过导出手动提交到目标分支,对于使用tortoise这样的工具来说,导出确实是实现这一目标的有效方法。我知道这在SVN中效果很好,到目前为止,在git的一些测试中也取得了同样的成功,只要它们100%相同,将来合并功能分支就不应该有任何冲突解决方案。

举个例子:
C:/git/MyProject_Master/
C:/git/C:/g it/MyProject_FeatureA/模块A/

假设我们希望ModuleA的FeatureA分支中的所有文件都在master分支中。暂时假设这是一个巨大的项目,还有其他模块,并且我们从经验中知道ModuleA没有任何依赖项会因功能分支的新更改而导致编译器或功能问题。选择ModuleA文件夹并选择从tortoise导出。然后选择master的ModuleA将其导出到。最后,对每个文件进行文件差异检查以查看更改,使用diff工具,确保所有调用仍然兼容。确保它编译,彻底测试。提交,推送。这个解决方案经过时间考验,对svn有效。

如果您是Cherry选择的新手,请尝试GitHub桌面版本,当您选择Cherry-选择选项时,GitHub会要求您选择要推送提交的分支。

1)

输入图片描述

2)

输入图片描述