分支合並沖突的處理
合並分支的沖突時在不同的分支中修改了同一個文件的同一部分,程序無法把兩份有差異的文件合並,這時候需要人為的干預解決沖突。當前處於master 分支,當dev 分支和master 分支對相當部分test1.txt 都做了修改,當合並dev 分支的時候,合並會出現分支沖突如下:查詢當前工作區的狀態可以顯示那些文件發生合並沖突,任何包含未解決沖突的文件都會以未合並(ummerged)的狀態列出,git 會加入標准沖突解決標記,可以通過手工定位來解決這些沖突。可以看大 =======隔開以上部分就是當前活動分支,也是合並的基准分支(head 指向的master分支),======分隔符以下的是dev分支中的內容。解決沖突的辦法無非是二者選其一或者由你親自整合到一起。比如你可以兩部分內容合並成 一部分內容。
$ git branch
dev
* master
testing
$ git merge dev
Auto-merging test1.txt
CONFLICT (content): Merge conflict in test1.txt
Automatic merge failed; fix conflicts and then commit the result.
$ git status
# On branch master
# Unmerged paths:
# (use "git add/rm <file>..." as appropriate to mark resolution)
#
# both modified: test1.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
$ notepad test1.txt
<<<<<<< HEAD
now this is bug fix branch
=======
this is branch merge conflict problem
>>>>>>> dev
now this is bug fix branch
=======
this is branch merge conflict problem
>>>>>>> dev
同時還可以用圖形化界面的工具來處理分支,git mergetool 命令會調用時當前系統配置的合並工具。合並完成后可以查詢狀態git status 來確認所有沖突都已經解決。如果沖突解決都已完成,可以把合並后的內容提交到暫存區,可以用git commit 完成這次合並提交。針對沖突合並,需要寫好注釋說明,后續查看會更加簡單方便。
$ git commit -m "master merge dev branch"
[master 05a2f29] master merge dev branch
1 files changed, 4 insertions(+), 1 deletions(-)
分支的管理
git branch 是查詢當前所有分支的清單,*號的表示當前的活動分支,也就是當前所在的分支。也就是說如果現在有提交更新,當前的工作分支master 分支或向前移動。若要看各個分支最后一個提交對象的新,可以通過git branch -v 來查看。
$ git branch
dev
* master
testing
$ git branch -v
dev be70ec8 dev
* master 05a2f29 master merge dev branch
testing 0c8f2de testing branch change
在所有分支清單中,可以篩選出那些與當前分支尚未合並,通過參數--merge 可以篩選出那些分支在當前分支的上游,這些分支只需要通過fast-forward 移動指正就可以移動當當前最后提交給對象。--no-merged 可以查看還位和當前分支合並的分支。如dev分支和當前分支還未合並。如果以前是無效的分支,可以通過git branch -d 刪除制定的分支。
$ git branch --merged
* master
testing
$ git branch --no-merged
dev
$ git branch -d testing
Deleted branch testing (was 0c8f2de).
長期分支
git只是簡單的三方合並分支的特性,所以在腳長的一段時間內,把多個分支合並到一個分支或者同時擁有多發分支進行開發。由於每個分支都有特定的任務,隨着開發的推進,隨時可以把某個特性分支合並到其它分支中。需求使用git 的開發者都喜歡用這種方式開發,一般來說僅僅在master 分支保留穩定的代碼,就是已經發布或者經過測試的代碼。與此同時,你可以同時擁有多個開發分支。每個開發分支都有特定的任務。如還有一個叫develop 的平行分支,專門擁有后續的開發,僅擁有穩定性的測試。一旦到達某種穩定的狀態就可以合並到master 分支。如果有其它特性的短缺分支能夠通過測試,並且不會引如更多錯誤后,就可以並到主干master分支中。等待下一次發布。
隨着提交對象的不斷右移指針,穩定分支總是在提交歷史中落后一大截,而且前言分支總是比較靠前。穩定分支總是滯后,經過測試比較穩定的對象或者集合才被合並到穩定的分支上。這樣可以維護不同層次的穩定。
特性分支
在任何規模的項目中可以使用特性分支(topic).一個特性是指一個短期的,用來實現單一特性與其相關的工作分支,你可以在以前版本中從未做過類似的這樣事情,因為創建和合並分支的消耗太大。然而在git中,一天之內創建,刪除和合並多個分支是常見的事情。在創建特性分支后,你可以提交合並到主干分支,然后刪除他,該技術讓你迅速且完全進行語境切換。因為你的工作分散在不同的流水性力,每個分支力改變都和他的目標特性相關。你可以把做出的改變保持在特性分支幾分鍾。幾天甚至幾個月。等他們成熟以后再合並。而不用在乎他們建立的順序和進度。
一般分支都是在本地。大部分都是本地分支。這一點很重要。當前使用合並分支的時候,一切都在你的git 倉庫中進行的,完全不與服務器交互。只有當你有固定的分支或者分享需要和其它合作伙伴共享的時候,才需要推送到中心服務器。
遠程分支:
remote branch 是對遠程倉庫中的分支的索引。他們是無法移動本地分支。只有在git進行網絡交互時才會更新。遠程分支就是書簽,提醒着你上次鏈接遠程倉庫時上面各個分支的位置。 我們用倉庫名/分支名 這樣的形式表示遠程分支。比如我們想想上次同 origin 倉庫進行通訊時master 分支的樣子。就應該查看origin/master 分支。如果你和同伴一起修復某個問題。他們推送一個iss53分支到遠程倉庫。雖然你可能也有一個本地的iss53分支,但指向服務器上最新的更新的英是origin/iss53分支。
假如團隊中心服務器git地址:git.ourcompany.com.。如果你從這里克隆,git會自動在為你將次遠程倉庫嗎命名為origin。並下載其中的數據,建立一個指向它的master分支指針。在本地命名為Origin/master。但你無法再本地更改數據,接着git建立一個屬於你自己本地的master分支。始於origin上master分支相同的位置。如下圖
如果你在本地master 分支做了些改動。與此同時本地分支向前推進。只要本地沒有向遠程服務器推送,origin/master 分支指針任然保持在原位不會移動。
在本地工作同時有人向遠程倉庫推送內容會讓歷史開始分流。可以允許git fethch origin 來同步遠程服務器上的數據到本地。該命令首先找到origin 是哪個服務器。從上面獲取你未擁有的數據。更新你本地的數據庫。然后把Origin/master的指針移動到他最新的位置上。
如果有多個遠程分支的項目是如果進行工作的。我們假設你還有另外一個內部使用的遠程服務器。通過git remote add 命令吧它加為當前項目的遠程分支之一。我們把它命名為teamtone,以便代替完整的git url。
現在把另外一個遠程服務器添加為遠程倉庫了,現在可以用git fetch teamtone 來獲取小組服務器你還沒有的數據,由於當前服務器的內容是origin服務器上的子集,git不會下載任何數據。而只是簡答創建一個名為teamone/master 的遠程分支。指向teamone 服務器上master 分支所有在的提交對象 31b3e 如下圖:現在你在本地就有了一個指向teamone 的索引。
推送本地分支
要想和其它人分享某個本地的分支,你需要把它推送到一個擁有些權限的遠程倉庫。你創建的本地分支部會因為你的寫入操作而被自動同步到你引入的遠程服務器上,你需要明確的執行推送分支的操作。換句話說,對於無意分享的分支,你盡管保留私人分支好了。而只推送那些協同工作要用到的特性分支。如果有個交severfix 的分支需要和他人一起開發,可以運行git push (遠程倉庫名) 分支名。
$ git push origin serverfix
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:andy/test.git
* [new branch] serverfix -> serverfix
git 自動把serverfix 分支名擴展為refs/heads/serverfix:refs/heads/serverfix,意思是“取出我在本地的serverfix分支,推送到遠程倉庫的serverfix分支中區,一般在同一分支上可以省略,
git push origin serverfix:serverfix,還可以把本地分支推送到遠程不同的分支。可以用已經存在的新遠程分支或新的遠程分支。
當你再次從遠程獲取服務器上數據的時候,同伴會獲取到origin/serverfix 和 origin/newfix 的分支,並指向服務器上serverfix 所指向的版本。在fetch操作下載好新的遠程分支之后。你任然無法再本地編輯遠程倉庫中的分支。換句話說你不會有一個新的serverfix 分支。有的只是一個你無法移動的Origin/serverfix指針。你如果需要把該遠程分支的內容合並到當前分支,可以運行git merge origin/serverfix ,如果想要一份自己的serverfix來開發。可以在遠程分支的基礎上分化一個新的分支來。這會切換到新的serverfix 的本地分支。其內容同遠程分支 origin/serverfix 一致。這樣可以繼續開發了。
$ git push origin serverfix:newfix
Total 0 (delta 0), reused 0 (delta 0)
To git@github.com:andy
i/test.git
* [new branch] serverfix -> newfix
$ git fetch origin
remote: Counting objects: 19, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 17 (delta 6), reused 16 (delta 5)
Unpacking objects: 100% (17/17), done.
From github.com:andy
i/test
* [new branch] dev -> origin/dev
894ed8b..37b40ce master -> origin/master
跟蹤遠程分支
從遠程分支checkout 出來的本地分支。稱為跟蹤(tracking branch),跟蹤分支是一種和某個遠程分支有直接聯系的本地分支。在跟蹤分支里輸入git push,git 會自行推斷應該向那個服務器的那個分支推送數據。同樣,在這些分支里運行git pull 會回去遠程索引,並把它們的數據合並到本地分支中。
在克隆倉庫時,git 通常會自創建一個名master 的分支來跟蹤,這正是git push 和 git pull 一開始就能正常工作的原因。當然,你可以隨心所欲設定其為跟蹤分支,比如在origin 上除了master 之外的其它分支。剛才我們已經開到了這樣的一個例子。 git checkout -b 分支名 遠程名/分支名, 還可以用 --track 選項。 如果本地分支和遠程分支的名稱不一樣,可以本地分支換個名稱。
$ git checkout -b serv origin/serverfix
Branch serv set up to track remote branch serverfix from origin.
Switched to a new branch 'serv'
$ git branch
master
* serv
serverfix
刪除遠程分支
如果不再需要摸個遠程分支了,比如搞定某個特性並合並進了遠程的master 分支(或任何其他存放穩定的代碼分支),可以用這個命令 git push 遠程名:分支名。如果運行這個命令,服務器上的分支就沒了,git puhs 遠程名 本地分支:遠程分支 語法,如果省略本地分支。那就是等提前空白然后把它變成遠程分支。
分支的衍和
把一個分支中的修改整合到另一個分支的辦法由兩種:merge 和 rebase(翻譯為衍合)。
基本的衍合操作,當開發進程分叉到兩個不同的分支,有各自提交了更新。最簡單的整合方式是合並merege 命令。他會把兩者共同的祖先ac631f6進行三方合並。並合后產生一個結果就是兩條分的合並點。
其實除了合並以外,還有另外一個選擇,可以把7599941產生變化的補丁在4632de基礎上重新打一遍。在git 里着叫衍合(rebase),有了rebase命令,就可以在把在一個分只里提交的改變移動到另一個分支重方一遍。他們的原理是回到兩個分支最近共同的祖先。根據當前分支(也就是要進行衍合的分支)后續歷次提交的對象在這里分支只有一個提交。生產一系列文件補丁,然后基地分支(也就是主干分支master 的最后一個提交對象為新的出發點,逐個應用之前准備好的補丁文件,最后會生產一個新的合並提交對象。從而改寫需要衍合分支的提交歷史。使他成為master 分支的直接下游。
