Git的使用以及Git協(xié)同工作流的選擇
[TOC]
為什么要使用Git
- Git 是一個(gè)分布式的版本管理工具馅笙,而且可以是單機(jī)版的浆洗,所以催束,你在沒(méi)有網(wǎng)絡(luò)的時(shí)候同樣可以提交(commit)代碼。對(duì)于我們來(lái)說(shuō)伏社,這意味著在出差途中或是沒(méi)有網(wǎng)絡(luò)的環(huán)境中依然可以工作寫代碼。
- Git 從一個(gè)分支向另一個(gè)分支合并代碼的時(shí)候塔淤,會(huì)把要合并的分支上的所有提交一個(gè)一個(gè)應(yīng)用到被合并的分支上摘昌,合并后也能看得到整個(gè)代碼的變更記錄。而其他的版本管理工具則不能高蜂。
- Git 切換分支的時(shí)候通常很快聪黎。不像其他版本管理器,每個(gè)分支一份拷貝
- Git 有很多非常有用的命令备恤,讓你可以很方便地工作稿饰。
-
git stash
命令,可以把當(dāng)前沒(méi)有完成的事先暫存一下露泊,然后去忙別的事喉镰。 -
git cherry-pick
命令可以讓你有選擇地合并提交。 -
git grep $regexp $(git rev-list --all)
可以用來(lái)在所有的提交中找代碼惭笑。因?yàn)槎际潜镜夭僮髀履罚阅銜?huì)覺(jué)得飛快生真。 - ... ...
- 除此之外,由 Git 衍生出來(lái)的 GitHub/GitLab 可以幫你很好地管理編程工作捺宗,比如 wiki柱蟀、fork、pull request蚜厉、issue……集成了與編程相關(guān)的工作长已。
概念
版本庫(kù) Repository
理解成一個(gè)目錄,這個(gè)目錄里面的所有文件都可以被Git管理起來(lái)昼牛,每個(gè)文件的修改术瓮、刪除,Git都能跟蹤匾嘱,以便任何時(shí)刻都可以追蹤歷史斤斧,或者在將來(lái)某個(gè)時(shí)刻可以“還原”。 簡(jiǎn)單理解成 .git目錄霎烙。
工作區(qū) working directory
就是你在電腦里能看到的目錄撬讽,比如我的test目錄就是一個(gè)工作區(qū):
暫存區(qū) stage/index
Git的版本庫(kù)里存了很多東西,其中最重要的就是稱為stage(或者叫index)的暫存區(qū)悬垃。
[圖片上傳失敗...(image-dd4519-1520338302455)]
第一步是用git add把文件添加進(jìn)去游昼,實(shí)際上就是把文件修改添加到暫存區(qū);
[圖片上傳失敗...(image-f3ca47-1520338302455)]
第二步是用git commit提交更改尝蠕,實(shí)際上就是把暫存區(qū)的所有內(nèi)容提交到當(dāng)前分支烘豌。
遠(yuǎn)程倉(cāng)庫(kù) origin repository
遠(yuǎn)程服務(wù)器上的git倉(cāng)庫(kù), 讓其他人通過(guò)該倉(cāng)庫(kù)來(lái)協(xié)作看彼。
分支 Branch
因?yàn)閯?chuàng)建廊佩、合并和刪除分支非常快靖榕,所以Git鼓勵(lì)你使用分支完成某個(gè)任務(wù)标锄,合并后再刪掉分支。
標(biāo)簽 Tag
在branch上面打tag茁计, 可以用來(lái)做版本管理料皇。
HEAD指針
HEAD指向的版本就是當(dāng)前版本,因此星压,Git允許我們?cè)诎姹镜臍v史之間穿梭
用Shell還是GUI
- 圖形化工具 : SoureTree, 或者IDE里面的git插件
- 圖形化界面更加直觀践剂, 敲命令更快, 看個(gè)人喜好娜膘。
日常場(chǎng)景
初次使用
- 本地安裝git
- (可選)本地安裝圖形化工具SourceTree
- (可選)IDE中安裝git插件并配置
- 在github 創(chuàng)建代碼庫(kù)
- 復(fù)制項(xiàng)目地址 比如:git@git.xxx.com:themis/themis.git
- git clone git@git.xxx.com:themis/themis.git逊脯。 Git支持多種協(xié)議,默認(rèn)的git://使用ssh劲绪,但也可以使用https等其他協(xié)議男窟。ssh需要用到公私鑰盆赤,https需要用戶名密碼。
提交文件
git add file1.txt
git add file2.txt file3.txt --將文件添加到暫存區(qū)
git commit -m "add 3 files." --將暫存區(qū)內(nèi)容提交到本地
git push origin master -- 將本地內(nèi)容推送到遠(yuǎn)程
創(chuàng)建分支歉眷,切換分支牺六,合并分支,刪除分支
git branch dev -創(chuàng)建
git checkout dev -切換
git branch -查看當(dāng)前分支
git merge branch-name -合并某分支到當(dāng)前分支
git branch -d branch-name - 刪除本地分支
git push origin branch-name - 推送到遠(yuǎn)程倉(cāng)庫(kù)
注意:如果此分支是需要走cd發(fā)布的汗捡,請(qǐng)?jiān)趐hoebus平臺(tái)上創(chuàng)建淑际,不然平臺(tái)無(wú)法獲取新建的分支。
合并分支中的沖突解決
git checkout -b feature1
修改readme.txt
git add readme.txt
git commit -m '11'
git checkout master
git add readme.txt
git commit -m '22'
git merge feature1 -- 這一步就沖突了,修改完再提交
版本回退
回退本地版本
git reset --hard commit-id
強(qiáng)制推送到遠(yuǎn)程分支
git push -f
參考附錄3
多人協(xié)作
多人協(xié)作的工作模式通常是這樣:
1. 首先扇住,可以試圖用git push origin branch-name推送自己的修改春缕;
2. 如果推送失敗,則因?yàn)檫h(yuǎn)程分支比你的本地更新艘蹋,需要先用git pull試圖合并锄贼;
3. 如果合并有沖突,則解決沖突女阀,并在本地提交宅荤;
4. 沒(méi)有沖突或者解決掉沖突后,再用git push origin branch-name推送就能成功浸策!
那么 多人多版本多環(huán)境協(xié)作怎么搞冯键?這時(shí)候就需要有一個(gè)工作流來(lái)指導(dǎo)我們進(jìn)行代碼管理。
工作流
中心式協(xié)同工作流
Git 是可以像 SVN 這樣的中心工作流一樣工作的庸汗。很多程序員都是在采用這樣的工作方式惫确。
這個(gè)過(guò)程一般是下面這個(gè)樣子的。
- 從服務(wù)器上做git pull origin master把代碼同步下來(lái)蚯舱。
- 改完后改化,git commit到本地倉(cāng)庫(kù)中。
- 然后git push origin master到遠(yuǎn)程倉(cāng)庫(kù)中枉昏,這樣其他同學(xué)就可以得到你的代碼了所袁。
- 如果在第 3 步發(fā)現(xiàn) push 失敗,因?yàn)閯e人已經(jīng)提交了凶掰,那么你需要先把服務(wù)器上的代碼給 pull 下來(lái)。
功能分支協(xié)同工作流
上面的那種方式有一個(gè)問(wèn)題蜈亩,就是大家都在一個(gè)主干上開(kāi)發(fā)程序懦窘,對(duì)于小團(tuán)隊(duì)或是小項(xiàng)目你可以這么干,但是對(duì)比較大的項(xiàng)目或是人比較多的團(tuán)隊(duì)稚配,這么干就會(huì)有很多問(wèn)題畅涂。
最大的問(wèn)題就是代碼可能干擾太嚴(yán)重。尤其是道川,我們想安安靜靜地開(kāi)發(fā)一個(gè)功能時(shí)午衰,我們想把各個(gè)功能的代碼變動(dòng)隔離開(kāi)來(lái)立宜,同時(shí)各個(gè)功能又會(huì)有多個(gè)開(kāi)發(fā)人員在開(kāi)發(fā)。
這時(shí)臊岸,我們不想讓各個(gè)功能的開(kāi)發(fā)人員都在 Master 分支上共享他們的代碼橙数。我們想要的協(xié)同方式是這樣的:同時(shí)開(kāi)發(fā)一個(gè)功能的開(kāi)發(fā)人員可以分享各自的代碼,但是不會(huì)把代碼分享給開(kāi)發(fā)其他功能的開(kāi)發(fā)人員帅戒,直到整個(gè)功能開(kāi)發(fā)完畢后灯帮,才會(huì)分享給其他的開(kāi)發(fā)人員(也就是進(jìn)入主干分支)。
因此逻住,我們引入“功能分支”钟哥。這個(gè)協(xié)同工作流的開(kāi)發(fā)過(guò)程如下。
- 首先使用 git checkout -b new-feature 創(chuàng)建 “new-feature”分支瞎访。
- 然后共同開(kāi)發(fā)這個(gè)功能的程序員就在這個(gè)分支上工作腻贰,進(jìn)行 add、commit 等操作扒秸。
- 然后通過(guò) git push -u origin new-feature 把分支代碼 push 到服務(wù)器上播演。
- 其他程序員可以通過(guò)git pull --rebase來(lái)拿到最新的這個(gè)分支的代碼。
- 最后通過(guò) Pull Request 的方式做完 Code Review 后合并到 Master 分支上鸦采。
就像上面這個(gè)圖顯示的一樣宾巍,紫色的分支就是功能分支,合并后就會(huì)像上面這個(gè)樣子渔伯。
GitFlow 協(xié)同工作流
在真實(shí)的生產(chǎn)過(guò)程中顶霞,前面的協(xié)同工作流還是不能滿足工作的要求锣吼。這主要因?yàn)槲覀兊纳a(chǎn)過(guò)程是比較復(fù)雜的古徒,軟件生產(chǎn)中會(huì)有各式各樣的問(wèn)題寺惫,并要面對(duì)不同的環(huán)境。我們要在不停地開(kāi)發(fā)新代碼的同時(shí)腔呜,維護(hù)線上的代碼膝但,于是,就有了下面這些需求。
希望有一個(gè)分支是非常干凈的,上面是可以發(fā)布的代碼,上面的改動(dòng)永遠(yuǎn)都是可以發(fā)布到生產(chǎn)環(huán)境中的。這個(gè)分支上不能有中間開(kāi)發(fā)過(guò)程中不可以上生產(chǎn)線的代碼提交是嗜。
希望當(dāng)代碼達(dá)到可以上線的狀態(tài)時(shí),也就是在 alpha/beta release 時(shí)甫题,在測(cè)試和交付的過(guò)程中芹扭,依然可以開(kāi)發(fā)下一個(gè)版本的代碼麻顶。
最后赦抖,對(duì)于已經(jīng)發(fā)布的代碼,也會(huì)有一些 Bug-fix 的改動(dòng)辅肾,不會(huì)將正在開(kāi)發(fā)的代碼提交到生產(chǎn)線上去队萤。
面對(duì)這些需求,前面的那些協(xié)同方式就都不行了矫钓。因?yàn)槲覀儾粌H是要在整個(gè)團(tuán)隊(duì)中共享代碼要尔,我們要的更是管理好不同環(huán)境下的代碼不互相干擾。說(shuō)得技術(shù)一點(diǎn)兒就是新娜,要管理好代碼與環(huán)境的一致性赵辕。
為了解決這些問(wèn)題,GitFlow 協(xié)同工作流就出來(lái)了概龄。
整個(gè)代碼庫(kù)中一共有五種分支还惠。
- (長(zhǎng)期)Master 分支。也就是主干分支私杜,用作發(fā)布環(huán)境蚕键,上面的每一次提交都是可以發(fā)布的。
- (短期) Feature 分支衰粹。也就是功能分支锣光,用于開(kāi)發(fā)功能,其對(duì)應(yīng)的是開(kāi)發(fā)環(huán)境铝耻。
- (長(zhǎng)期)Developer 分支誊爹。是開(kāi)發(fā)分支,一旦功能開(kāi)發(fā)完成田篇,就向 Developer 分支合并替废,合并完成后,刪除功能分支泊柬。這個(gè)分支對(duì)應(yīng)的是集成測(cè)試環(huán)境椎镣。
- (短期) Release 分支。當(dāng) Developer 分支測(cè)試達(dá)到可以發(fā)布狀態(tài)時(shí)兽赁,開(kāi)出一個(gè) Release 分支來(lái)状答,然后做發(fā)布前的準(zhǔn)備工作。這個(gè)分支對(duì)應(yīng)的是預(yù)發(fā)環(huán)境刀崖。之所以需要這個(gè) Release 分支惊科,是我們的開(kāi)發(fā)可以繼續(xù)向前,不會(huì)因?yàn)橐l(fā)布而被 block 住而不能提交亮钦。一旦 Release 分支上的代碼達(dá)到可以上線的狀態(tài)馆截,那么需要把 Release 分支向 Master 分支和 Developer 分支同時(shí)合并,以保證代碼的一致性。然后再把 Release 分支刪除掉蜡娶。
- (短期)Hotfix 分支混卵。是用于處理生產(chǎn)線上代碼的 Bug-fix,每個(gè)線上代碼的 Bug-fix 都需要開(kāi)一個(gè) Hotfix 分支窖张,完成后幕随,向 Developer 分支和 Master 分支上合并。合并完成后宿接,刪除 Hotfix 分支赘淮。
Git flow的優(yōu)點(diǎn)是清晰可控,缺點(diǎn)是相對(duì)復(fù)雜睦霎,需要同時(shí)維護(hù)兩個(gè)長(zhǎng)期分支梢卸。具體了解可以參考附錄2。
GitHub 協(xié)同工作流
過(guò)于簡(jiǎn)單碎赢,不適合低剔。具體了解可以參考附錄2。
GitLab 協(xié)同工作流
- 引入環(huán)境分支肮塞,如下圖所示襟齿,其包含了開(kāi)發(fā)環(huán)境(master)、預(yù)發(fā)布(Pre-Production)和生產(chǎn)(Production)分支枕赵。
上游優(yōu)先原則:開(kāi)發(fā)分支是預(yù)發(fā)分支的"上游"猜欺,預(yù)發(fā)分支又是生產(chǎn)分支的"上游"。代碼的變化拷窜,必須由"上游"向"下游"發(fā)展开皿。比如,生產(chǎn)環(huán)境出現(xiàn)了bug篮昧,這時(shí)就要新建一個(gè)功能分支赋荆,先把它合并到master,確認(rèn)沒(méi)有問(wèn)題懊昨,再cherry-pick到pre-production窄潭,這一步也沒(méi)有問(wèn)題,才進(jìn)入production酵颁。
只有緊急情況嫉你,才允許跳過(guò)上游,直接合并到下游分支躏惋。
- (不一定有這個(gè)需求)而有些時(shí)候幽污,我們還會(huì)有不同版本的發(fā)布,所以簿姨,還需要有各種 release 的分支距误。如下圖所示。Master 分支是一個(gè) roadmap 分支,然后深寥,一旦穩(wěn)定了就建穩(wěn)定版的分支攘乒,如 2.3.stable 分支和 2.4.stable 分支,其中可以 cherry-pick master 分支上的一些改動(dòng)過(guò)去惋鹅。
這樣也就解決了兩個(gè)問(wèn)題:
- 環(huán)境和代碼分支對(duì)應(yīng)的問(wèn)題;
- 版本和代碼分支對(duì)應(yīng)的問(wèn)題殉簸。
我的選擇
使用GitLab 協(xié)同工作流
其他操作
忽略特殊文件
- 用.gitignore文件處理
- 參考 https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000/0013758404317281e54b6f5375640abbb11e67be4cd49e0000
本地修改不提交到遠(yuǎn)程倉(cāng)庫(kù)
本地修改不提交到遠(yuǎn)程倉(cāng)庫(kù)
git update-index --assume-unchanged 文件名
取消本地忽略
git update-index --no-assume-unchanged 文件名
cherry-pick
- 選擇某一個(gè)分支中的一個(gè)或幾個(gè)commit(s)來(lái)進(jìn)行操作
- 參考 http://www.reibang.com/p/8fbb12781d05