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

时间:2022-06-15 15:16:57

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):

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

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?

有一个更好的方法吗?

7 个解决方案

#1


42  

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).

如果不进行重新划分,你就不能从分支的中间进行更改,但是当它在后来的合并中看到相同的变化时会发生正确的事情(例如,从樱桃采摘和什么不是)。

#2


102  

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

我在Pro Git书中找到了适合我的解决方案。

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

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

On branch A:

在分支A上:

  1. Create a file named .gitattributes in 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.

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

  2. Add the .gitattributes file and commit

    添加.gitattributes文件并提交

On branch B: repeat steps 1-2

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

Try merging now. Your file should be left untouched.

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

#3


13  

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 support to master will always have conflicts in the file containing the version info.

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

If the file containing the version information only contains 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 support into master without 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 ours argument we are telling git to only record a merge without altering the workspace. This is comparable to the --record-only option of svn.

使用-s我们的参数,我们告诉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

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.*/\1/g"`
do
  git cherry-pick --no-commit $id
done
git commit -m 'merged support into master'

#4


4  

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可能是实现这一目标的最简单方法。

#5


2  

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文件,这些文件最终都需要将它们添加到源代码控制中。

#6


2  

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

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

  1. sneakily hide them (not my favorite)
  2. 偷偷地隐藏他们(不是我最喜欢的)

  3. explicitly skip them
  4. 明确跳过它们

  5. explicitly undo them
  6. 明确撤消它们

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

很不幸的是,不行。 2在历史图表中是不可能表达的。

No. 1 is possible, but I would never do 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 and it 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.

其他一些答案表明这种隐藏。我建议使用显式方式:merge plus revert commit。

#7


1  

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

#1


42  

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).

如果不进行重新划分,你就不能从分支的中间进行更改,但是当它在后来的合并中看到相同的变化时会发生正确的事情(例如,从樱桃采摘和什么不是)。

#2


102  

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

我在Pro Git书中找到了适合我的解决方案。

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

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

On branch A:

在分支A上:

  1. Create a file named .gitattributes in 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.

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

  2. Add the .gitattributes file and commit

    添加.gitattributes文件并提交

On branch B: repeat steps 1-2

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

Try merging now. Your file should be left untouched.

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

#3


13  

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 support to master will always have conflicts in the file containing the version info.

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

If the file containing the version information only contains 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 support into master without 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 ours argument we are telling git to only record a merge without altering the workspace. This is comparable to the --record-only option of svn.

使用-s我们的参数,我们告诉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

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.*/\1/g"`
do
  git cherry-pick --no-commit $id
done
git commit -m 'merged support into master'

#4


4  

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可能是实现这一目标的最简单方法。

#5


2  

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文件,这些文件最终都需要将它们添加到源代码控制中。

#6


2  

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

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

  1. sneakily hide them (not my favorite)
  2. 偷偷地隐藏他们(不是我最喜欢的)

  3. explicitly skip them
  4. 明确跳过它们

  5. explicitly undo them
  6. 明确撤消它们

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

很不幸的是,不行。 2在历史图表中是不可能表达的。

No. 1 is possible, but I would never do 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 and it 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.

其他一些答案表明这种隐藏。我建议使用显式方式:merge plus revert commit。

#7


1  

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