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

时间:2009-05-19 05:27:34

标签: git merge

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

我想在没有先前提交的情况下合并它。我该怎么办?我知道如何合并所有提交:

git branch -b a-good-feature
git pull repository master
git checkout master
git merge a-good-feature
git commit -a
git push

9 个答案:

答案 0 :(得分:1069)

'git cherry-pick'应该是你的答案。

  

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

请不要忘记在这篇文章中阅读bdonlan关于采摘樱桃后果的答案:
"Pull all commits from a branch, push specified commits to another",其中:

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

变为:

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

这个提交的问题是git认为提交要包括它们之前的所有历史记录

     

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

     

这种更改提交ID会破坏git的合并功能(尽管如果谨慎使用,会有一些启发式方法可以解决这个问题)。   更重要的是,它忽略了功能依赖 - 如果C实际上使用了B中定义的函数,你将永远不会知道

答案 1 :(得分:635)

您可以使用git cherry-pick将单个提交单独应用于当前分支。

示例:git cherry-pick d42c389f

答案 2 :(得分:24)

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

我有一个分支,说,指向X< commit-id>,我有一个指向Y< sha1>的新分支。

Y< commit-id> =< master>分支提交 - 很少提交

现在说对于Y分支我必须在主分支和新分支之间进行间隙关闭。以下是我们可以遵循的程序:

第1步:

git checkout -b local origin/new

其中local是分支名称。任何名字都可以给出。

第2步:

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

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

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

git merge --help

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

git cherry-pick <commit-id>

答案 3 :(得分:10)

假设您想将分支X的提交e27af03合并到主服务器。

git checkout master
git cherry-pick e27af03
git push

答案 4 :(得分:6)

主要答案描述了如何将更改从特定提交应用于当前分支。如果这就是“如何合并”的意思,那么请按照他们的建议使用Cherry-pick。

但是,如果您实际上想要进行合并,即您想要具有两个父级的新提交 -当前分支上的现有提交,以及您想要的提交应用-的更改,那么完成任务将无法实现。

例如,如果您的构建过程利用git ancestry来基于最新标记自动设置版本字符串(使用git describe),则可能需要具有真实的合并历史记录。

您可以执行实际的git merge --no-commit,而不是执行自动选择操作,然后手动调整索引以删除不需要的任何更改。

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

git checkout A
git 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技术合并。

答案 5 :(得分:5)

我过去经常采摘樱桃,但是发现我时不时遇到一些神秘的问题。 我碰到了Microsoft的25年经验丰富的Raymond Chen的博客,该博客描述了在某些情况下摘樱桃可能导致问题的某些情况。

经验法则之一是,如果您从一个分支中挑选一个分支,然后再在这些分支之间进行合并,那么您迟早会遇到问题的。

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

我对Raymond博客的唯一问题是他没有提供完整的示例。因此,我将尝试在此处提供一个。

上面的问题询问如何仅将HEAD指向的 a-feature-feature 分支中的提交合并到 master

这是怎么做:

  1. 找到 master 一个好功能之间的共同祖先 分支。
  2. 从该祖先创建一个新分支,我们称其为 新分支补丁
  3. Cherry在这个新的 patch 分支中选择了一个或多个提交。
  4. 将补丁分支合并到 master 的两个分支中 功能优良分支。
  5. master 分支现在将包含提交,并且 master a-feature-分支也将具有新的共同祖先,如果以后再进行合并,它将解决以后的所有问题。

以下是这些命令的示例:

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

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

围绕部分合并的场景和细节可能会非常深入,因此,我建议您仔细阅读Raymond Chen博客的所有10个部分,以全面了解可能出问题的地方,如何避免出现问题以及为什么这样做的原因。

答案 6 :(得分:2)

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

在这种情况下,选择“摘樱桃”不是一个好选择。但是,我们从commit-id创建一个本地分支,然后将该本地分支合并到master并执行mvn clean verify(我们使用maven)。如果成功,则使用带有localCheckout = true选项和pushChanges = false的maven发布插件将生产版本工件发布到联系。最终,当一切都成功时,将更改并标记为原始。

示例代码段:

如果手动完成,则假设您已掌握。但是在jenkins上,当您签出仓库时,您将位于默认分支(如果已配置,则为master)。

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

这将为您提供完全控制,而无需担心合并或冲突地狱。

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

答案 7 :(得分:0)

我们将不得不使用dotnet ef dbcontext scaffold "Server=.\SQLEXPRESS;Database=SchoolDB;Trusted_Connection=True;" Microsoft.EntityFrameworkCore.SqlServer -o Models

场景:我在一个名为release的分支上,我只想在master分支到release分支之间添加一些更改。

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

git cherry-pick <commit-number>

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

例如

git checkout release

第3步:git cherry-pick 634af7b56ec

注意:每次合并时,都会创建一个单独的提交编号。不要将无法执行的提交编号用于合并。相反,您要添加的任何常规提交的提交编号。

答案 8 :(得分:0)

如果已将更改提交到master分支。现在,您要将相同的提交移至发布分支。检查提交ID(例如:xyzabc123)以进行提交。

现在尝试执行以下命令

git checkout release-branch
git cherry-pick xyzabc123
git push origin release-branch