进行 git 合并时是否可以排除特定提交?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/332528/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-10 05:59:54  来源:igfitidea点击:

Is it possible to exclude specific commits when doing a git merge?

git

提问by Readonly

Let's say that I want to merge from a release branch to the master branch and there are some commits in the release branch that I don't want to include in the master branch. Is there a way to do the merge so that one or more of those commits will not be merged?

假设我想从发布分支合并到主分支,并且发布分支中有一些我不想包含在主分支中的提交。有没有办法进行合并,以便不会合并一个或多个提交?

My strategy so far is to do the following (in master):

到目前为止,我的策略是执行以下操作(在 master 中):

git merge --no-commit release-branch
# Resolve conflicts and apply reverse patch of the commits that I don't want included
git commit # Edit commit message so that it lists the commits that have been reverse-patched

Is there a better way to do this?

有一个更好的方法吗?

采纳答案by Dustin

Create a new branch, rebase the branch interactively and drop commits you don't want, and then merge that.

创建一个新分支,以交互方式重新设置分支并删除您不想要的提交,然后合并它。

You can't take changes out of the middle of a branch without rehashing, but the right thing will happen when it sees the same changes in a later merge (e.g. from cherry-picking and what-not).

您不能在不重新散列的情况下从分支中间进行更改,但是当它在以后的合并中看到相同的更改时(例如,从cherry-picking 和what-not 中),正确的事情就会发生。

回答by fcurella

I've found a solution that works for me in the Pro Gitbook.

Pro Gitbook 中找到了一个对我有用的解决方案。

Let's say you want to exclude the file config.php.

假设您要排除文件config.php.

On branch A:

在分支 A:

  1. Create a file named .gitattributesin the same dir, with this line: config.php merge=ours. This tells git what strategy to use when merging the file. In this case it always keep your version, ie. the version on the branch you are merging into.

  2. Add the .gitattributesfile and commit

  1. 创建一个.gitattributes在同一目录中命名的文件,包含以下行:config.php merge=ours. 这告诉 git 在合并文件时使用什么策略。在这种情况下,它始终保留您的版本,即。您要合并到的分支上的版本。

  2. 添加.gitattributes文件并提交

On branch B: repeat steps 1-2

在分支 B:重复步骤 1-2

Try merging now. Your file should be left untouched.

现在尝试合并。您的文件应该保持不变。

回答by Tobias Schulte

If you have a support branch where you fix bugs and build new versions. On master you have the next version where you also build new versions frequently.

如果您有一个支持分支,您可以在其中修复错误并构建新版本。在 master 上,您有下一个版本,您也经常在其中构建新版本。

Every time you build a new version you change the version in some file, commit that new file, create a tag and push. Now merges from supportto masterwill always have conflicts in the file containing the version info.

每次构建新版本时,都会更改某个文件中的版本,提交该新文件,创建标签并推送。现在从support合并到master将在包含版本信息的文件中始终存在冲突。

If the file containing the version information onlycontains the version information, you can go with the answer of fcurella. But if it does indeed may also contain mergeable information (pom.xml, gradle.properties, MANIFEST.MF, ...), you must perform some extra action.

如果包含版本信息的文件包含版本信息,可以使用fcurella的回答。但是如果它确实也可能包含可合并的信息(pom.xml、gradle.properties、MANIFEST.MF、...),则必须执行一些额外的操作。

Lets use the following example

让我们使用以下示例

      C---D*---E---F* support
     /
A---B---G---H*---I master

where commits with stars contain only changes due to version changes that should be ignored during merge.

其中带有星号的提交仅包含由于版本更改而应在合并期间忽略的更改。

To merge supportinto masterwithout merge-conflicts due to the version builds, you can do either of the following:

要将支持合并到master而不会由于版本构建而发生合并冲突,您可以执行以下任一操作:

Multiple merge commits

多次合并提交

git checkout master
git merge C
git merge D -s ours
git merge E
git merge F -s ours

With the -s oursargument we are telling git to only record a merge without altering the workspace. This is comparable to the --record-onlyoption of svn.

通过-s ours参数,我们告诉 git 只记录合并而不改变工作区。这与svn--record-only选项相当。

The above will result in the following layout

以上将导致以下布局

      -------------C---D*---E---F* support
     /              \   \    \   \
A---B---G---H*---I---J---K----L---M master

