git - 为什么 git 默认执行快进 merge ?

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

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

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

所以展望 future :我是唯一一个从事这个项目的人。如果我使用 git 的默认方法(快进 merge ),我的历史将导致一个巨大的主分支。 没有人知道我为每个功能使用了一个单独的分支,因为最后我将只有那个巨大的 master 分支。这样会不会显得不专业?

根据这个推理,我不想快进 merge ,也看不出为什么它是默认设置。这有什么好处?

最佳答案

快进 merge 对短期分支有意义,但在更多 complex history 中,非快进 merge 可能使历史更容易理解,并且更容易还原一组提交。

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

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

Incorporating a finished feature on develop

Finished features may be merged into the develop branch to add them to the upcoming release:

$ 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

The --no-ff flag causes the merge to always create a new commit object, even if the merge could be performed with a fast-forward. This avoids losing information about the historical existence of a feature branch and groups together all commits that together added the feature.

Jakub Narębski还有mentions config merge.ff :

By default, Git does not create an extra merge commit when merging a commit that is a descendant of the current commit. Instead, the tip of the current branch is fast-forwarded.
When set to false, this variable tells Git to create an extra merge commit in such a case (equivalent to giving the --no-ff option from the command line).
When set to 'only', only such fast-forward merges are allowed (equivalent to giving the --ff-only option from the command line).


默认快进是因为:

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

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

在这种情况下,您最终可以设置 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 在评论中添加:

I see some sense in fast-forward for [short-lived] branches, but making it the default action means that git assumes you... often have [short-lived] branches. Reasonable?

杰弗罗米回答:

I think the lifetime of branches varies greatly from user to user. Among experienced users, though, there's probably a tendency to have far more short-lived branches.

To me, a short-lived branch is one that I create in order to make a certain operation easier (rebasing, likely, or quick patching and testing), and then immediately delete once I'm done.
That means it likely should be absorbed into the topic branch it forked from, and the topic branch will be merged as one branch. No one needs to know what I did internally in order to create the series of commits implementing that given feature.

更一般地说,我补充说:

it really depends on your development workflow:

  • if it is linear, one branch makes sense.
  • If you need to isolate features and work on them for a long period of time and repeatedly merge them, several branches make sense.

See "When should you branch?"

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

Mercurial, by default, uses anonymous lightweight codelines, which in its terminology are called "heads".
Git uses lightweight named branches, with injective mapping to map names of branches in remote repository to names of remote-tracking branches.
Git "forces" you to name branches (well, with the exception of a single unnamed branch, which is a situation called a "detached HEAD"), but I think this works better with branch-heavy workflows such as topic branch workflow, meaning multiple branches in a single repository paradigm.

关于git - 为什么 git 默认执行快进 merge ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2850369/

相关文章:

windows - 如何在 Windows git hooks 中使用 cygwin 路径?

Git Discipline : combining multiple feature branches, 但仍将它们分开?

git - 查找用于 merge 提交的 merge 策略?

git - 在git中查看对已删除文件的更改

git - 如何 "pull request"一个特定的提交

git - 我怎么能责怪 Git 中删除的文件?

亚搏体育appGitLab CI : Get source branch after merge-request has been accepted

Git 更改分支,但不更改工作区中的文件

issue-tracking - git 工作流程中的发布编号

git - 临时 merge 其他分支到我当前的分支