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

bq9c1y66  于 2022-11-20  发布在  Git
关注(0)|答案(8)|浏览(395)

假设我想从release分支合并到master分支,而release分支中有一些提交我不想包含在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

有没有更好的方法?

x33g5p2x

x33g5p2x1#

我在 Pro Git 书中找到了适合我的解决方案。
假设您要排除文件config.php
在分支A上:
1.在同一目录中创建一个名为.gitattributes的文件,其中包含以下行:config.php merge=ours。这告诉git合并文件时使用什么策略。在这种情况下,它总是保留你的版本,即你要合并到的分支上的版本。
1.添加.gitattributes文件并提交
在分支B上:重复步骤1-2
现在尝试合并。您的文件应该保持不变。

ewm0tg9j

ewm0tg9j2#

创建一个新的分支,以交互方式重定分支的基,丢弃不需要的提交,然后合并它们。
如果不进行重新散列,就不能从分支中间取出更改,但是当它在以后的合并中看到相同的更改时(例如,从樱桃采摘和什么不是),就会发生正确的事情。

balp4ylt

balp4ylt3#

如果你有一个支持分支,在那里你修复bug并构建新版本。在master上,你有下一个版本,在那里你也经常构建新版本。
每次你构建一个新版本的时候,你都会改变某个文件的版本,提交这个新文件,创建一个标签并推送。现在从 supportmaster 的合并总是会在包含版本信息的文件中产生冲突。
如果包含版本信息的文件包含版本信息,您可以使用fcurela的答案,但如果它确实还包含可合并的信息(pom.xml、gradle.properties、MANIFEST.MF ...),则必须执行一些额外的操作。
让我们使用以下示例

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

其中带星号的提交只包含由于版本更改而导致的更改,这些更改在合并期间应被忽略。
要将 support 合并到 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'
7y4bm7vi

7y4bm7vi4#

之所以不能直接这样做,是因为每个提交都包含指向父提交的链接(通常只有一个,但合并时有多个)。(通过其SHA1和)整个历史记录也是固定的,因为父进程也包含到它们的父进程的链接等等。所以在历史记录中删除补丁的唯一方法是编写一个新的补丁。git rebase -i可能是实现这一点的最简单方法。

mspsb9vt

mspsb9vt5#

也可以修改.git/info/attributes文件,并将其保存在.git文件夹中,而不是将.gitattribute文件添加到所有地方,最终需要将它们添加到源代码管理中。

rbpvctlc

rbpvctlc6#

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

1.偷偷地把它们藏起来(不是我的最爱)
1.显式跳过它们
1.显式撤消它们
不幸的是2号是不可能在历史图中表达出来的。
第一名是可能的,但我绝对不会这么做:合并提交可以包含更改。-通常合并提交指向两个以上分支的合并结果:在那些分支中开发的所有东西都应该在合并后的代码中(即在合并提交所指向的代码中)。2并且在这个提交中不应该有其他东西。
但是,令人惊讶的是,你可以改变整个代码库,并将其表示为合并。合并的效果有两个方面:它合并了历史树 * 和 * 它应该合并两个代码库。前者肯定会合并(否则没有人称之为合并),对于后者,它可能会失败,例如,当合并冲突出现时,它被错误地解决(然后代码库没有被正确合并)。
其他一些答案也暗示了这种隐藏,我建议你用明确的方式:合并和还原提交。

6yt4nkrj

6yt4nkrj7#

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

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
km0tfn4u

km0tfn4u8#

为了避免覆盖@ fcurela的答案所遇到的问题,首先定义一个合并驱动程序,它总是支持我们当前版本的文件,通过使用现有的true命令。我们将这个驱动程序称为我们的驱动程序,以保持与类似的合并策略一致:
git config --global merge.ours.driver true
然后我们可以实现@fcurella解决方案:
假设您要排除文件.env
在分支A上(例如主):
1.在同一目录下创建一个名为 .gitattributes 的文件,并使用以下行:

.env merge=ours

这会告诉git合并文件时使用什么策略。在这种情况下,它总是保留你的版本,即你要合并到的分支上的版本。
1.添加.gitattributes文件并提交
在分支B上(例如开发):重复步骤1-2
现在尝试合并。您的文件应该保持不变。
阅读this以了解更多说明

相关问题