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

时间:2008-12-01 22:55:21

标签: git

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

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

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

有更好的方法吗?

7 个答案:

答案 0 :(得分:105)

我找到了一个适合我的解决方案in the Pro Git book

假设您要排除文件config.php

在分支A:

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

  2. 添加.gitattributes文件并提交

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

    立即尝试合并。您的文件应保持不变。

答案 1 :(得分:43)

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

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

答案 2 :(得分:14)

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

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

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

让我们使用以下示例

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

其中明星提交仅包含因合并期间应忽略的版本更改而发生的更改。

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

多个合并提交

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

使用-s ours参数,我们告诉git只记录合并而不改变工作区。这与to the --record-only option of svn相当。

以上将导致以下布局

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

使用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'

首先我们开始合并,但只记录我们正在合并,而不改变工作空间而不进行合并提交。然后,我们正在挑选合并的提交,再次没有提交。最后我们正在进行合并。

以上将导致以下布局

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

甚至可以自动采摘樱桃。

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'

答案 3 :(得分:4)

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

答案 4 :(得分:2)

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

答案 5 :(得分:2)

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

  1. 偷偷地隐藏他们(不是我最喜欢的)
  2. 明确跳过它们
  3. 明确撤消他们
  4. 不幸的是没有。 2在历史图表中无法表达。

    没有。 1是可能的,但我永远不会这样做:合并提交可以包含更改。 - 通常,合并提交指向两个或多个分支的合并结果:在这些分支中开发的所有内容应该在合并之后的代码中(即在合并提交指向的代码中)。此提交中没有其他内容。

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

    其他一些答案表明这种隐藏。我推荐使用显式方式:merge plus revert commits。

答案 6 :(得分:1)

如果您只想排除最后的一些提交,您只需提交一个特定的提交号:

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