使用gitk日志,我无法发现git merge和git merge -no-ff的效果之间的区别。我如何观察差异(使用git命令或一些工具)?


当前回答

——no-ff标志阻止git merge执行“快进”,如果它检测到你当前的HEAD是你试图合并的提交的祖先。快进是指git不构造合并提交,而是将分支指针指向传入的提交。这通常发生在没有任何本地更改的情况下进行git拉取时。

然而,有时你想防止这种行为发生,通常是因为你想维护一个特定的分支拓扑(例如,你正在合并一个主题分支,你想确保它在读取历史记录时看起来是那样的)。为了做到这一点,你可以传递——no-ff标志,git merge将始终构造一个merge而不是快进。

类似地,如果你想执行git pull或使用git merge来显式快进,如果不能快进,你想退出,那么你可以使用——ff-only标志。这样你就可以不假思索地定期执行git pull—ff-only之类的操作,然后如果它出错,你就可以返回并决定是合并还是重基。

其他回答

合并策略

显式合并(又名非快进):创建一个新的合并提交。(这是你使用no-ff后得到的结果。)

快速向前合并:快速向前,不创建新的提交:

Rebase:建立一个新的基准面:

Squash:用力压碎或挤压(某物)使其变平:

其他答案很好地表明——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

将变更从main分支合并到feature分支:leave off—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"]

——no-ff标志阻止git merge执行“快进”,如果它检测到你当前的HEAD是你试图合并的提交的祖先。快进是指git不构造合并提交,而是将分支指针指向传入的提交。这通常发生在没有任何本地更改的情况下进行git拉取时。

然而,有时你想防止这种行为发生,通常是因为你想维护一个特定的分支拓扑(例如,你正在合并一个主题分支,你想确保它在读取历史记录时看起来是那样的)。为了做到这一点,你可以传递——no-ff标志,git merge将始终构造一个merge而不是快进。

类似地,如果你想执行git pull或使用git merge来显式快进,如果不能快进,你想退出,那么你可以使用——ff-only标志。这样你就可以不假思索地定期执行git pull—ff-only之类的操作,然后如果它出错,你就可以返回并决定是合并还是重基。

——no-ff标志导致合并总是创建一个新的提交对象,即使合并可以用快进执行。这避免了丢失关于特性分支的历史存在信息,并将所有添加了该特性的提交组合在一起

这个问题的形象答案

这里有一个网站,有一个清晰的解释和图形说明使用git合并-no-ff:

在我看到这个之前,我完全被git迷住了。使用——no-ff允许查看历史记录的人清楚地看到您签出要处理的分支。(链接指向github的“网络”可视化工具)这里是另一个很好的参考插图。这篇参考文献很好地补充了第一个参考文献,更多地关注那些不太熟悉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混淆,我稍后将创建一个不同的清理分支来反映这些文件的删除。 3)我没有遵循我的工作流程!当我试图让ecc再次工作时,我忘记了git。

以下:而不是像通常那样做所有的git commit -am“更新的ecc包”,我只想在/ecc文件夹中添加文件。那些被删除的文件并不是我git添加的一部分,但因为它们已经在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,我从“modified”列表中选择文件,通过git状态产生,然后粘贴在这个脚本中。这是因为我做了几十个编辑,但想要不同的分支名称来帮助分组更改。