30分鐘教你輕松使用Git做代碼管理
2017-06-20
Git的起源
(故事性內(nèi)容,不喜跳過,干貨往下看)
git的由來說白了,就是一個(gè)天才程序員,因?yàn)椴幌矚g傳統(tǒng)的代碼版本控制工具(集中式)或者喜歡的工具不開源,就自己花了半個(gè)月的時(shí)間寫了這么一個(gè)流行至今的“分布式版本控制系統(tǒng)”。
當(dāng)年,Linux的發(fā)明人Linus Torvalds將Linux的源碼放置開源社區(qū)后,開始接收來自世界各地的志愿者們貢獻(xiàn)的代碼,并手工合并??上攵?,隨著linux社區(qū)日益活躍,Linux的源碼也更加龐大,這樣的手工合并代碼的方式越來越困難,也越來越不像程序員的做事風(fēng)格。
不是早就存在像SVN和CVS這樣的自動(dòng)化代碼版本控制工具嗎?然而Linus表示,堅(jiān)決抵制集中式版本控制器。因?yàn)榧惺降墓ぞ卟坏俣嚷?,而且如果中央服?wù)器突然宕機(jī),或者沒有網(wǎng)絡(luò),團(tuán)隊(duì)幾乎無法提交工作。那Bitkeeper這樣強(qiáng)大的分布式版本控制工具呢?事實(shí)上,從2002年開始,linus就開始用Bitkeeper管理代碼,自此,Linux的發(fā)展步伐加快了一倍。
然而,Bitkeeper是一款商業(yè)版軟件,雖然為開發(fā)開源軟件的兄弟們提供使用許可,但是同時(shí)也限制開源社區(qū)不可以開發(fā)具備相同功能的軟件。但程序員們哪有幾個(gè)是安份的?開源社區(qū)的兄弟們更是如此。Linux和Bitkeeper交往的大好時(shí)光持續(xù)到2005年,開發(fā)Samba的Andrew試圖破解BitKeeper的協(xié)議,卻被Bitmover公司(Bitkeeper的研發(fā)公司)發(fā)現(xiàn)了,從此收回了在開源社區(qū)使用Bitkeeper的許可。
激動(dòng)人心的時(shí)刻來了,Linus和Bitmover公司的CEO Larry McVoy是好朋友,本來可以為社區(qū)的兄弟們低個(gè)頭,向Bitmover認(rèn)個(gè)錯(cuò),以前怎么哥倆好,今后繼續(xù)怎么搞。
但是天才就是天才,Linus隨后花了半個(gè)月的時(shí)間用C寫了一個(gè)分布式版本控制器,并在一個(gè)月內(nèi)將Linux的代碼完全由其托管,這個(gè)工具就是Git。當(dāng)然,開源的。
時(shí)至今日,Git已經(jīng)成為了最為流行的代碼管理工具。隨著Github網(wǎng)站的上線,更是紅得一發(fā)不可收拾。
Tips:據(jù)說去年,Bitkeeper也開源了。
Git vs SVN
上面說了這么多,無非是想表達(dá)的對(duì)天才程序員的敬佩之情和對(duì)開源精神的推崇,雖然自己還只是一個(gè)Coder,但也會(huì)努力成為一個(gè)厲害的Programmer的。
為什么Linus抵制像SVN這樣的集中式版本控制呢?Git是分布式的,和集中式的區(qū)別究竟在哪呢?我們接下來就來探討下。上圖
可以看出,所有的開發(fā)者都是通過連接中央服務(wù)器進(jìn)行代碼獲取或者代碼提交的。開發(fā)人員之間,必須通過中央服務(wù)器來合作開發(fā)。中央服務(wù)器中保存著完整的版本庫(kù),開發(fā)者如果要進(jìn)行版本控制,需要連接網(wǎng)絡(luò)。若服務(wù)器宕機(jī),或者網(wǎng)絡(luò)中斷,開發(fā)工作將無法開展。