One merge commit using cherry-pick

使用cherry-pick进行一次合并提交

git checkout master
git merge support -s ours --no-commit
git cherry-pick C E --no-commit
git commit -m 'merged support into master'

first we are starting a merge but only record that we are merging, without altering the workspace and without doing the merge commit. Then we are cherry-picking the commits to merge, again without commit. Finally we are committing the merge.

首先我们开始一个合并,但只记录我们正在合并,不改变工作区,不做合并提交。然后我们挑选要合并的提交,同样没有提交。最后,我们正在提交合并。

The above will result in the following layout

以上将导致以下布局

      C---D*---E---F* support
     /              \
A---B---G---H*---I---J master

One could even automate the cherry-picking.

人们甚至可以自动化挑选樱桃。

git checkout master
git merge support -s ours --no-commit
for id in `git log support --reverse --not HEAD --format="%H [%an] %s" |
  grep -v "bump version" |
  sed "s/\(\w*\)\s.*//g"`
do
  git cherry-pick --no-commit $id
done
git commit -m 'merged support into master'

回答by user43563

The reason why this can't be done directly is that every commit contains links to the parent commits (typically just one but several for merges). That way if you have one commit (by its SHA1 sum) the whole history is also fixed as the parents also contain links to their parents and so on. So the only way to leave out patches in the history is to write a new one. git rebase -i on a newly created branch is probably the easiest way of achieving that.

这不能直接完成的原因是每个提交都包含到父提交的链接(通常只有一个但有几个用于合并)。这样,如果您有一次提交(通过其 SHA1 总和),则整个历史记录也是固定的,因为父级还包含指向其父级的链接等等。因此,在历史中遗漏补丁的唯一方法是编写一个新补丁。在新创建的分支上执行 git rebase -i 可能是实现这一目标的最简单方法。

回答by Robert Siemer

The main question is: how do you want to represent the commits you want to skip?

主要问题是:你想如何表示你想跳过的提交?

  1. sneakily hide them (not my favorite)
  2. explicitly skip them
  3. explicitly undo them
  1. 偷偷地隐藏它们(不是我最喜欢的)
  2. 明确跳过它们
  3. 明确撤消它们

Unfortunately no. 2 is impossible to express in the history graph.

抱歉不行。2 是不可能在历史图中表达的。

No. 1 is possible, but I would neverdo that: a merge commit can contain changes. – Normally a merge commit points to the result of the merge of two more more branches: all things developed in those branches should be in the code after the merge (i.e. in the code pointed to by the merge commit). And nothing else should be in this commit.

第 1 条是可能的,但我永远不会这样做:合并提交可以包含更改。– 通常一个合并提交指向另外两个分支合并的结果:在这些分支中开发的所有东西都应该在合并之后的代码中(即在合并提交指向的代码中)。此提交中不应包含其他任何内容。

But surprise, surprise, you can change the entire code base and represent it as a merge. The effect of a merge is two-fold: it merges the history tree andit should merge two code bases. The former it does for sure (otherwise no-one calls it a merge), for the latter it might fail, e.g. when a merge conflict arose and it was resolved wrongly (then the code bases were not merged properly).

但是令人惊讶的是,您可以更改整个代码库并将其表示为合并。合并的效果有两方面:合并历史树合并两个代码库。前者肯定会(否则没有人称其为合并),后者可能会失败,例如,当出现合并冲突并且错误解决时(然后代码库没有正确合并)。

Some of the other answers suggest this hiding. I recommend the explicit way: merge plus revert commits.

其他一些答案表明这种隐藏。我推荐明确的方式:合并加还原提交。

回答by Kuznero

It's also possible to modify .git/info/attributes file and keep it inside .git folder instead of adding .gitattribute files all over that will require adding them to source control eventually.

也可以修改 .git/info/attributes 文件并将其保存在 .git 文件夹中,而不是添加 .gitattribute 文件,因为最终需要将它们添加到源代码控制中。

回答by Maze

If you only want to exclude some commits that are at the end, you can just commit to a specific commit number:

如果你只想排除一些最后的提交,你可以提交到一个特定的提交号:

git checkout partlyMergedFrom
git whatchanged
--> find the commit hash up to where you want to merge
git checkout partlyMergedInto
git merge e40a0e384f58409fe3c864c655a8d252b6422bfc
git whatchanged
--> check that you really got all the changes you want to have