为什么git默认执行快进合并?

时间:2010-05-17 15:26:16

标签: git git-branch git-merge fast-forward

来自mercurial,我使用分支来组织功能。 当然,我也想在我的历史中看到这种工作流程。

我使用git开始了我的新项目并完成了我的第一个功能。合并该功能时,我意识到git使用快进,即如果可能,它会将我的更改直接应用到主分支,并忘记我的分支。

所以想想未来:我是唯一一个从事这个项目的人。如果我使用git的默认方法(快进合并),我的历史将导致一个巨大的主分支。 没有人知道我为每个功能使用了一个单独的分支,因为最后我只有那个巨大的主分支。这看起来不专业吗?

通过这种推理,我不想要快进合并,也不知道为什么它是默认的。这有什么好处?

2 个答案:

答案 0 :(得分:705)

快速合并对于短期分支是有意义的,但是在更多complex history中,非快进合并可以使历史更容易理解,并且更容易恢复一组提交。

警告:非快速转发也有潜在的副作用。请查看https://sandofsky.com/blog/git-workflow.html,避免使用“检查点提交”的'no-ff'来打破平分或责备,并仔细考虑它是否应该是master的默认方法。

alt text
(来自nvie.comVincent Driessen,发布“A successful Git branching model”)

  

将完成的功能纳入开发

     

已完成的功能可以合并到开发分支中,以将它们添加到即将发布的版本中:

$ 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ębskimentions config merge.ff

  

默认情况下,Git在合并作为当前提交后代的提交时不会创建额外的合并提交。相反,当前分支的提示是快进的   设置为false时,此变量告诉Git在这种情况下创建额外的合并提交(相当于从命令行提供--no-ff选项)。
  设置为“only”时,仅允许此类快进合并(相当于从命令行提供--ff-only选项。)


快进是默认值,因为:

  • 在Git
  • 中很容易创建和使用短命分支
  • 短命分支通常会隔离许多可以在该分支内自由重组的提交
  • 这些提交实际上是主分支的一部分:一旦重新组织,主分支将被快速转发以包含它们。

但是如果你预期一个主题/功能分支上的迭代工作流(即我合并,然后我回到这个功能分支并添加一些更多的提交),那么在主分支中仅包含合并是有用的,而不是功能分支的所有中间提交。

在这种情况下,您最终可以设置this kind of config file

[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在评论中添加:

  

我在[短命]分支的快进中看到了某种意义,但是将其作为默认动作意味着git假设你...通常有[短命]分支。合理?

Jefromi回答:

  

我认为分支的生命周期因用户而异。然而,在有经验的用户中,可能存在更多短期分支的趋势。

     

对我来说,一个短命分支是我创建的一个分支,以便使某个操作更容易(重新定位,可能,或快速修补和测试),然后立即删除一次我'完了。
  这意味着它可能应该被吸收到它从分叉的主题分支中,并且主题分支将合并为一个分支。没有人需要知道我在内部做了什么来创建实现给定功能的一系列提交。

更一般地说,我补充说:

  

这实际上取决于您的development workflow

     
      
  • 如果它是线性的,那么一个分支是有意义的。
  •   
  • 如果您需要隔离功能并长时间处理它们并反复合并它们,那么有几个分支是有意义的。
  •   
     

请参阅“When should you branch?

实际上,当您考虑Mercurial分支模型时,它位于核心one branch per repository(即使您可以创建anonymous heads, bookmarks and even named branches
请参阅"Git and Mercurial - Compare and Contrast"

  

默认情况下,Mercurial使用匿名的轻量级代码行,在其术语中称为“head”   Git使用轻量级命名分支,使用内射映射将远程存储库中分支的名称映射到远程跟踪分支的名称   Git“强迫”你命名分支(好吧,除了一个未命名的分支,这种情况称为“detached HEAD”),但我认为这对于分支繁重的工作流程(如主题分支)更有效工作流,意味着单个存储库范例中的多个分支。

答案 1 :(得分:41)

让我在VonCvery comprehensive answer上展开一点:


首先,如果我没记错的话,Git默认情况下不会在快进情况下创建合并提交的事实来自于考虑单分支“相同的存储库”,其中相互拉动用于同步这两个存储库(在大多数用户的文档中,您可以找到作为第一个示例的工作流,包括“The Git User's Manual”和“Version by Example by Example” )。在这种情况下,您不使用pull来合并完全实现的分支,您可以使用它来跟上其他工作。当您碰巧保存并存储在存储库中时,您不希望出现短暂且不重要的事实,并保存以供将来使用。

请注意,功能分支的有用性以及在单个存储库中具有多个分支的功能仅在稍后出现,具有良好的合并支持的VCS的更广泛使用以及尝试各种基于合并的工作流。这就是为什么例如Mercurial最初只支持每个存储库一个分支(以及用于跟踪远程分支的匿名提示),如旧版“Mercurial:The Definitive Guide”中所示。


其次,当遵循最佳做法使用功能分支时,即功能分支应该全部从稳定版本(通常是从上次发布)开始,以便能够-pick并选择要合并的功能,通过选择要合并的功能分支,您通常不处于快进状态 ...这使得这个问题没有实际意义。合并第一个分支时,您需要担心创建一个真正的合并而不是快进(假设您没有直接在'master'上放置单个提交更改);所有其他后来的合并当然都是非快进的情况。

HTH