协慌网

登录 贡献 社区

`git merge` 和 `git merge --no-ff` 有什么区别?

使用gitk log ,我无法发现两者之间的差异。如何观察差异(使用 git 命令或某些工具)?

答案

如果检测到您当前的HEAD是您尝试合并的提交的祖先,则--no-ff标志会阻止git merge执行 “fast-forward”。快进是指 git 只是将您的分支指针移动到指向传入提交的位置,而不是构建合并提交。这种情况通常发生在没有任何局部更改的情况下执行git pull

但是,有时您希望防止此行为发生,通常是因为您希望维护特定的分支拓扑(例如,您正在合并主题分支,并且您希望确保在阅读历史记录时看起来如此)。为此,您可以传递--no-ff标志, git merge始终构建合并而不是快进。

类似地,如果你想执行git pull或使用git merge以显式快进,并且你想要在它无法快进时挽救,那么你可以使用--ff-only标志。通过这种方式,您可以不经思考地定期执行git pull --ff-only ,然后如果错误输出,您可以返回并决定是否要合并或重新绑定。

图形答案这个问题

这是一个使用git merge --no-ff的清晰解释和图解说明的网站

git merge --no-ff和git merge之间的区别

直到我看到这个,我完全迷失了 git。使用--no-ff允许某人查看历史记录以清楚地看到您检出的分支 。 (该链接指向 github 的 “网络” 可视化工具)这是另一个有插图的精彩参考 。这个参考文章很好地补充了第一个,更多地关注那些不熟悉 git 的人。


像我这样的新手的基本信息

如果你像我一样,而不是 Git-guru, 我在这里的答案描述了处理从 git 跟踪中删除文件而不从本地文件系统中删除文件,这似乎记录不清,但经常发生。另一个新的情况是获得当前的代码 ,仍然设法逃避我。


示例工作流程

我将一个软件包更新到我的网站,不得不回到我的笔记中查看我的工作流程; 我认为在这个答案中添加一个例子很有用。

我的 git 命令工作流程:

git checkout -b contact-form
(do your work on "contact-form")
git status
git commit -am  "updated form in contact module"
git checkout master
git merge --no-ff contact-form
git branch -d contact-form
git push origin master

下图:实际使用情况,包括说明。
注意:下面的输出是剪切的; git 非常冗长。

$ git status
# On branch master
# Changed but not updated:
#   (use "git add/rm <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   ecc/Desktop.php
#       modified:   ecc/Mobile.php
#       deleted:    ecc/ecc-config.php
#       modified:   ecc/readme.txt
#       modified:   ecc/test.php
#       deleted:    passthru-adapter.igs
#       deleted:    shop/mickey/index.php
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       ecc/upgrade.php
#       ecc/webgility-config.php
#       ecc/webgility-config.php.bak
#       ecc/webgility-magento.php

请注意上面的 3 件事:
1)在输出中,您可以看到 ECC 包升级的更改,包括添加新文件。
2)另请注意,我删除了两个文件(不在/ecc文件夹中),与此更改无关。而不是将这些文件删除与ecc混淆,我将在稍后创建一个不同的cleanup分支以反映这些文件的删除。
3)我没有按照我的工作流程!当我试图让 ecc 再次工作时,我忘记了 git。

下面:而不是做全包git commit -am "updated ecc package"我通常会,我只想在/ecc文件夹中添加文件。那些删除的文件并不是我的git add一部分,但因为它们已经在 git 中被跟踪,我需要从这个分支的提交中删除它们:

$ git checkout -b ecc
$ git add ecc/*
$ git reset HEAD passthru-adapter.igs
$ git reset HEAD shop/mickey/index.php
Unstaged changes after reset:
M       passthru-adapter.igs
M       shop/mickey/index.php

$ git commit -m "Webgility ecc desktop connector files; integrates with Quickbooks"

$ git checkout master
D       passthru-adapter.igs
D       shop/mickey/index.php
Switched to branch 'master'
$ git merge --no-ff ecc
$ git branch -d ecc
Deleted branch ecc (was 98269a2).
$ git push origin master
Counting objects: 22, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (14/14), 59.00 KiB, done.
Total 14 (delta 10), reused 0 (delta 0)
To git@github.com:me/mywebsite.git
   8a0d9ec..333eff5  master -> master



用于自动执行上述操作的脚本

在一天中使用过程 10 次以上,我已经开始编写批处理脚本来执行命令,所以我做了一个几乎正确的git_update.sh <branch> <"commit message">脚本来执行上述步骤。 这是该脚本的 Gist 源代码

而不是git commit -am我选择通过git status生成的 “modified” 列表中的文件,然后粘贴这个脚本中的文件。这是因为我做了几十次编辑,但想要不同的分支名称来帮助分组更改。

--no-ff选项确保不会发生快进合并,并且始终会创建新的提交对象 。如果您希望 git 维护功能分支的历史记录,这可能是理想的。 git merge --no-ff vs git merge在上面的图像中,左侧是使用git merge --no-ff之后的 git 历史的示例,右侧是使用git merge的示例,其中 ff 合并是可能的。

编辑 :此图像的先前版本仅指示合并提交的单个父项。 合并提交有多个父提交 ,git 用它来维护 “特征分支” 和原始分支的历史记录。多个父链接以绿色突出显示。