`git merge` 和 `git merge --no-ff` 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9069061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is the difference between `git merge` and `git merge --no-ff`?
提问by user1162226
Using gitk log
, I could not spot a difference between the two. How can I observe the difference (with a git command or some tool)?
使用gitk log
,我无法发现两者之间的区别。如何观察差异(使用 git 命令或某些工具)?
回答by Lily Ballard
The --no-ff
flag prevents git merge
from executing a "fast-forward" if it detects that your current HEAD
is an ancestor of the commit you're trying to merge. A fast-forward is when, instead of constructing a merge commit, git just moves your branch pointer to point at the incoming commit. This commonly occurs when doing a git pull
without any local changes.
如果该--no-ff
标志git merge
检测到您的当前HEAD
是您尝试合并的提交的祖先,则该标志会阻止执行“快进” 。快进是指 git 不构建合并提交,而是将分支指针移动到指向传入的提交。这通常发生在git pull
没有任何本地更改的情况下。
However, occasionally you want to prevent this behavior from happening, typically because you want to maintain a specific branch topology (e.g. you're merging in a topic branch and you want to ensure it looks that way when reading history). In order to do that, you can pass the --no-ff
flag and git merge
will alwaysconstruct a merge instead of fast-forwarding.
但是,有时您希望防止这种行为发生,通常是因为您希望维护特定的分支拓扑(例如,您正在合并一个主题分支,并且您希望确保它在阅读历史记录时看起来是这样)。为了做到这一点,你可以通过--no-ff
标志和git merge
将始终构造一个合并,而不是快进。
Similarly, if you want to execute a git pull
or use git merge
in order to explicitly fast-forward, and you want to bail out if it can't fast-forward, then you can use the --ff-only
flag. This way you can regularly do something like git pull --ff-only
without thinking, and then if it errors out you can go back and decide if you want to merge or rebase.
同样,如果您想执行 a git pull
or usegit merge
以显式快进,并且您想在无法快进时退出,那么您可以使用该--ff-only
标志。通过这种方式,您可以git pull --ff-only
不假思索地定期做一些事情,然后如果出错,您可以返回并决定是否要合并或变基。
回答by Chris K
Graphic answer to this question
这个问题的图形答案
Here is a sitewith a clear explanation and graphical illustration of using git merge --no-ff
:
这是一个站点,其中包含使用的清晰说明和图形说明git merge --no-ff
:
Until I saw this, I was completely lost with git. Using --no-ff
allows someone reviewing history to clearly see the branch you checked outto work on. (that link points to github's "network" visualization tool) And here is another great referencewith illustrations. This reference complements the first one nicely with more of a focus on those less acquainted with git.
直到我看到这个,我才完全迷失了 git。使用--no-ff
允许查看历史的人清楚地看到您签出的分支。(该链接指向 github 的“网络”可视化工具)这是另一个很好的插图参考。这个参考很好地补充了第一个,更多地关注那些不太熟悉 git 的人。
Basic info for newbs like me
像我这样的新手的基本信息
If you are like me, and not a Git-guru, my answer heredescribes handling the deletion of files from git's tracking without deleting them from the local filesystem, which seems poorly documented but often occurrence. Another newb situation is getting current code, which still manages to elude me.
如果你像我一样,而不是 Git 专家,我在这里的回答描述了如何处理从 git 跟踪中删除文件而不从本地文件系统中删除它们,这似乎记录不全,但经常发生。另一个新手情况是获取当前代码,但它仍然设法避开了我。
Example Workflow
示例工作流
I updated a package to my website and had to go back to my notes to see my workflow; I thought it useful to add an example to this answer.
我在我的网站上更新了一个包,不得不回到我的笔记中查看我的工作流程;我认为在这个答案中添加一个例子很有用。
My workflow of git commands:
我的 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
Below:actual usage, including explanations.
Note: the output below is snipped; git is quite verbose.
下面:实际使用,包括解释。
注意:下面的输出被剪断了;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
Notice 3 things from above:
1) In the output you can see the changes from the ECC package's upgrade, including the addition of new files.
2) Also notice there are two files (not in the /ecc
folder) I deleted independent of this change. Instead of confusing those file deletions with ecc
, I'll make a different cleanup
branch later to reflect those files' deletion.
3) I didn't follow my workflow! I forgot about git while I was trying to get ecc working again.
请注意上面的 3 件事:
1) 在输出中,您可以看到 ECC 包升级的更改,包括添加新文件。
2) 另请注意,/ecc
我删除了与此更改无关的两个文件(不在文件夹中)。ecc
我不会将这些文件删除与 混淆,而是稍后创建一个不同的cleanup
分支来反映这些文件的删除。
3)我没有遵循我的工作流程!当我试图让 ecc 再次工作时,我忘记了 git。
Below: rather than do the all-inclusive git commit -am "updated ecc package"
I normally would, I only wanted to add the files in the /ecc
folder. Those deleted files weren't specifically part of my git add
, but because they already were tracked in git, I need to remove them from this branch's commit:
下面:git commit -am "updated ecc package"
我不想做我通常会做的全包,我只想在文件/ecc
夹中添加文件。那些删除的文件并不是我的 .git 文件的一部分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 [email protected]:me/mywebsite.git
8a0d9ec..333eff5 master -> master
Script for automating the above
用于自动执行上述操作的脚本
Having used this process 10+ times in a day, I have taken to writing batch scripts to execute the commands, so I made an almost-proper git_update.sh <branch> <"commit message">
script for doing the above steps. Here is the Gist sourcefor that script.
一天使用这个过程超过 10 次,我已经开始编写批处理脚本来执行命令,所以我制作了一个几乎正确的git_update.sh <branch> <"commit message">
脚本来执行上述步骤。这是该脚本的 Gist 源代码。
Instead of git commit -am
I am selecting files from the "modified" list produced via git status
and then pasting those in this script. This came about because I made dozens of edits but wanted varied branch names to help group the changes.
相反的git commit -am
,我选择从“修饰”列表,经由产生的文件git status
,然后粘贴那些这个脚本。这是因为我进行了数十次编辑,但想要不同的分支名称来帮助对更改进行分组。
回答by Premraj
Explicit Merge: Creates a new merge commit. (This is what you will get if you used --no-ff
.)
显式合并:创建一个新的合并提交。(如果你使用了,这就是你会得到的--no-ff
。)
Fast Forward Merge:Forward rapidly, without creating a new commit:
Fast Forward Merge:快速转发,无需创建新提交:
Rebase: Establish a new base level:
Rebase:建立一个新的基础级别:
Squash:Crush or squeeze (something) with force so that it becomes flat:
Squash:用力挤压或挤压(某物)使其变平:
回答by Daniel Smith
The --no-ff
option ensures that a fast forward merge will not happen, and that a new commit object will always be created. This can be desirable if you want git to maintain a history of feature branches.
In the above image, the left side is an example of the git history after using
git merge --no-ff
and the right side is an example of using git merge
where an ff merge was possible.
该--no-ff
选项确保不会发生快进合并,并且始终会创建新的提交对象。如果您希望 git 维护功能分支的历史记录,这可能是可取的。
在上图中,左侧是使用后的 git 历史示例,
git merge --no-ff
右侧git merge
是可以进行 ff 合并的使用示例。
EDIT: A previous version of this image indicated only a single parent for the merge commit. Merge commits have multiple parent commitswhich git uses to maintain a history of the "feature branch" and of the original branch. The multiple parent links are highlighted in green.
编辑:此图像的先前版本仅指示合并提交的单个父级。合并提交有多个父提交,git 使用这些提交来维护“功能分支”和原始分支的历史记录。多个父链接以绿色突出显示。
回答by Parris Varney
This is an old question, and this is somewhat subtly mentioned in the other posts, but the explanation that made this click for me is that non fast forward merges will require a separate commit.
这是一个老问题,在其他帖子中有些巧妙地提到了这一点,但是让我点击的解释是非快进合并需要单独提交。
回答by jsina
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
--no-ff 标志导致合并总是创建一个新的提交对象,即使合并可以用快进执行。这避免丢失有关功能分支的历史存在的信息,并将所有一起添加功能的提交组合在一起