快进合并对短暂的分支有意义,但在更复杂的历史中,非快进合并可能会使历史更容易理解,并且更容易恢复一组提交。
警告:非快进也有潜在的副作用。请查看https://sandofsky.com/blog/git-workflow.html,避免使用“检查点提交”打破平分或指责的“no-ff”,并仔细考虑它是否应该是您的默认方法master
。
(来自nvie.com,Vincent Driessen,发表“一个成功的 Git 分支模型”)
在开发中合并一个已完成的功能
完成的功能可以合并到开发分支中,以将它们添加到即将发布的版本中:
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop
该--no-ff
标志会导致合并始终创建一个新的提交对象,即使可以使用快进执行合并。这样可以避免丢失有关功能分支的历史存在的信息,并将所有添加该功能的提交组合在一起。
Jakub Narębski还提到了配置merge.ff
:
默认情况下,Git 在合并作为当前提交的后代的提交时不会创建额外的合并提交。相反,当前分支的尖端是快进的。
当设置为 时false
,这个变量告诉 Git 在这种情况下创建一个额外的合并提交(相当于--no-ff
从命令行提供选项)。
当设置为 ' only
' 时,只允许这样的快进合并(相当于--ff-only
从命令行给出选项)。
快进是默认设置,因为:
- 短期分支在 Git 中很容易创建和使用
- 短暂的分支通常会隔离许多可以在该分支内自由重组的提交
- 这些提交实际上是主分支的一部分:一旦重组,主分支就会快速转发以包含它们。
但是,如果您期望在一个主题/功能分支上进行迭代工作流(即,我合并,然后我返回此功能分支并添加更多提交),那么在主分支中仅包含合并是有用的,而不是功能分支的所有中间提交。
在这种情况下,您最终可以设置这种配置文件:
[branch "master"]
# This is the list of cmdline options that should be added to git-merge
# when I merge commits into the master branch.
# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.
# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.
mergeoptions = --no-commit --no-ff
OP在评论中添加:
我认为 [short-lived] 分支的快进有些意义,但将其设为默认操作意味着 git 假设您......经常有 [short-lived] 分支。合理的?
杰弗罗米回答:
我认为分支的生命周期因用户而异。但是,在有经验的用户中,可能倾向于拥有更多短命的分支。
对我来说,一个短暂的分支是我创建的,目的是使某个操作更容易(变基、可能或快速修补和测试),然后在我完成后立即删除。
这意味着它可能应该被吸收到它派生出来的主题分支中,并且主题分支将合并为一个分支。没有人需要知道我在内部做了什么来创建实现该给定功能的一系列提交。
更一般地说,我补充说:
这实际上取决于您的开发工作流程:
- 如果它是线性的,那么一个分支是有意义的。
- 如果您需要隔离特征并长时间处理它们并反复合并它们,那么几个分支是有意义的。
请参阅“什么时候应该分支? ”
实际上,当您考虑 Mercurial 分支模型时,它的核心是每个存储库一个分支(即使您可以创建匿名头、书签甚至命名分支)
请参阅“Git 和 Mercurial - 比较和对比”。
Mercurial 默认使用匿名轻量级代码行,在其术语中称为“heads”。
Git 使用轻量级命名分支,通过单射映射将远程存储库中的分支名称映射到远程跟踪分支的名称。
Git“强制”你命名分支(嗯,除了单个未命名的分支,这是一种称为“分离的 HEAD ”的情况),但我认为这更适用于分支繁重的工作流程,例如主题分支工作流程,意思是单个存储库范例中的多个分支。