一 分支操作
1 概述
每次提交,Git 把它們串成⼀條時間線,這條時間線就是⼀個分支。git 初始化時默認創建了一個分支,即 master 分支。HEAD 嚴格來說不是指向提交,而是指向 master,master 纔是指向提交的,所以,HEAD 指向的就是當前分支。一開始的時候,master 分支是一條線,Git 用 master 指向最新的提交,再用 HEAD 指向 master,就能確定當前分支,以及當前分支的提交點。
2 創建分支
例如創建新的分支 dev,Git 新建了一個指針叫 dev,指向 master 相同的提交,再把 HEAD 指向 dev,就表示當前分支在 dev 上,創建分支命令:
$ git checkout -b dev
Switched to a new branch 'dev'
git checkout 命令加上 -b 參數表示創建並切換,相當於以下兩條命令:
$ git branch dev
$ git checkout dev
Switched to branch 'dev'
然後,用git branch命令查看當前分支:
$ git branch
* dev
master
git branch 命令會列出所有分支,當前分支前面會標一個 * 號。
Git 創建一個分支很快,因爲除了增加一個 dev 指針,改變一下 HEAD 的指向,工作區的文件都沒有任何變化!從現在開始,對工作區的修改和提交就是針對 dev 分支了,比如新提交一次後,dev 指針往前移動一步,而master指針不變:
3 切換分支
如果切換分支:
$ git checkout master
Switched to branch 'master'
4 合併分支
dev 上的工作完成了,就可以把 dev 合併到 master 上。最簡單的方法,就是直接把 master 指向 dev 的當前提交,就完成了合併。dev 分支的工作成果合併到master分支上:
$ git merge dev
Updating d17efd8..fec145a
Fast-forward
readme.txt | 1 +
1 file changed, 1 insertion(+)
5 禁用 fast forward
通常,合併分支時,如果可能,Git會用“Fast forward”模式,但這種模式下,刪除分支後,會丟掉分支信息。如果要強制禁用“Fast forward”模式,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支信息。
$ git merge --no-ff -m "merge with no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
--no-ff
參數,表示禁用“Fast forward”,因爲本次合併要創建一個新的commit,所以加上-m參數,把commit描述寫進去。
6 刪除分支
所以Git合併分支很快!就改變指針,工作區內容也不變!合併完分支後,甚至可以刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉後,就剩master分支。
$ git branch -d dev
Deleted branch dev (was fec145a).
$ git branch
* master
二 解決衝突
這種情況下,Git 無法執行“快速合併”,只能試圖把各自的修改合併起來,但這種合併就可能會有衝突:
$ git merge feature1
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
查看文件內容:
Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature1
Git 用<<<<<<<,=======,>>>>>>>標記出不同分支的內容,修改衝突後再次提交。
用帶參數的 git log 也可以看到分支的合併情況:
$ git log --graph --pretty=oneline --abbrev-commit
* 59bc1cb conflict fixed
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...
用git log --graph
命令可以看到分支合併圖。
三 分支策略
在實際開發中,應該按照幾個基本原則進行分支管理:首先,一個項目分支分爲三類:一個master分支,一個次於master分支的次分支,和個人分支(每個人都有一個分支);其次,master 分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面幹活;幹活都在次分支上,也就是說,分支是不穩定的,到某個時候,比如1.0版本發佈時,再把分支合併到master上,在master分支發佈1.0版本;最後,每個人都在dev分支上幹活,每個人都有自己的分支,時不時地往dev分支上合併就可以了。所以,團隊合作的分支看起來就像這樣:
四 Bug分支
軟件開發中,有了bug就需要修復,在Git中,每個bug都可以通過一個新的臨時分支來修復,修復後,合併分支,然後將臨時分支刪除。
但是很多時候,目前的工作沒法提交,可以使用 stash 功能。
其實在開發新功能的時候,和修復 bug 的概念一樣,都是建議重新建立一個分支功能分支,然後合併,刪除分支,如果要丟棄一個沒有被合併過的分支,可以通過vgit branch -D name
強行刪除。
五 Git 的M,T,D,A,U標誌
在使用git checkout , git status,或git diff files時會出現奇怪的標誌。如M,T,D,A,R,U等等。
$ git checkout master
M cpp-iniparser
文件cpp-iniparser前面有個M。git的這些奇怪標誌是什麼意思呢。
A: 增加的文件。
C: 文件的一個新拷貝。
D: 刪除的一個文件。
M: 文件的內容或者mode被修改了。
R: 文件名被修改了。
T: 文件的類型被修改了。
U: 文件沒有被合併。(你需要完成合並才能進行提交)
X: 未知狀態。(很可能是遇到git的bug了,你可以向git提交bug report)
在git diff-files的手冊man git diff-files中可以查到這些標誌的說明。
這些狀態標誌在git的源代碼的diff.h文件中被定義。
六 切換分支把未add或未commit的內容帶過去
git 切換分支時會把未 add 或未 commit 的內容帶過去,因爲未add的內容不屬於任何一個分支, 未commit的內容也不屬於任何一個分支。 也就是說,對於所有分支而言, 工作區和暫存區是公共的。
要想在分支間切換, 又不想又上述影響, 怎麼辦呢?git stash
搞起。要注意,在當前分支git stash的內容, 在其他分支也可以git stash pop出來,爲什麼? 因爲:工作區和暫存區是公共的。
另外一種方法就是用 git add
和 git commit
提交修改,只要用 git status
檢查工作區和暫存區是乾淨的就可以了。