而對(duì)于分布式的版本控制器,每個(gè)人的電腦上都可以保存一份完整的版本庫(kù)。從remote pull下來最新的代碼,如果網(wǎng)絡(luò)中斷,開發(fā)人員完全可以在本地做版本回滾和修改提交,再在聯(lián)網(wǎng)的時(shí)候推送到遠(yuǎn)程倉(cāng)庫(kù)。若兩名開發(fā)人員合作開發(fā)一個(gè)功能,可以不經(jīng)過遠(yuǎn)端服務(wù)器就可以相互之間推送修改,合并沖突后,再由某一人推送代碼。大大得提高了開發(fā)效率。而且如果服務(wù)器壞了,數(shù)據(jù)丟失,沒關(guān)系,每個(gè)人都有完整的版本庫(kù),從其他人那里clone一份就ok了。當(dāng)然,信息安全的問題也就來了。
當(dāng)然,對(duì)于一個(gè)項(xiàng)目的開發(fā),選擇集中式或者分布式的版本控制并不是關(guān)鍵問題,我認(rèn)為提高版本控制的決定因素在于良好的分支管理策略,這里還是比較講究的。有興趣的同學(xué)可以參考《Git權(quán)威指南》。
Git初體驗(yàn)
講了這么多,我們來實(shí)際演練下git的操作吧。由于習(xí)慣了命令行操作,雖然公司推薦小烏龜,但我還是很傲嬌的用git bash
環(huán)境搭建
window10(win7也ok,64bit或者32bit無關(guān)緊要,都有對(duì)應(yīng)的git版本)
git的win版官網(wǎng)下載地址 下載最新版的可以的。30M+,一會(huì)就下好了。
github遠(yuǎn)端倉(cāng)庫(kù),登陸官網(wǎng)注冊(cè),創(chuàng)建一個(gè)就好
安裝
看到以下畫面前一路next(注意設(shè)置安裝路徑)

然后按上圖進(jìn)行單選,接著一路next,安裝就好了。在新建一個(gè)文件夾,進(jìn)入,在空白處右擊,會(huì)發(fā)現(xiàn)右鍵菜單多了兩個(gè)選項(xiàng),Git GUI here,Git Bash here。選擇第二個(gè)。進(jìn)入如下界面

這個(gè)就是git的命令行界面了。
我利用git提交代碼的流程
git在window的安裝需要200M+的空間,而在Linux上安裝包卻非常小,很有可能是因?yàn)閣indows上啟動(dòng)git,首先會(huì)啟動(dòng)一個(gè)輕量級(jí)Linux系統(tǒng),然后再在其中啟動(dòng)git,你會(huì)發(fā)現(xiàn)在git bash界面上,你能夠使用很多Linux下的代碼,包括vim編輯器,有點(diǎn)小激動(dòng)。
Tips:C://Users/[你的用戶名]/目錄下面有一個(gè).bashrc文件,這個(gè)文件和Linux的.bashrc一樣,在啟動(dòng)時(shí)加載,配置bash的環(huán)境變量,你可以在這里配置java的環(huán)境變量,這樣就能在git bash使用java命令了。其他軟件也是如此。
假設(shè)你剛進(jìn)公司,公司在github上托管了一個(gè)開源項(xiàng)目(我剛剛創(chuàng)建一個(gè)空的項(xiàng)目),你需要在上面開發(fā),你首先需要從github上clone一份完整的最新代碼。復(fù)制下圖鏈接

然后在git bash敲入如下命令git clone [剛剛復(fù)制的鏈接],并進(jìn)入目錄。

查看code1.txt的內(nèi)容

你已經(jīng)或得了完整的代碼了,現(xiàn)在你可以嘗試進(jìn)行開發(fā)。一般這個(gè)時(shí)候,我會(huì)選擇新建一個(gè)分支,在那個(gè)分支上做開發(fā),完成后切換回主分支,合并新建的分支,再提交代碼。那什么是分支呢?參考這里吧!
敲入git checkout -b dev來新建一個(gè)名為dev的分支。

