gitk log
,我无法发现在使用git merge
和git merge --no-ff
之间的区别。如何通过git命令或一些工具观察到这种区别?gitk log
,我无法发现在使用git merge
和git merge --no-ff
之间的区别。如何通过git命令或一些工具观察到这种区别?--no-ff
标记防止git merge
执行“快进”操作,如果检测到你当前的HEAD
是要合并的提交的祖先,则不会进行快进。快进是指,Git不构造合并提交,而只是将你的分支指针移动到指向传入的提交。这通常在没有任何本地更改的情况下执行git pull
时发生。--no-ff
标记,git merge
将始终构建合并而不是快进。git pull
或使用git merge
以明确进行快进,并且希望如果无法快进则退出,则可以使用--ff-only
标记。这样,你就可以经常执行像git pull --ff-only
这样的操作,而不必思考,如果出现错误,你可以回退并决定是否合并或变基。gitk
或 git log --graph
中可以清楚地看出快进合并没有创建合并提交,而非快进合并则有。 - Cascabel--no-ff
从 feature 分支合并到 develop 或者从 develop 合并到 master,可以说与合并 pull request 类似,这样说是否公平? - Merlin -they-them-这里是一个网站,清晰地解释和图示了如何使用git merge --no-ff
:
在看到这个之前,我完全摸不着头脑。使用--no-ff
允许审核历史记录的人清晰地看到你所检出的分支进行工作。 (该链接指向 github 的“network”可视化工具) 这里还有另一个精彩的参考资料,配有插图。这份参考资料与第一份相互补充,更专注于那些对 git 不太熟悉的人。
如果你像我一样,不是 Git 大师,请参考我在这里的答案,描述了如何处理从 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
从上面可以注意到三件事:
1)在输出中,您可以看到ECC软件包升级的更改情况,包括添加了新文件。
2)还要注意有两个文件(不在/ecc
文件夹中),我独立于此更改删除了这些文件。为了避免将那些文件删除与ecc
混淆,我稍后会创建一个不同的cleanup
分支以反映这些文件的删除情况。
3)我没有按照我的工作流程进行操作!当我尝试重新使ecc工作时,我忘记了git。
下面:与其像我通常会做的那样使用全包含的git commit -am“updated ecc package”
,我只想添加/ecc
文件夹中的文件。那些已经被跟踪在git中的已删除文件并不是我特别加入git add
的一部分,但因为它们已经被跟踪,所以我需要将它们从这个分支的提交中移除:
$ 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 <分支> <"提交信息">
脚本以完成以上步骤。 这是该脚本的Gist源代码。
与其使用 git commit -am
命令,我会从通过 git status
生成的 "修改" 列表中选择文件,然后将它们粘贴到这个脚本中。这是因为我做了几十个编辑,但想要不同的分支名称来帮助分组更改。
--no-ff
选项合并后,您仍然可以安全地删除分支吗? - Andy Fleming显式合并(又称为非快进合并):创建一个新的合并提交。(如果你使用了 --no-ff
,就会得到这个结果。)
注意:Rebase合并与快进合并相似,但与快进合并不同的是,分支的HEAD必须是我们要合并的提交的祖先。
压缩:以力量将(某物)压扁或挤压使其变平:
--no-ff
选项确保不会进行快速向前合并,而且始终会创建新的提交对象。如果您希望 git 维护功能分支的历史记录,则这是有利的。
在上图中,左侧是使用 git merge --no-ff
后的 git 历史记录示例,右侧是使用 git merge
的示例,其中可以进行 ff 合并。
编辑:此前版本的图片只显示合并提交的单个父提交。合并提交具有多个父提交,git 使用它们来维护 "功能分支" 和原始分支的历史记录。多个父链接以绿色突出显示。git merge
之后,它与主分支完全相同,因为所有提交都已快进到主分支。在git日志中,您会看到feature和master指向相同的提交。在git merge --no-ff
的情况下,feature分支将缺少最后一个合并提交。 - cb2这是一个老问题,其他帖子中可能会略微提及,但使我恍然大悟的解释是非快进合并需要一个单独的提交。
git merge --no-ff ecc
,则在主分支的 git log
中将出现一个额外的合并提交。如果主分支指向了提交ecc所在的直接祖先,则从技术上讲这是不必要的,但通过指定--no-ff选项,您正在强制创建该合并提交。它的标题将为:Merge branch 'ecc'
。 - Ankur Agarwal--no-ff标志意味着即使可以使用快进模式合并,合并操作始终会创建一个新的提交对象。这样可以避免丢失有关功能分支历史存在的信息,并将一起添加功能的所有提交组合在一起。
其他回答已经很好地说明了--no-ff
会产生一个合并提交。这将保留有关功能分支的历史信息,因为功能分支经常被清理和删除。
这个答案可能提供了何时使用或不使用--no-ff
的上下文。
--no-ff
示例:
$ git checkout -b NewFeature
[work...work...work]
$ git commit -am "New feature complete!"
$ git checkout main
$ git merge --no-ff NewFeature
$ git push origin main
$ git branch -d NewFeature
--no-ff
示例:
$ git checkout -b NewFeature
[work...work...work]
[New changes made for HotFix in the main branch! Lets get them...]
$ git commit -am "New feature in progress"
$ git pull origin main
[shortcut for "git fetch origin main", "git merge origin main"]
什么是快进(fast-forward)?
当您对比所选分支之前的分支进行合并或变基时,Git 所执行的操作就是快进。
假设有如下分支设置:
您拥有两个分支都引用同一次提交。它们都具有完全相同的历史记录。现在在feature 分支上进行了提交。
在此时,master 分支仍然引用 7ddac6c,而 feature 分支已经向前移动了两个提交。可以认为 feature 分支现在领先于 master 分支。
现在很容易看出当 Git 进行快进时会发生什么。它只需将 master 分支更新为引用与 feature 分支相同的精确提交即可。由于来自 feature 的提交已包含所有必要的更改,因此不会对存储库本身进行任何更改。
此时您的存储库历史记录应如下所示:
什么情况下不会发生快进?
当原始分支和新分支中都进行了更改时,就不会发生快进。
如果将 feature 分支合并或变基到 master 上,由于树已经分叉,Git 将无法进行快进。考虑到 Git 提交是不可变的,因此 Git 无法在不更改其父引用的情况下将 feature 分支提交合并到 master 上。