如何在 Git 中合并特定提交
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/881092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to merge a specific commit in Git
提问by netawater
I have forked a branch from a repository in GitHub and committed something specific to me. Now I found the original repository had a good feature which was at HEAD
.
我从 GitHub 的存储库中创建了一个分支,并提交了一些特定于我的内容。现在我发现原始存储库有一个很好的功能,它位于HEAD
.
I want to merge it only without previous commits. What should I do? I know how to merge all commits:
我只想在没有先前提交的情况下合并它。我该怎么办?我知道如何合并所有提交:
git branch -b a-good-feature
git pull repository master
git checkout master
git merge a-good-feature
git commit -a
git push
回答by VonC
'git cherry-pick
' should be your answer here.
' git cherry-pick
' 应该是你的答案。
Apply the change introduced by an existing commit.
应用由现有提交引入的更改。
Do not forget to read bdonlan's answer about the consequence of cherry-picking in this post:
"Pull all commits from a branch, push specified commits to another", where:
不要忘记阅读bdonlan在这篇文章中关于挑选樱桃的后果的回答:
“从一个分支拉取所有提交,将指定的提交推送到另一个”,其中:
A-----B------C
\
\
D
becomes:
变成:
A-----B------C
\
\
D-----C'
The problem with this commit is that git considers commits to include all history before them
Where C' has a different
SHA-1
ID.
Likewise, cherry picking a commit from one branch to another basically involves generating a patch, then applying it, thus losing history that way as well.This changing of commit IDs breaks git's merging functionality among other things (though if used sparingly there are heuristics that will paper over this).
More importantly though, it ignores functional dependencies - if C actually used a function defined in B, you'll never know.
这个提交的问题是 git 认为提交包括他们之前的所有历史记录
其中 C' 具有不同的
SHA-1
ID。
同样,从一个分支到另一个分支的樱桃提交基本上涉及生成一个补丁,然后应用它,因此也会以这种方式丢失历史记录。提交 ID 的这种更改会破坏 git 的合并功能等(尽管如果谨慎使用,会有一些启发式方法可以解决这个问题)。
更重要的是,它忽略了函数依赖——如果 C 实际上使用了 B 中定义的函数,你永远不会知道.
回答by bdonlan
You can use git cherry-pick to apply a single commit by itself to your current branch.
您可以使用 git cherry-pick 将单个提交单独应用到您当前的分支。
Example: git cherry-pick d42c389f
例子: git cherry-pick d42c389f
回答by Spyder
Let's try to take an example and understand:
我们试着举个例子来理解:
I have a branch, say master, pointing to X <commit-id>, and I have a new branch pointing to Y <sha1>.
我有一个分支,比如master,指向 X <commit-id>,我有一个新分支指向 Y <sha1>。
Where Y <commit-id> = <master> branch commits - few commits
其中Y <commit-id> = <master> 分支提交 - 很少提交
Now say for Y branch I have to gap-close the commits between the master branch and the new branch. Below is the procedure we can follow:
现在说对于 Y 分支,我必须关闭主分支和新分支之间的提交。以下是我们可以遵循的程序:
Step 1:
第1步:
git checkout -b local origin/new
where local is the branch name. Any name can be given.
其中 local 是分支名称。可以给出任何名称。
Step 2:
第2步:
git merge origin/master --no-ff --stat -v --log=300
Merge the commits from master branch to new branch and also create a merge commit of log message with one-line descriptions from at most <n> actual commits that are being merged.
将主分支的提交合并到新分支,并创建日志消息的合并提交,其中包含最多 <n> 个正在合并的实际提交的单行描述。
For more information and parameters about Git merge, please refer to:
更多关于Git merge的信息和参数请参考:
git merge --help
Also if you need to merge a specific commit, then you can use:
此外,如果您需要合并特定提交,则可以使用:
git cherry-pick <commit-id>
回答by nrkkalyan
In my use case we had a similar need for CI CD. We used git flow with develop and master branches. Developers are free to merge there changes directly to develop or via a pull request from a feature branch. However to master we merge only the stable commits from the develop branch in an automated way via Jenkins.
在我的用例中,我们对 CI CD 有类似的需求。我们将 git flow 与 develop 和 master 分支一起使用。开发人员可以自由地直接合并这些更改以进行开发或通过来自功能分支的拉取请求。然而,为了掌握,我们只通过 Jenkins 以自动方式合并来自开发分支的稳定提交。
In this case doing cherry-pick is not a good option. However we create a local-branch from the commit-id then merge that local-branch to master and perform mvn clean verify(we use maven). If success then release production version artifact to nexus using maven release plugin with localCheckout=true option and pushChanges=false. Finally when everything is success then push the changes and tag to origin.
在这种情况下,挑选樱桃不是一个好选择。但是,我们从 commit-id 创建了一个本地分支,然后将该本地分支合并到 master 并执行 mvn clean verify(我们使用 maven)。如果成功,则使用带有 localCheckout=true 选项和 pushChanges=false 的 maven 发布插件将生产版本工件发布到 nexus。最后,当一切都成功时,将更改和标签推送到原点。
A sample code snippet:
示例代码片段:
Assuming you are on master if done manually. However on jenkins, when you checkout the repo you will be on the default branch(master if configured).
如果手动完成,假设您在 master 上。但是在 jenkins 上,当您检出 repo 时,您将位于默认分支上(如果已配置,则为 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
This will give you a full control with a fearless merge or conflict hell.
这将使您完全控制无畏的合并或冲突地狱。
Feel free to advise in case there is any better option.
如果有更好的选择,请随时提出建议。
回答by LarsH
The leading answers describe how to apply the changes froma specific commit to the current branch. If that's what you mean by "how to merge," then just use cherry-pick as they suggest.
主要答案描述了如何将来自特定提交的更改应用到当前分支。如果这就是“如何合并”的意思,那么就按照他们的建议使用cherry-pick。
But if you actually want a merge, i.e. you want a new commit with two parents-- the existing commit on the current branch, and the commit you wanted to apply changes from -- then a cherry-pick will not accomplish that.
但是如果你真的想要一个合并,即你想要一个有两个父级的新提交——当前分支上的现有提交,以及你想要应用更改的提交——那么樱桃挑选将无法实现这一点。
Having true merge history may be desirable, for example, if your build process takes advantage of git ancestry to automatically set version strings based on the latest tag (using git describe
).
例如,如果您的构建过程利用 git ancestry 自动设置基于最新标签的版本字符串(使用git describe
),则可能需要拥有真正的合并历史记录。
Instead of cherry-pick, you can do an actual git merge --no-commit
, and then manually adjust the index to remove any changes you don't want.
您可以做一个实际的git merge --no-commit
,然后手动调整索引以删除您不想要的任何更改,而不是挑选樱桃。
Suppose you're on branch A
and you want to merge the commit at the tip of branch B
:
假设您在分支上A
并且想要在分支的尖端合并提交B
:
git checkout A
git merge --no-commit B
Now you're set up to create a commit with two parents, the current tip commits of A
and B
. However you may have more changes applied than you want, including changes from earlier commits on the B branch. You need to undo these unwanted changes, then commit.
现在您已准备好创建具有两个父项的提交,当前提示提交为A
和B
。但是,您可能应用了比您想要的更多的更改,包括来自 B 分支上早期提交的更改。您需要撤消这些不需要的更改,然后提交。
(There may be an easy way to set the state of the working directory and the index back to way it was before the merge, so that you have a clean slate onto which to cherry-pick the commit you wanted in the first place. But I don't know how to achieve that clean slate. git checkout HEAD
and git reset HEAD
will both remove the merge state, defeating the purpose of this method.)
(可能有一种简单的方法可以将工作目录和索引的状态设置回合并之前的状态,以便您有一个干净的石板,可以首先在其上挑选您想要的提交。但是我不知道如何实现那个干净的石板。git checkout HEAD
并且git reset HEAD
都会删除合并状态,从而破坏了这种方法的目的。)
So manually undo the unwanted changes. For example, you could
所以手动撤消不需要的更改。例如,你可以
git revert --no-commit 012ea56
for each unwanted commit 012ea56
.
对于每个不需要的提交012ea56
。
When you're finished adjusting things, create your commit:
完成调整后,创建您的提交:
git commit -m "Merge in commit 823749a from B which tweaked the timeout code"
Now you have only the change you wanted, and the ancestry tree shows that you technically merged from B.
现在您只有您想要的更改,并且祖先树显示您在技术上从 B 合并。