git checkout 這個(gè)命令是用來切換分支的,如果帶上了-b選項(xiàng),就表示新建一個(gè)分支。git branch是查看所有分支,分支名前帶分號(hào)的表示當(dāng)前所在分支。-a選項(xiàng)表示羅列所有分支,包括本地和遠(yuǎn)程追蹤分支。
**Tips: **在命令后設(shè)置-h可以查看命令幫助,--help可以啟動(dòng)瀏覽器查看更加詳細(xì)的幫助文檔。
好了,分支也建好了,我們可以嘗試開發(fā)了,我們做如下操作:
- 在code1.txt中修改第一行,并增加若干行。
- 新建一個(gè)文件,寫入一些內(nèi)容


你在項(xiàng)目中添加了新的文件,并且更改了舊的文件,可以通過git diff命令查看修改

你發(fā)現(xiàn),對(duì)于code1.txt中原本一行的修改,git簡(jiǎn)單粗暴的記錄為刪除后,再添加。對(duì)于新增的內(nèi)容記錄為增加。是的,git是以行(hang)為單位記錄文件的修改。等等,你發(fā)現(xiàn)我們剛剛新建的mycode1.txt文件并沒有被顯示。使用git status命令查看當(dāng)前工作空間狀態(tài)

mycode1.txt是Untracked files,這個(gè)文件未被git追蹤,你需要通過git add .將你的所有修改、新增、刪除添加進(jìn)工作區(qū)的暫存區(qū)stage,什么是git的暫存區(qū)呢,參考
敲入git add .

再用git status可以看到,能夠看到所有文件的修改了。mycode.txt為新增文件。
現(xiàn)在你完成了你的工作,準(zhǔn)備提交所有的修改,敲入git commit -m "一些信息"

將代碼的變化提交到本地倉(cāng)庫(kù)?,F(xiàn)在的分支是dev,我們切換回master

可以看出,切換回master分支后,你會(huì)發(fā)現(xiàn)目錄下只有code1.txt文件了,自己新建的文件不復(fù)存在。(注意:如果在dev分支上沒有commit修改,在master分支上能夠看到在dev分支上的修改。)
我們以圖來分析

這是最開始的狀態(tài),只有一個(gè)master分支,HEAD指向當(dāng)前分支的最新版本。

新建一個(gè)分支后,同時(shí)也切換到dev分支上,此時(shí)HEAD指向dev,master和dev的最新版本是一樣的。

現(xiàn)在在dev分支上修改,并提交代碼,你會(huì)發(fā)現(xiàn),dev開始和master分開了,

多次提交代碼后,切換回master,此時(shí)master的版本早已落后于dev,通過git merge dev命令將dev分支合并進(jìn)master分支中,以保證版本一致.


現(xiàn)在,你可以在將master分支推送的遠(yuǎn)端倉(cāng)庫(kù)的master分支了。

**Tips: **截圖中的命令很仔細(xì)的制定了本地分支和遠(yuǎn)程分支的名字git push origin [local branch]:[remote branch],事實(shí)上,如果使用了git branch --set-upstream [本地分支] [遠(yuǎn)程分支]關(guān)聯(lián)本地和遠(yuǎn)端分支后,可以直接簡(jiǎn)寫git push推送代碼。git branch -vv可以查看本地和遠(yuǎn)端分支的關(guān)聯(lián)。
git branch -D dev刪除dev分支

