git的fast-forward在之前的文章有介紹過,但是介紹的不細:
http://www.cnblogs.com/charlesblc/p/5953066.html
fast-forward方式就是當條件允許的時候,git直接把HEAD指針指向合並分支的頭,完成合並。屬於“快進方式”,不過這種情況如果刪除分支,則會丟失分支信息。
因為在這個過程中沒有創建commit
squash 是用來把一些不必要commit進行壓縮,比如說,你的feature在開發的時候寫的commit很亂,那么我們合並的時候不希望把這些歷史commit帶過來,
於是使用--squash進行合並,此時文件已經同合並后一樣了,但不移動HEAD,不提交。需要進行一次額外的commit來“總結”一下,然后完成最終的合並。
--no-ff指的是強行關閉fast-forward方式。

有這篇文章詳細復習一下 (Link)
通常,合並分支時,如果可能,Git會用Fast forward模式,但這種模式下,刪除分支后,會丟掉分支信息。
如果要強制禁用Fast forward模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支信息。
實戰一下--no-ff方式的git merge:
首先,仍然創建並切換dev分支:
$ git checkout -b dev
Switched to a new branch 'dev'
修改readme.txt文件,並提交一個新的commit:
$ git add readme.txt
$ git commit -m "add merge"
[dev 6224937] add merge
1 file changed, 1 insertion(+)
現在,我們切換回master:
$ git checkout master
Switched to branch 'master'
准備合並dev分支,請注意--no-ff參數,表示禁用Fast forward:
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
因為本次合並要創建一個新的commit,所以加上-m參數,把commit描述寫進去。
合並后,我們用git log看看分支歷史:
$ git log --graph --pretty=oneline --abbrev-commit
* 7825a50 merge with no-ff
|\
| * 6224937 add merge
|/
* 59bc1cb conflict fixed
...
可以看到,不使用Fast forward模式,merge后就像這樣:

關於默認的fast-forward的,上面引文沒有詳述。基本就是看不出有從其他分支合並過來的信息,只能看到每個commit實際的信息。如果其他分支丟失了,分支合並的信息就丟失了。
我自己試了一下 默認的有fast-forward的情況。如下:
$ git checkout -b testff
Switched to a new branch 'testff'
$ vi readme
$ git add readme
$ git commit readme
test ff
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
# Explicit paths specified without -i or -o; assuming --only paths...
# On branch testff
# Changes to be committed:
# new file: readme
#
...
".git/COMMIT_EDITMSG" [converted] 8L, 282C written
[testff 5a036ee] test ff
1 file changed, 1 insertion(+)
create mode 100644 readme
$ git checkout -b newtestff
Switched to a new branch 'newtestff'
$ git merge testff
Already up-to-date.
$ git diff testff newtestff
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git pull
$ git checkout -b newff
Switched to a new branch 'newff'
$ git checkout newff
Already on 'newff'
$ git merge testff
Updating 30a974d..5a036ee
Fast-forward
readme | 1 +
1 file changed, 1 insertion(+)
create mode 100644 readme
$ git log --graph --pretty=oneline --abbrev-commit
* 5a036ee test ff
* 30a974d Merge branch 'xxx' into master
|\
...
重點看兩點:
1. 第一處飄黃的地方,是在test-ff版本 checkout -b的,結果發現git 兩個branch完全沒有差別。
git checkout -b dev命令相當於
創建分支: git branch dev 切換分支: git checkout dev
而這個創建是基於當前HEAD的。
所以新創建的分支和test-ff沒有區別。
2. 采用默認的merge之后,使用git log --graph --pretty=oneline --abbrev-commit 能夠看到:
* 5a036ee test ff
完全沒有原來 test-ff 分支的信息。
另,git log命令加上后面的參數很好用,--graph --pretty=oneline --abbrev-commit
比原始的輸出好看多了。
分支策略
在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面干活;
那在哪干活呢?干活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本發布時,再把dev分支合並到master上,在master分支發布1.0版本;
你和你的小伙伴們每個人都在dev分支上干活,每個人都有自己的分支,時不時地往dev分支上合並就可以了。
所以,團隊合作的分支看起來就像這樣:

小結
Git分支十分強大,在團隊開發中應該充分應用。
合並分支時,加上--no-ff參數就可以用普通模式合並,合並后的歷史有分支,能看出來曾經做過合並,而fast forward合並就看不出來曾經做過合並。
一些git命令:
git checkout -b dev//基於本地創建分支
git checkout -b dev origin/dev //基於遠程分支創建本地分支
可以看到git checkout -b命令相當於
創建分支: git branch dev切換分支: git checkout dev
是基於當前HEAD的
刪除本地分支
git branch -D dev
刪除遠程分支
git push origin :branch-name
冒號后面沒有空格
下面再對這些內容做一下復習:
http://www.ruanyifeng.com/blog/2015/12/git-workflow.html
http://www.ruanyifeng.com/blog/2015/12/git-cheat-sheet.html
http://www.ruanyifeng.com/blog/2015/08/git-use-process.html
http://www.ruanyifeng.com/blog/2014/06/git_remote.html

