在进行 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

还有更好的办法吗?

72558 次浏览

创建一个新的分支,交互式地重新设置分支的基础,删除不需要的提交,然后合并它。

你不能在不重新散列的情况下从一个分支中取出变更,但是当它在稍后的合并中看到相同的变更时,正确的事情就会发生(例如从初始化和其他)。

之所以不能直接做到这一点,是因为每个提交都包含到父提交的链接(通常只有一个,但对于合并来说有几个)。这样,如果您有一个提交(通过它的 SHA1和) ,整个历史也是固定的,因为父级也包含到父级的链接等等。所以在历史中遗漏补丁的唯一方法就是写一个新的。Git rebase-i 在一个新创建的分支上可能是实现这一点的最简单方法。

我找到了一个对我有效的解决方案。

假设要排除文件 config.php

在分行 A:

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

  2. 添加 .gitattributes文件并提交

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

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

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

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

也可以修改。Git/info/properties 文件,并将其保存在内部。Git 文件夹而不是添加。到处都是 gittribute 文件,最终需要将它们添加到源代码管理中。

如果您有一个支持分支,可以在其中修复 bug 并构建新版本。在 master 上,您有下一个版本,在这个版本中,您还需要频繁地构建新版本。

每次构建新版本时,都要更改某个文件中的版本,提交该新文件,创建标记并推送。现在从 支持师父的合并在包含版本信息的文件中总是有冲突。

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

让我们使用以下示例

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

其中星号提交只包含由于版本更改而发生的更改,这些更改在合并期间应该忽略。

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

多次合并提交

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

使用 -s ours参数,我们告诉 git 只记录合并,而不改变工作区。这是可比的 到 svn 的 --record-only选项

以上将导致以下布局

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

使用初选提交一次合并

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'

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

  1. 偷偷地把它们藏起来(不是我的最爱)
  2. 明确地跳过它们
  3. 明确地撤销它们

不幸的是,2号不可能在历史图表中表示出来。

第一个是可能的,但我会 永远不会这样做: 合并提交可以包含更改。通常情况下,一个合并提交指向另外两个分支的合并结果: 在这些分支中开发的所有内容都应该在合并后的代码中(也就是说,在合并提交指向的代码中)。没有其他的东西应该在这个承诺。

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

其他一些答案表明了这种隐藏。我推荐显式的方法: 合并加上恢复提交。

为了避免在使用 @ fcurella的回答时遇到覆盖问题,首先通过使用现有的 true 命令定义一个总是有利于文件当前版本的合并驱动程序。为了与类似的合并策略保持一致,我们将把这个驱动程序称为我们的:

git config --global merge.ours.driver true

之后,我们可以实施 @ fcurella解决方案:

假设您希望排除.env 文件

在分支 A (例如硕士) :

  1. 在同一个目录中创建一个名为 。 gittribute的文件,如下所示:

    .env merge=ours
    

    这告诉 git 在合并文件时使用什么策略。在这种情况下,它总是保持你的版本。要合并到的分支上的版本。

  2. 添加. gitproperties 文件并提交

对于分支 B (例如开发) : 重复步骤1-2

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

阅读 这个以获得进一步的解释