這大概是我每天最常的一套提交代碼的流程,只要沒有人碰我修改了的文件,就不會(huì)發(fā)生代碼沖突,一般能夠順利提交(后面會(huì)演示沖突的產(chǎn)生和解決辦法)。此外,你不會(huì)直接提交修改給遠(yuǎn)端master分支,一般會(huì)設(shè)置評(píng)審分支,日常的代碼先提交到評(píng)審分支,再發(fā)起合并請(qǐng)求,請(qǐng)相關(guān)大佬review代碼,再合并進(jìn)master分支。這個(gè)還是比較簡(jiǎn)單的分支管理策略,對(duì)于持續(xù)發(fā)布的項(xiàng)目,分支管理是更加復(fù)雜的。具體可以查閱阮一峰的博客,或者搜索“git flow”,"gitlab flow","github flow"關(guān)鍵字。
代碼沖突
在多人協(xié)作開發(fā)的情況下,代碼沖突是常有的事,每次辛辛苦苦地修改完bug,增加feature,滿心歡喜的推送代碼,等著下班回家陪媳婦,結(jié)果看到由于代碼沖突而導(dǎo)致merge失敗的錯(cuò)誤,真的有點(diǎn)想shi.

親親抱抱舉高高,沒什么大不了。下面我就以我的經(jīng)驗(yàn),演示下沖突的產(chǎn)生,以及解決辦法。
情況1:研發(fā)A修改了code1.txt文件并合并到master,此時(shí)研發(fā)B修改了mycode1.txt文件,想要合并到master(A已經(jīng)合并)

在code1.txt中增加新內(nèi)容

提交修改,并切換回master分支,merge devA

checkout devB分支,修改mycode1.txt內(nèi)容

再提交修改,并切換回master,合并devB
合并成功,這是不會(huì)發(fā)生沖突的。因此,如果每個(gè)人修改的不同的代碼文件都,合并是不會(huì)發(fā)生沖突的。
情況2:研發(fā)A和研發(fā)B合作開發(fā)新功能,A修改了code1.txt文件并合并到master,此時(shí)B在他的分支上也修改了code1.txt文件,想要合并到master(A已經(jīng)合并)

修改完code1.txt后,devA提交修改,并切換到master,合并devA

切換到devB,由于沒有更新代碼,你發(fā)現(xiàn)devB分支上的code1.txt文件沒有devA之前修改的痕跡,同樣的,devA分支上的mycode1.txt也沒有devB的修改。修改code1.txt,增加一行內(nèi)容。

切換回master,進(jìn)行合并發(fā)現(xiàn)代碼沖突,合并失敗。此時(shí)右下角顯示merging狀態(tài)。激動(dòng)人心的時(shí)刻到了!


這個(gè)時(shí)候使用git status命令可以看到,code1.txt被同時(shí)修改了,所以產(chǎn)生沖突。繼續(xù)使用git diff命令查看code1.txt中的沖突

命令行中看到上面這樣的內(nèi)容,第一反應(yīng)是崩潰的,本能的就會(huì)抵制繼續(xù)往下看,而開始尋找好用的GUI工具。這就是人們對(duì)未知事物的本能反應(yīng),抗拒。其實(shí)讀懂這些符號(hào)就沒啥了。這些內(nèi)容是實(shí)實(shí)在在得寫在了文件中的,在實(shí)際的工程中,如果有實(shí)時(shí)編譯的IDE,立馬就會(huì)報(bào)錯(cuò)。我們用vim編輯code1.txt,以圖解決沖突。

第一部分是沖突中HEAD的修改,現(xiàn)在在master分支,自然是指master的修改。第二部分就是devB的修改。

簡(jiǎn)單粗暴的刪除git自動(dòng)添加的符號(hào),完成沖突解決。注意:實(shí)際開發(fā)中,沖突的解決還是的小心一點(diǎn),兩個(gè)人當(dāng)面核對(duì)代碼沖突還是很有必要的。如果不能見面溝通,最好是在理解對(duì)方的修改后,再解決沖突。否則弄丟了對(duì)方辛辛苦苦修改的代碼,還是很崩潰的。

之后將修改add進(jìn)暫存區(qū),然后commit。merge會(huì)自動(dòng)完成。git log可以查看版本歷史
一般在工程中,推送代碼前,重新從遠(yuǎn)端倉(cāng)庫(kù)pull一份新的代碼,和本地分支做合并,在本地解決沖突后,再推送到遠(yuǎn)程倉(cāng)庫(kù)。