目錄
一、Git簡介
二、Git的一些基本操作
?1、安裝Git
?2、配置Git全局用戶名和全局郵箱
?3、創建本地倉庫、創建遠程倉庫、本地倉庫關聯遠程倉庫
?4、代碼重置revert
?5、節點閱讀、分支和分支小標簽閱讀、創建分支和合并分支閱讀
三、一些規范
?1、gitignore規范
?2、commit規范
?3、分支規范
?4、打tag規范
一、Git簡介
Git和SVN的區別
Git是分布式版本控制系統,SVN是集中式版本控制系統。
所謂分布式主要是指本地倉庫這個概念,也就是說我們每個人都可以在自己的電腦上通過本地倉庫來進行源代碼版本控制,它是去中心化的、不需要聯網的;所謂集中式主要是指遠程倉庫這個概念,也就是說我們每個人都必須直接面向同一個遠程倉庫來進行源代碼版本控制,它是中心化的、需要聯網的。當然Git也有遠程倉庫這個概念,但它的遠程倉庫并非一個必要角色,而只是為了方便不同空間、多人之間的合作而擴展的一個輔助工具。
Git的分區
Git有工作區、暫存區、本地倉庫、遠程倉庫四個分區,工作區--添加add-->
暫存區--提交commit-->
本地倉庫--推送push-->
遠程倉庫--拉取pull-->
本地倉庫。
工作區:項目目錄下.git
以外的部分,存儲著我們的源代碼。
本地倉庫:項目目錄下.git
- 暫存區:存儲著準備添加到版本控制的源代碼;
- 貯存區:存儲著已經添加到版本控制的源代碼。
廣義的本地倉庫由暫存區和貯存區兩部分組成,但是為了方便描述,后面我們提到本地倉庫時都是指狹義的本地倉庫——即貯存區。
遠程倉庫:GitHub || GitLab || Gitee,本地倉庫的一個云端備份。
Sourcetree里能看到工作區和暫存區,看不到本地倉庫和遠程倉庫。
Git的文件狀態
- 紫色的
?
:只可能出現在工作區,代表我們新增了該文件、還未添加到版本控制 <==> 對應Xcode里的?
——untracked - 綠色的
+
:只可能出現在暫存區,代表我們新增了該文件、準備添加到版本控制 <==> 對應Xcode里的A
——added - 黃色的
...
:有可能出現在工作區或暫存區,代表我們修改了該文件的內容 <==> 對應Xcode里的M
——modified - 橙色的
!
:有可能出現在工作區或暫存區,代表該文件里有沖突需要我們解決 <==> 對應Xcode里的C
——conflicted - 紅色的
-
:有可能出現在工作區或暫存區,代表我們刪除了該文件 <==> 對應Xcode里的D
——deleted
二、Git的一些基本操作
1、安裝Git
安裝SourceTree,Git也會被自動安裝。
2、配置Git全局用戶名和全局郵箱
配置Git全局用戶名和全局郵箱,將來我們每次提交的“作者”就是“全局用戶名 <全局郵箱>”了。
3、創建本地倉庫、創建遠程倉庫、本地倉庫關聯遠程倉庫
創建本地倉庫
- 先創建一個項目
- 創建好后,項目目錄下就這倆文件
- 為項目創建本地倉庫
- 目標路徑選擇剛才的項目
- 點擊創建后,就為項目創建好了本地倉庫
- 我們會發現項目目錄下多了一個隱藏文件夾
.git
,它就是用來做源代碼版本控制的本地倉庫,如果我們想讓項目脫離版本控制,只需要把.git
刪掉就可以了
- 添加
.gitignore
文件,在項目目錄下創建一個.gitignore
文件,然后去gitignore.io這個網站搜索一個現成的.gitignore
文件,把內容復制到我們創建的.gitignore
文件里即可
- 添加
README.md
文件,在項目目錄下創建一個README.md
文件,然后寫一些關于該項目如何使用的指導即可
- 此時把所有的文件都提交,做一次
init commit
創建遠程倉庫
- 遠程倉庫可以是GitHub || GitLab || Gitee,這里我們選擇Gitee做演示。注意創建遠程倉庫的時候,創建一個完全空的倉庫,不要勾選創建
.gitignore
文件和README.md
文件,否則本地倉庫關聯遠程倉庫的時候容易出問題
- 點擊創建后,就創建好了遠程倉庫
本地倉庫關聯遠程倉庫
本地倉庫關聯遠程倉庫的方式有兩種:HTTPS或SSH,它們倆的主要區別就是HTTPS直接用就行,但是后面每次拉取代碼或推送代碼都得輸入GitHub || GitLab || Gitee的用戶名和密碼(存儲到鑰匙串好像就不用輸入了),而SSH則需要先配置公鑰和私鑰后才能使用,以后隨便拉取代碼或推送代碼,這里我們采用SSH的方式來演示。
- 創建和配置SSH公鑰和私鑰
終端輸入ssh-keygen -t ed25519 -C "ineyee@foxmail.com"
(后面跟的是你的郵箱),然后連摁三次回車就完事了(期間不用輸地址,會有一個默認的存儲公鑰和私鑰的地址;期間不用輸密碼和確認密碼,否則將來在推送代碼和拉取代碼的時候就得輸密碼)。
打開.ssh
文件夾,就可以看到生成的公鑰和私鑰。
打開.pub
公鑰文件,把里面的內容全部復制下來。
打開Gitee,點擊你的頭像 --> 設置 --> SSH公鑰,把復制下來的內容填進去,點擊確定即可。
然后在終端輸入ssh -T git@gitee.com
(如果是GitHub || GitLab,則輸入ssh -T git@github.com
|| ssh -T git@gitlab.com
),因為首次使用需要確認并添加主機到本機SSH可信任列表,這就配置成功了。
- 把遠程倉庫的SSH地址復制下來
- 關聯本地倉庫
4、代碼重置revert
工作區重置
工作區的內容,如果我們不想要了,可以采用工作區重置。
暫存區重置
暫存區的內容,如果我們不想要了,可以采用暫存區重置。
本地倉庫重置
選中要重置到的某次提交,右鍵選擇“將XXX重置到這次提交”。
- 軟合并(麻煩、一般使用混合合并代替;最終效果其實和混合合并一樣,但是比混合合并少做了一步“暫存區 --> 工作區”的操作)
軟合并是指我們重置到這次提交后,這次提交后面的提交記錄還會給我們保存在暫存區,以備我們可能還會用到這些代碼,如果用不到直接重置掉即可。
- 混合合并(靠譜、常用;相當于軟合并后,我們手動把暫存區的代碼移動到工作區)
混合合并是指我們重置到這次提交后,這次提交后面的提交記錄還會給我們保存在工作區,以備我們可能還會用到這些代碼,如果用不到直接重置掉即可。
- 強行合并(危險、慎用;相當于混合合并后,我們手動把工作區的代碼重置掉)
混合合并是指我們重置到這次提交后,這次提交后面的提交記錄全部抹掉、不會給我們保存在暫存區或工作區,我們就丟失掉這些可能還會有用的代碼了,如果你非常確定這些代碼你就是用不到了,再選擇強行合并。
遠程倉庫重置
方式一、不推薦:完成了上面的本地倉庫重置,我們可以通過本地倉庫重置 + 強制推送的方式達到遠程倉庫重置的效果,但是這種方式會抹掉提交記錄,在團隊開發中是不推薦的。
方式二、推薦:推薦的方式是本地倉庫重置兩次(強行合并一次 + 軟合并一次) + 提交、推送的方式,這種方式可以保留提交記錄。
先把本地倉庫重置到3,注意選擇強行合并,以便本地倉庫丟掉4、5、6這三次提交的代碼,當然你也可以選擇軟合并或混合合并、然后再自己重置掉保存下來的代碼,這樣本地倉庫就可以比遠程倉庫少掉不想要的代碼了。
然后再把本地倉庫重置到遠程倉庫當前所在的節點6,注意需要選擇軟合并,這樣我們剛才刪除4、5、6三次提交代碼的操作就會被扔到暫存區了(如果想不通,可以這樣想,代碼多的那個節點往代碼少的那個節點重置時,選擇軟合并是把多出來的代碼——即增加代碼操作扔到暫存區了;那代碼少的那個節點往代碼多的那個節點重置時,選擇軟合并是把少出來的代碼扔到暫存區了——即刪除代碼操作)
此時我們做一次提交、推送操作,就完成遠程倉庫重置了。
5、節點閱讀、分支和分支小標簽閱讀、創建分支和合并分支閱讀
節點閱讀
我們每一次提交都會形成一個節點,當前所在的節點用一個空心圓圈表示,以前的節點用一個實心圓點表示。
分支和分支小標簽閱讀
創建分支和合并分支閱讀
master分支小標簽是藍色的,它對應的節點樹就是藍色的那條;dev分支小標簽是粉色的,它對應的節點樹就是粉色的那條。dev分支是從master分支的“重置:到3”節點處創建出來的,提交了三次,然后就合并到了master分支(注意:Git會自動幫我們把dev分支的多次提交合并成一次“Merge brach ‘xxx’”的提交合并到master分支),合并分支完成后master分支就會落到“Merge brach ‘xxx’”的這一次提交節點上。
三、一些規范
1、gitignore規范
忽略精確的文件:
Extra.txt
;忽略所有后綴為此的:*.dll
;忽略某個文件夾下所有的文件:abc/
。
我們項目里的.gitignore
文件通常都是去gitignore.io這個網站搜索一個現成的.gitignore
文件,把內容復制到我們創建的.gitignore
文件里,不過復制完后還有幾點需要注意:
-
.gitignore
文件本身不能忽略,要加入版本控制,保證每個開發者忽略的東西都一樣。不過這個我們不用動,.gitignore
文件模板本來就沒忽略.gitignore
文件; -
README.md
文件不能忽略,要加入版本控制,保證每個開發者讀到的東西都一樣。不過這個我們不用動,.gitignore
文件模板本來就沒忽略README.md
文件; -
xcuserdata
文件夾得忽略,不要加入版本控制,它里面存儲的是每個開發者Xcode的一些情況,如Xcode的目錄展開情況、Xcode里面打的斷點等,這些東西大家沒必要共享。不過這個我們不用動,.gitignore
文件模板本來就忽略了xcuserdata
文件夾; -
project.pbxproj
文件不能忽略,要加入版本控制,它里面存儲的是項目里源文件的描述信息,如我們新增了一個文件、移動了一個文件的目錄、重命名了一個文件等,這些東西大家需要共享。不過這個我們不用動,.gitignore
文件模板本來就沒忽略project.pbxproj
文件; -
project.xcworkspce
文件不能忽略,要加入版本控制,它對應于project.pbxproj
文件、存儲的是工作區源文件的描述信息; - Pods文件夾得忽略,不要加入版本控制,它里面存放的是所有三方庫的源碼文件,我們一般不把它放到版本控制里,是為了避免不同分支依賴了不同版本的三方庫、進而導致在分支合并時的沖突,而是把Podfile和Podfile.lock文件加入版本管理,團隊其他人員拉取代碼后得執行一下pod install項目才能跑起來。這個需要我們去
.gitignore
文件里打開/Pods
的注釋,.gitignore
文件模板默認是沒忽略Pods文件夾的。
2、commit規范
格式:type: content
例如:feature: 新增JS彈窗功能
、bugfix: 修復JS彈窗bug
1類型type
- feature:新增xxx功能(常用)
- bugfix:修復xxxbug(常用)
- test:測試xxx功能(常用)
- build:依賴項的修改,例如Podfile文件的修改等(常用)
- chore:不修改源代碼的其余修改,例如調整文件目錄順序等(常用)
- docs:變更xxx文檔
- style:變更xxx代碼格式或注釋
- refactor:重構xxx功能或方法
- revert:重置到xxx(常用)
2內容content
末尾不要加。
或.
標點
3、分支規范
創建分支規范和gitflow工作流
創建新項目的時候,我們會固定創建兩個常駐分支:master分支和develop分支,develop分支的當前節點永遠應該 >= master分支的當前節點。
1、master分支(常駐)
發布分支或者叫線上分支或者
對應線上最穩定的代碼
2、develop分支(常駐)
開發分支
develop分支對應當前功能最全代碼
上面兩個分支在創建好后就沒什么好說的了,我們平常的工作流主要是下面三個分支。
3、feature分支
功能分支
創建:當需要開發一個新功能時,從develop分支的最新節點處拉一個feature分支出來,之所以要從最新的節點處拉是為了保證該feature分支是基于最全的代碼開發,如果不是從最新的節點處創建出來,那就很有可能后面的節點已經提供了某些公共的方法,你這個分支卻沒有還得自己寫,這會增加工作量和沖突的概率;分支名為feature/功能描述,例如我們要開發一個點贊功能,分支名可以命名feature/add_like_butto
開發 + 測試:新功能都在該分支上開發,新功能開發完成后,測試需要先在該分支回歸,確保該功能的代碼時沒問題健全的
刪除:該分支測試完沒問題了,如果下個版本不準備發布這個功能那就不要合到develop、還是放著這個分支就行了,等哪個版本想發布這個功能了再合到develop;如果下個版本準備發布該功能,那就開發者發起MR,管理員把該分支的代碼合并回develop分支,注意此時先不要刪除feature分支、feature分支要等該功能的確上線后再刪除(原因見下面的疑問)
4、release分支
預發布分支或者叫預上線分支
創建:當我們開發完一個feature合并到develop后,測試可能就會問我們要一個最終包來進行最后一波集中測試、修復bug和準備發布,此時我們就需要在develop分支的最新節點(保證有自己這個feature分支代碼的同時也保證有別的團隊該有的代碼)處創建出來一個release預發布分支交給測試去測試,名字一般就是release/下一個要發布的版本
修復bug + 測試:最后一波bug的修復都要在該分支修復,繼續測試,直到認為沒bug準備發布
結束:該分支回歸完成后,那此時release分支上是最全的代碼,開發者發起MR,管理員把release分支的代碼合并回develop分支以保證develop分支的代碼為最新,并合并到master分支、在master分支上打包發布、在master分支上打tag,注意此時先不要刪除release分支、release分支要等該功能的確上線后再刪除(原因見下面的疑問)
(1)此時你可能會有個疑問:既然feature分支已經單獨測試過一波了,而且代碼已經很健全了,為什么把它合回develop分之后,還要再開出一個release分支再測一遍呢,為什么不直接把develop合并到master上發布呢,要release分支不是多此一舉嗎?上圖中1的那個節點處就描述的是這個現象。
當然最簡單地回答就是再對你這個feature分支的功能測試一遍,以免第一波測試遺漏,這個回答也可以,但不是根本原因,因為你完全可以在feature分支上多測幾遍嘛。其實最重要的原因是我們的一次發布可能不僅是你的一個feature分支,而是有好團隊的幾個功能一起發布,就像上圖中的2一樣,功能1和功能2都要在3.0.0這個版本發布,那如果沒有release分支的話,就是功能1分支開發完直接合并到master,功能2分支開發完又直接合并到master,沒有中間的release做集中過渡,那就可能存在這樣一個問題:功能1單獨測試的時候是ok的,功能2單獨測試的時候也是ok的,于是大家認為那它們合并到master后也都是ok的,但其實兩個功能之間可能會存在對一些公共數據的處理而互相影響,也就是說單獨測試是ok的,但合在一起就不ok了,所以如果develop直接把兩個feature帶進到master就出bug了,所以release分支的定位其實就是發布前的最后集中測試,注意“集中測試”這個說法,所以“集中測試”就是指把多個要發布的feature再合并到一起測一波,即便每個feature分支單獨> 測起來是ok的
所以release分支更多的價值體現在某一個版本要同時發布多個feature分支時,一個版本如果只發一個feature分支確實release分支存在不存在沒多大區別,但流程規范嘛最好還是走走,無論是這次版本只發一個feature還是要發多個feature。
(2)你可能還會有第二個疑問:我們把release分支最后一波都測完了,結果上級決定臨時不發布先開發先合并上來的feature1、feature2了,只發布后開發后合并上來的feature3,怎么辦?
這就是我們在把feature分支合并到develop后不刪除feature分支的原因,此時我們revert掉這三次提交,然后再單獨把feature3給合并上來,因為從提交記錄中間抽走feature1、feature2來revert很難搞,容易出錯。
5、hotfix分支
緊急修復線上bug分支
創建:當發現線上有bug時,從master分支最新的節點處拉一個hotfix分支出來,分支名為bugfix/修復bug描述,例如我們要修復一個用戶頭像的UI bug,分支名可以命名為bugfix/fix_avatar_ui_bug
修復bug + 測試:bug的修復都要在該分支修復,繼續測試,直到認為沒bug準備發布
刪除:該分支回歸完成后,那此時hotfix分支上是最全的代碼,開發者發起MR,管理員把hotfix分支的代碼合并回develop分支以保證develop分支的代碼為最新,并合并到master分支、在master分支上打包發布、在master分支上打tag,就可以刪除release分支來保持分支的清晰整潔
使用Gitflow工作流的優點包括:
嚴格的分支管理,使團隊成員清楚各個分支的作用和使用規則。
分離穩定版本和開發版本,有助于保持生產環境的穩定性。
提供了一種結構化的方式來管理功能開發、版本發布和緊急修復。
然而,Gitflow工作流也可能帶來一些挑戰:
如分支數量增多、合并沖突的潛在增加等。
因此,團隊在選擇工作流時應權衡其優點和挑戰,并根據項目的特定需求進行調整。
合并分支規范
1、master分支保護和合并請求(PR/MR,Pull Request/Merge Request)
為了減少事故的發生,我們一般會做master分支保護,不允許開發者直接往master分支上推送代碼。
而是讓開發者在需要合并其它分支到master分支時提交一個合并請求,項目管理者收到合并請求后把經過code review的代碼合并到master分支上。
建議開發者在提交合并請求之前,先把master分支的代碼合并到feature分支/bugfix分支,看看代碼是否有沖突,有沖突的話優先在feature分支/bugfix分支上解決掉,這樣可以保證開發者的分支在合并到master分支時沒有沖突。
2普通合并和變基合并
想保留提交記錄就用普通合并,不想保留提交記錄就用變基合并rebase。
普通合并:Git會自動幫我們把dev分支的多次提交合并成一次“Merge brach ‘xxx’”的提交合并到master分支,dev分支的提交記錄會被記錄在提交歷史上。
reabase:Git不會幫我們把dev分支的多次提交合并成一次統一的提交,而是直接把dev的幾次提交平移合并到master分支,dev分支的提交記錄不會被記錄在提交歷史上,就像我們是直接在master分支上修改的一樣。
4、打tag規范
每當release分支上線后,我們都會給release分支打一個和線上版本號一致的tag并推送到遠程倉庫,這樣方便我們查看版本、追蹤問題。
版本號一般由四個部分組成:MAJOR、MINOR、PATCH、BUILD。
MAJOR是指主版本號,通常在重大更新的時候才會需要更新主版本號。例如iOS每年都會更新一個主版本號;而對于第三方庫來說,主版本號的更新,表示該庫的API新增了重大功能,或者引入了不可兼容的更新。
MINOR是指副版本號,用于小功能的改善。例如iOS14在發布主版本后,在一年內可能發布多個副版本如14.1、14.2來完善其系統功能;而對于第三方庫來說,副版本號的更新就是新增一些API,但不包含不可兼容的更新。
PATCH是指補丁版本號,一般用于bugfix以及修復安全性問題等。對于第三方庫來說,補丁版本號的更新也不應該有不可兼容的更新。雖然實際操作中這會有些困難,但我們可以通過把原有 API 標記為 deprecated,或者為新API參數提供默認值等辦法來解決。
BUILD是指構建版本號,通常在內部測試時使用。一般當我們使用CI服務器進行自動構建時,構建版本號會自動更新。