前情提要:Git應用詳解第五講:遠程倉庫Github與Git圖形化界面git
git
除了能夠很好地管理我的項目外,最大的一個用處就是實現團隊協做開發。何況,linus
大神開發git
的初衷就是爲了維護Linux
內核這一開源項目。因此,熟悉使用git
進行多人協做開發的通常步驟和方法具備十分重要的意義。這一講將會爲你介紹使用git
進行團隊協做開發的通常方式以及git pull
操做常見問題的解決方法。vim
git
協做方式Gitflow
:簡單來講,就是多種開發模式的總稱。例如:使用多少分支,何時合併分支等等。這方面篇幅較長,內容較多,以後會進行詳細講解;bash
基於Git
分支的開發模型:通常最少有三個分支:post
develop
分支:頻繁變化的分支,供開發人員之間進行協做開發,文件推送與合併;test
分支:供測試人員與產品等人員使用的一個分支,變化不是特別頻繁;master
分支:生產發佈分支,變化很是不頻繁的一個分支(通常有權限設置,由於直接與生產有關);bugfix(hotfix)
分支:用於緊急修復的分支;當出現緊急bug
時,在常規的develop
分支上修復已經趕不上了。此時能夠直接將master
分支的代碼拉取到bugfix
分支上,進行bug
修復,修復完以後,再將它合併到master
分支上發佈;合併方向爲:develop
-> test
-> master
學習
SVN
方式(典型模型)首先有兩位用戶A
與B
,A
的本地倉庫不爲空,B
的倉庫爲空,還有一個遠程倉庫C
。測試
A
首先將本地倉庫的代碼推送(push
)到C
中,此時A
和C
兩個倉庫的文件一致,如圖中1
所示;B
將C
的代碼拉取(pull
)下來,如圖中2
所示,此時A
,B
,C
三個倉庫中的文件一致;隨後A
,B
繼續在本地進行開發,並向各自的本地倉庫進行了數次提交;A
先向C
推送修改事後的本地倉庫文件,因爲這是遠程倉庫C
的首次修改,C
中的文件A
中都有,因此能夠直接推送,不用先執行git pull
,如圖中3
所示;B
將修改過的本地倉庫文件推送到C
的過程當中會出現錯誤。緣由在於:此時的C
中有A
作出的修改,不能讓B
進行覆蓋,此時B
要想成功推送,應該先將C
中的文件拉取(pull
)到本地;如圖中4
所示,拉取時有兩種狀況:
A
與B
修改的不是同一個文件,採用Fast-forward
方式自動合併;A
與B
修改了同一個文件,須要手動解決衝突併合並;B
成功將C
中的文件拉取到本地合併後,就能將B
對本地倉庫所作的修改推送(push
)到遠程倉庫C
了,如圖中的5
所示;在整個過程當中,能夠發現遠程倉庫C
僅僅是起到代碼第三方託管的做用;fetch
爲了模擬多用戶協做,可使用--local
來設置每一個倉庫的用戶信息:ui
git config --local user.name '張三'
複製代碼
--local
是一個配置做用域的參數,其餘的還有:spa
--global
:做用域爲每一個計算機用戶,優先度第二,實際上經常使用這個參數進行配置;--system
:做用域爲整個系統,優先級最低;可使用:git clone
將遠程倉庫的代碼下載到本地某文件夾中,下面使用的是SSH
的方式:命令行
還能夠經過在連接後面加上一個字符串,從新命名下載到本地的遠程倉庫文件的名字:
git clone git@gitee.com:ahuntsun/MY.git mygit2
複製代碼
遠程倉庫一般有多個分支,而在本地倉庫進行一次推送時並非將本地倉庫的全部分支都推送到遠程倉庫,而是選擇本地倉庫中的一個分支,將其推送到遠程倉庫的其中一個分支上:
好比本地的master
分支,如上圖所示,能夠選擇遠程倉庫的master、dev、test
其中一條分支進行推送。假如想要推送到遠程倉庫的master
分支,若是一開始兩個分支沒有任何聯繫,天然要:
master
分支與遠程master
分支的關聯(至於如何創建關聯,下一節將會詳細講解);master
分支與遠程master
分支的合併,使兩條分支的內容第一次達到同步;master
分支上進行修改,而後將修改推送到對應的遠程master
分支上。此時,兩分支的內容第二次達到同步;git pull
在實際開發中,在推送代碼前,每每都要先執行一次git pull
將遠程倉庫的代碼拉取到本地並進行合併;從前面的學習中咱們知道:git pull = git fetch + git merge
:
git fetch
:表示將遠程倉庫的全部文件拉取到本地版本庫;git merge
:將遠程倉庫中的文件與本地倉庫中的文件進行合併;可是,在執行git pull
命令時,因爲本地倉庫與遠程倉庫歷史提交記錄的不一樣,每每會出現各類各樣的合併錯誤;在分析這些錯誤以前,首先搭建測試環境:
分別建立兩個本地倉庫mygit
和mygit2
,而且這兩個本地倉庫與同一個遠程倉庫創建聯繫,以下圖所示:
在本地倉庫mygit2
中使用--local
參數配置新的用戶lisi
模擬多人協做,隨後經過lisi
給遠程倉庫推送一個新的文件。回到mygit
後執行git remote show origin
指令,會顯示以下信息:
表示,本地倉庫mygit
相對於遠程倉庫而言已通過時了,即遠程倉庫中有mygit2
推送的,mygit
中沒有的文件;此時能夠在mygit
中執行git pull
,將遠程倉庫中的文件拉取到本地倉庫mygit
中進行合併:
上圖中的第二個箭頭表示,在pull
操做的過程當中mygit
中的master
分支與遠程倉庫中的master
分支採用Fast-forward
方式進行了合併,並達到了同步。
這裏的本地遠程分支
origin/master
表明着遠程master
分支,關於本地遠程分支將會在下一節進行詳細講解;
關於Fast-forward
方式以前已經介紹過了,在上述合併過程當中origin/master
分支直接指向了最新提交,中間沒有其餘分支,也就不會出現合併衝突,這種合併方式稱爲快進。以下圖所示:
這是一個理想的狀況,不少狀況下執行git pull
操做時,都會出現合併衝突,須要解決衝突,再進行手動合併;
git pull
同源合併衝突所謂同源,指的是本地倉庫與遠程倉庫中的分支從根提交節點開始,有共同的提交歷史;簡而言之,有共同的根提交節點的兩個分支稱爲同源;以下圖所示,兩倉庫中的master
分支有共同的根提交節點A
,因此這兩個倉庫的master
分支是同源的:
這種狀況下git pull
出現的錯誤爲自動合併失敗,好比都同時修改了develop.txt
文件,錯誤信息以下:
Auto-merging develop.txt
CONFLICT (content): Merge conflict in develop.txt
Automatic merge failed; fix conflicts and then commit the result.
複製代碼
具體狀況模擬以下:
在mygit
中修改hello.txt
文件的第二行爲1
,在mygit2
中修改hello.txt
文件的第二行爲2
,即對同一文件的同一處進行了修改。
此時取決於誰先進行git push
操做,若mygit
先將修改後的hello.txt
推送到遠程倉庫。那麼當mygit2
再進行推送時會出現以下錯誤:
提示信息代表:遠程倉庫中有一些文件是你沒有的,沒法更新遠程倉庫;這是由於,mygit
先把修改的hello.txt
推送到了遠程倉庫;此時mygit2
想要成功進行推送,須要先將遠程倉庫中通過mygit
修改的hello.txt
與本地倉庫的hello.txt
進行合併。
可使用git pull
來解決這一問題,那麼咱們首先執行一次git pull
操做:
能夠發現git pull
指令在進行自動合併時發生了錯誤,這是由於mygit
和mygit2
都對hello.txt
的同一個地方作了修改,git
不知道以誰爲準,因此會致使自動合併失敗,此時須要經過解決衝突三步曲來手動合併:
第一步:
打開衝突文件hello.txt
能夠看到典型的衝突文件顯示方式:
箭頭<<<
與>>>
範圍內表示的是發生衝突的位置。2
是mygit2
對hello.txt
的修改,1
爲遠程倉庫中hello.txt
的內容;
通過協商後,留下第3
行,其他刪除:
由此手動合併了對文件hello.txt
的修改,解決了衝突。
vim
指令補充:經過esc
進入命令行模式後,經過上下方向鍵選中某一行,再雙擊d
就能夠刪除光標所在的行;刪除多行時,在命令行中輸入:2,4d
表示刪除第2~4
行;
第二步:
再次查看狀態:
發現hello.txt
處於工做區,git
提示咱們要經過git add
指令將解決衝突時對hello.txt
所作的修改歸入暫存區。
第三步:
執行完git add
以後,再進行提交git commit
:
由此,解決了衝突;
從上圖中箭頭所指內容能夠看出:本地倉庫mygit2
中的master
分支已經比本地遠程分支origin/master
分支多了兩次提交。因爲origin/master
分支表明着遠程倉庫的master
分支,也就是說本地倉庫mygit2
中的master
分支比遠程倉庫的master
分支領先了兩次提交;過程以下圖所示:
首先mygit
在提交1st
的基礎上進行了第2
次提交(修改hello.txt
),以後mygit
將本地倉庫推送(push
)到遠程倉庫;
此時mygit2
一樣在本地倉庫中進行了一次提交3rd
(修改hello.txt
),此時推送到遠程倉庫會出現錯誤,須要進行pull
操做;
當mygit2
執行pull
操做,將遠程倉庫拉取到本地後,因爲發生衝突,因此暫時不會將origin/master
的指向更新到最新提交;隨後,在mygit2
中手動解除衝突並進行合併後,mygit2
的狀態爲:
能夠看到解決衝突,手動合併後,mygit2
已經往前更新了兩次提交,而此時origin/master
仍然指向提交1st
。
因此解決衝突後,mygit2
中的master
分支會比origin/master
分支領先兩次提交;再次執行git push
後,origin/master
分支就會指向最新的提交點4th
了,此時三個倉庫的狀態爲:
在實際開發當中,不免會出現多我的修改了同一個文件的狀況,在進行手動合併的過程當中必定要與對方協商應該如何合併,而不是直接覆蓋;
git pull
不一樣源合併衝突所謂不一樣源,指的是兩個倉庫中的分支,根提交節點不一樣,以下圖所示:
假如本地master
分支要將內容推送到遠程master
分支。因爲本地master
分支根提交節點爲1st
,遠程master
分支根提交節點爲A
,兩個分支沒有公共的父提交節點。因此,沒法進行合併。這種狀況下執行git pull
會出現如下錯誤:
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
複製代碼
簡單來講git pull
失敗的緣由有兩點:
master
分支因爲根提交節點不一樣,沒有共同的提交歷史。因此,會致使採用三方合併原則合併分支時,找不到公共提交節點而沒法合併:master
分支沒有與遠程倉庫中的任一分支創建關聯。所以,本地master
分支不知道將文件推送給誰,這樣天然會失敗;知道了git pull
失敗的兩點緣由,解決方案就很清晰了,一樣分爲三步:
**第一步:**執行一次git pull
將遠程倉庫的分支拉取到本地:
這裏的本地遠程分支origin/master
和origin/dev
是遠程分支master
和dev
的本地形式,表明着它們,內容上與它們一致。雖然git pull
失敗了,可是咱們得到了遠程分支的信息,方便進行第二步的合併操做;
**第二步:**建立兩分支的公共提交歷史。此時兩分支沒有公共父節點,不能採用merge
方式合併。應該採用rebase
變基的方式,將本地master
分支追加到遠程master
分支後面。因爲本地遠程分支origin/master
與遠程master
分支有這相同的提交歷史,因此能夠這樣寫:
git rebase origin/master
複製代碼
此時,本地master
分支的提交歷史變爲:A <- B <- 1st <- 2nd
。這樣本地master
分支與遠程master
分支就有了公共的提交歷史,即轉換爲了同源分支:
**簡寫:**能夠將第一步和第二步經過參數的形式合併爲一步操做:
git pull --rebase origin master 複製代碼
**第三步:**創建本地master
分支與遠程master
分支的關聯。經常使用的有如下三種方式:
//格式
git branch --set-upstream-to=origin/<branch> master
//用在這裏具體爲
git branch --set-upstream-to=origin/master master
複製代碼
該指令做用爲,將本地master
分支相關聯的遠程分支設置爲遠程master
分支,執行該指令後,經過git branch -vv
查看分支的關聯狀況,可見已順利創建關聯:
以後就能夠進行推送了:
git push -u origin master
複製代碼
該指令做用爲:創建本地master
分支與遠程master
分支的聯繫,並進行推送:
git push --set-upstream origin master
複製代碼
做用爲:創建本地master
分支與遠程master
分支的聯繫,並進行推送:
mygitA
和mygitB
,首先在mygitA
中的master
分支上添加A.txt
,提交信息記爲A
:mygitA
中建立並切換到dev
分支,添加文件C.txt
,並進行提交,提交信息記爲C
:mygitA
的master
分支,添加文件B.txt
,並進行提交,提交信息爲B
: 此時mygitA
中兩分支的狀態以下:
隨後,創建本地倉庫mygitA
與遠程倉庫的關聯:
設置並推送mygitA
的master
分支和dev
分支,到遠程倉庫的master
分支和dev
分支上:
回到mygitB
,添加文件1st.txt
和2st.txt
並進行兩次提交1st
和2nd
:
此時三個倉庫的狀態爲:
若想將mygitB
的master
分支推送到遠程倉庫的master
分支上,按照上文的討論,採用簡寫形式,可經過如下兩步進行實現:
rebase
合併本地master
分支與遠程master
分支:git pull --rebase origin master
複製代碼
執行完上述指令後,mygitB
的狀態爲:
master
分支與遠程master
分支的聯繫,並進行推送:git push -u origin master
複製代碼
如圖所示,與遠程分支創建了聯繫,並完成了推送;由此解決了因爲不一樣源形成的pull
操做衝突。
以上就是本節的所有內容,細心的你確定發現了,在這一節中偶爾會提到本地遠程分支
origin/master
,它究竟是什麼呢?有什麼做用?其實它是git
進行本地倉庫與遠程倉庫交流的一個重要橋樑。在下一節中將會爲你詳細介紹本地遠程分支的由來和做用,以及最重要的:如何創建本地倉庫與遠程倉庫的分支對應關係?咱們下一節再見!