熟練使用 git 分支管理

Git
觀察過不少使用 git的人,只會用 add, commit, push, pull這幾個命令,包括恢復版本之類的,多半也會暴力的刪除整個項目,再從新 clone乾淨的代碼。雖然說也能工做了,可是無疑沒有領會到 git的精華。 這篇文章主要說明如何使用分支使咱們的開發工做更加順滑,如何讓分支成爲你平常工做流不可缺失的一部分。

git branch 用法

git branch   //列出全部的分支
git branch <branch> //建立名爲<branch>的分支,可是不會切換過去
git branch -d <branch>  //刪除指定分支,這是一個「安全」操做,git會阻止你刪除包含未合併更改的分支。
git branch -D <branch>  //強制刪除分支
git branch -m <branch> //從新命名當前分支
複製代碼

在平常開發中,不管是修復一個bug或者添加一個功能,咱們都應該新建一個分支來封裝咱們的修改。這樣能夠保證咱們不穩定的代碼永遠不會提交到主代碼分支上。git

下面咱們具體來看在執行分支有關的操做,分支的變化:算法

建立分支

分支只是指向提交的指針,理解這一點很重要,當你建立新分支,實際上只是建立了一個新的指針,倉庫自己不會受到影響,一開始你的倉庫只有一條分支:安全

master
而後你執行下面的命令建立一個分支,用於加一個新feature:

git branch new-feature
複製代碼

new-feature
固然執行後,你只是建立了這個分支,還須要執行 git chekcout new-feature切換到 new-feature分支,而後再使用 git add, git commit

刪除分支

假如你已經開發完了new-feature,而且已經commit代碼了, 你就能夠自由刪除這個分支了。bash

git branch -d new-feature
複製代碼

若是分支尚未合入master,會報下面的錯誤:ui

error: The branch 'new feature' is not fully merged.
If you are sure you want to delete it, run 'git branch -D crazy-experiment'.
複製代碼

這時候你能夠合併分支(下面會說如何合併分支),若是你真的肯定了要刪除分支,能夠用-D執行強制刪除:this

git branch -D new-feature
複製代碼

切換分支(git checkout)

git checkout 命令容許你切換到用git branch建立的分支。切換分支會更新當前工做目錄中的文件,還能夠用git log查看當前分支的歷史。 用法spa

git checkout <existing-branch> //切換到一個已有分支上
git checkout -b <new-branch> // -b 標記 能夠方便讓你先建立一個新的new-branch,再直接切換過去
git checkout -b <new-branch> <existing-branch> //在已有的分支上建立分支,原來的分支使新分支的基
複製代碼

git branchgit chekout 是一對好基友,你可使用git checkout在不一樣的功能分支或者bug分支之間切換,而不產生相互影響。3d

關於分離的HEAD(detached HEAD) 通常咱們有時候須要恢復到之前commit的版本上查看原來的一些文件時,咱們會git checkout commit的hash碼或者tag, 這時候會提醒咱們進入了detached HEAD指針

detached HEAD
拿上圖舉例,咱們當前的HEAD在4,而後假設 git checkout 2,咱們的代碼回到2的狀態了,一般git會顯示下面的warning:

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 2
複製代碼

若是在這種狀態下開發,而後又add,commit,沒有分支可讓你回到以前的狀態。當你不可避免的須要checkout到另一個分支,想再回來就是不可能的了,由於像圖中的那個X狀態,根本就不在分支上,你將不再能引用你以前添加的代碼了。code

重點:永遠記得在開發分支上開發,不要在分離的HEAD上開發,這能夠確保你能夠引用到你的新提交,若是隻是checkout到之前看看無所謂,若是真的須要在之前的版本上添加什麼代碼,記得上面warning 中的git checkout -b new_branch_name,是本身處於一個確切的分支中。

遠離detached HEAD,咱們來看實際上git分支流程是什麼樣子的:

git branch new-feature
git checkout new-feature
複製代碼

接下來咱們作一些代碼改動,提交:

git add <some file>
git commit -m "A new feature"
##你接着改代碼,接着提交不少次
複製代碼

當你git log會顯示每一次的commit, 和master分支徹底獨立,當你checkout到master分支去,再git log,會發現new-feature分支的提交都不在,這就是不影響master分支。 這時候,你能夠考慮合併new-feature或者在master分支上開始別的工做。

合併(git merge)

合併是git將被fork的歷史放回到一塊兒的方式。 git merge 命令容許你將 git branch 建立的多條分支合併成一個。 用法

git merge <branch>  //將指定分支併入當前分支
git merge --no-ff <branch>  //將指定分支併入當前分支,但 老是 生成一個合併提交(即便是快速向前合併)。這能夠用來記錄倉庫中發生的全部合併。
複製代碼

一旦在新分支上完成開發,咱們須要把新分支的提交合併到主分支,git會根據目前分支之間的結構信息,選擇不一樣的算法來完成合並:

  • 快速向前合併
  • 三路合併

快速向前合併 當new-feature的分支與原有的master分支呈現線性關係時,執行快速向前合併,git將當前的HEAD指針快速移到目標分支的頂端,master分支也就具備了new-feature分支的歷史了,如圖:

快速向前合併

來看一個快速向前合併的實例:

# 開始新功能
git checkout -b new-feature master

# 編輯文件
git add <file>
git commit -m "開始新功能"

# 編輯文件
git add <file>
git commit -m "完成功能"

# 合併new-feature分支
git checkout master
git merge new-feature
git branch -d new-feature

複製代碼

對於合做開發的人少的項目,這是一種主要的工做流,合做開發的人多的話,主master分支常常都會有新提交,若是你的new-feature耗時比較久,再提交時,master分支可能已通過去幾個版本了,這時候就須要下面的三路合併了。

三路合併 可是若是master分支在new-feature分離後,又有了新的提交,即開始分叉了,git只能執行三路合併,三路合併使用一個專門的提交來合併兩個分支的歷史。

已經分叉的branch
所謂的三路也就是:兩個分支的頂端以及他們共同的祖先。 在執行三路合併後:

三路合併後
使用三路合併產生的合併提交做爲兩個分支的鏈接標誌。

解決衝突 若是兩個分支對同一個文件的同一部分均有修改時,git將沒法判斷應該使用哪一個,這時候合併提交會中止,須要你手動解決這些衝突。你可使用git status來查看哪裏存在衝突,不少時候我都會在目錄下執行grep -rn HEAD來查看哪些文件裏有這個標記,有這個標記的地方都是有衝突的。

當修改完全部的衝突後,git add全部的衝突文件,運行git commit生成一個合併提交,這和提交一個普通快照的流程相同。提交衝突只會存在在三路合併中,快速向前合併中不可能出現針對同一文件同一部分的不同修改。

下面實例來看看三路合併是怎麼產生的:

# 開始新功能
git checkout -b new-feature master

# 編輯文件
git add <file>
git commit -m "開始新功能"

# 編輯文件
git add <file>
git commit -m "完成功能"

# 在master分支上開發
git checkout master

# 編輯文件
git add <file>
git commit -m "在master上添加了一些極其穩定的功能"

# 合併new-feature分支
git merge new-feature
git branch -d new-feature
複製代碼

這時候,merge會中止,由於沒法將 master 直接移動到 new-feature。因此須要你手動合併衝突後再提交。

git merge會產生合併提交,有的人會選擇使用git rebase來合併以確保一個乾淨的提交歷史。關於這兩個的區別,我會另寫一篇介紹。

相關文章
相關標籤/搜索