本文以Gitlab來講解Git使用以及持續集成, 持續集成采用的是Gitlab CI. 其他代碼托管網站,如Github, 都有自己或第三方的持續集成方案, 如Travis CI等.
1 注冊Git賬號并添加SSH密鑰
首先在gitlab.com注冊賬號
1.1 生成個人ssh密鑰
如果不存在~/.ssh/id_rsa.pub,那么首先要生成你的用戶的ssh密鑰.如果已經有ssh密鑰了,可以跳過生成密鑰步驟.
1.1.1 打開終端,輸入以下命令生成密鑰
創建ssh密鑰,并使用郵箱地址作為標簽
ssh-keygen -t rsa -b 4096 -C "你的郵箱地址"
當出現"輸入密鑰保存地址的提示",按回車保存到默認地址
Enter a file in which to save the key (~/.ssh/id_rsa):[按回車]
以下輸入密碼保護密鑰,也可以直接回車使用空密碼
Enter passphrase (empty for no passphrase): [輸入密碼]
Enter same passphrase again: [再次輸入密碼]
查看密鑰的公鑰
cat ~/.ssh/id_rsa.pub
示例輸出結果如下,,復制輸出,待會添加到Gitlab網站.
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDYw1z5WqltnMBnPzlTV7Jvxv5hV1fzC6E49rUCIe1s7cINPNcGPPep+qjFH1OibxdvD7g86vPWSn5OYCsWb2WoVTwmiSKhoJm2+qOqjXE+4liqULAbag4uFNGQdIkXWdDJomFihxGy6xHkWmUx9ILvph07j+ai4VZWlb1OHnvegPU1umXprWG9cFmNKAzexLwTma9FJSkBTaH4KSUcyO+Hm7MRq5xTfD1w1TcHI83L2x9iFuOE2yUHNs9ijfOwlRr2WwRQmL8K8U+K9rkPndosvMuvzjDScjOO1cXvoD1QbqK2w/ofYngC3mqChzOiOJqQcRPwHakOz5L3gUe5ZHvjl0BJ/icgFYX/9sS8UT9B2v6irdO2ZSab3KKDqq6w1wrKJLQqhh2vu9kxu29qzEegXZ/M4DFP5wAqn0T+GxFp0rvVvcIqao0r8BrWrgOzdcTN6YsdtXT7He2Q3xVCtkMjA9sTrqU+fKxHiPb9GAtHV6txfetX2RaBUGwnXwCHoU1uZM9fgYnyjs2mq/dSLOpzR1jsmKZHcCQ9nMpV7/sph0dji91c37JEwGG7+6D4Mkm74FF1yhYdShFIe2VhFUJYYiXjTgJzKqd3XYmw4fJRIU2PNsSYyolFnVuhGNBDu97BDoEjxaCoBJf8BqqTCPpQCI5piAt6drCoHAOSDEZ3mw== test@test.com
1.2 加入ssh密鑰
1.2.1 登陸后點擊頭像中的Settings進入個人設置
1.2.2 點擊SSH Keys一欄
1.2.3 添加ssh密鑰
就這樣, 添加密鑰就完成了,后續就可以通過ssh方式訪問git服務器了.
2 添加Git項目
2.1 點擊添加項目按鈕
2.2 輸入項目信息
在選擇項目權限的時候有幾種選擇
Private - 私有, 權限必須明確授予給用戶
Internal - 內部, 項目能夠被登陸的用戶訪問
Pubblic - 公開, 項目能夠被公開訪問
一般設置成私有或者內部
點擊Create project進行項目創建.
2.3 初始化項目
在項目創建好后會有提示指導你進行初始化.如下為可能需要做的步驟.以下小節并不是按順序做的,需要根據選擇使用. 建議每個項目根目錄有README的文檔說明項目.
2.3.1 Git全局設置
該步驟只需要在每臺機器上做一次, 用來設置用戶信息. 已經執行過的可以跳過
git config --global user.name "你的名字"
git config --global user.email "郵箱,推薦使用注冊的郵箱"
如果執行以上命令時提示git命令不存在,請安裝git后重試.
2.3.2 創建新的倉庫
git clone 項目地址,如(git@192.168.17.200:zhang.zhiyi/test.git)
cd test
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
2.3.3 已經有文件了,添加到倉庫
cd 已有文件夾
git init
git remote add origin 項目地址,如(git@192.168.17.200:zhang.zhiyi/test.git)
git add .
git commit -m "Initial commit"
git push -u origin master
2.3.4 已有Git倉庫
cd 已有倉庫文件夾
git remote add origin 項目地址,如(git@192.168.17.200:zhang.zhiyi/test.git)
git push -u origin --all
git push -u origin --tags
3. Git基本使用
以下為一些常用的git命令, 需要詳細的使用方法,請參考Git官方文檔和其他網上教程.
3.1 git clone克隆代碼
git clone git@192.168.17.200:zhang.zhiyi/test.git
使用以上命令克隆代碼,克隆成功在本地會生成項目文件夾.
3.2 git pull拉取代碼
cd test
git pull
使用以上命令拉取最新代碼,注意在使用本命令之前需要本地分支是干凈的,如果不是,需要使用git stash暫存修改,或者使用git clean刪除修改(不推薦).
3.3 git add增加文件
默認的文件是不會自動加到git倉庫中的,需要使用git add命令加入到倉庫中,沒有加入的視為未跟蹤文件,不會被commit提交.
如需要添加README.md文件
git add README.md
3.4 git status查看狀態
當需要查看當前的文件狀態的時候,使用git status,可以看到當前那些文件被修改,添加,刪除等.
git status
若輸出如下,則說明是干凈的(不代表與服務器已經同步).
$ git status
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
3.5 git commit提交代碼
當使用git add
添加好需要提交的代碼時,就可以使用git commit
進行代碼提交了.
使用命令git commit
進行提交,會自動打開編輯器,需要輸入提交的信息,一般使用一行主題就可以.對于較復雜的commit,可以加入正文,一般格式如下
一行主題,不宜過長
[空行]
正文,說明有什么更改,可以較詳細
需要注意, 主題我們一般使用祈使句,如"Fix xxx","Add xxx","Implement xxx","修復什么","增加什么","實現什么","刪除什么"等.
3.5.1 git commit -am 一次性提交
對于確定是全部修改的文件是需要提交的,并且提交信息不多時,可以用git commit -am一次性提交代碼.如
git commit -am "Add README.md"
3.6 git push推送代碼到服務器
當我們進行提交后,我們可以提交這些commits到服務器
如推送到origin地址的master分支,使用
git push origin master
如果執行了地址跟蹤(使用了-u選項),如
git push -u origin
那么可以省略掉origin,直接執行
git push master
如果把分支名省掉,則是推送當前分支
git push
很經常, 如果服務器的分支進度跟你的不一致, 會發生沖突,這時候就需要拉取服務器上的代碼后進行沖突處理.沖突處理在后面小節中講到
3.7 git checkout檢出代碼
主要有以下用途
3.7.1 切換分支
執行完后會切換到目標分支,需要當前分支是干凈的.如果本地上有修改,請先執行git stash操作暫存修改或者,否則將不允許切換分支.
git checkout dev
3.7.2 丟棄某個文件更改(恢復文件到分支未修改狀況)
git checkout -- 文件路徑
3.8 git branch新建分支
在想要新建分支的分支上執行
git branch 分支名
執行后會有分支名的名字創建好,通過以下命令可以查看現有的分支
git branch -a
刪除分支使用-d或-D選項,-D選項強制刪除.
git branch -d 要刪除的分支名
或 git branch -D 要刪除的分支名
3.9 git merge合并代碼
merge操作主要用在這種情況,你新建的一個分支想和原有分支的新更改進行合并.比如你從master分支出一個新分支dev,然后master分支得到了更新,這時候你可以通過合并master的代碼獲取到這些更新.
首先你需要切換到另一分支
git checkout dev
然后執行git merge
git merge master
這樣就會把master分支上的新更改同步到當前分支, 一般可以自動合并,但是如果有雙方都修改了的代碼,無法自動合并時,需要手動解決沖突, 后面小節會講到.
3.10 git rebase重新切換基礎分支
rebase操作主要用在這種情況:你新建了dev分支,在上面做了修改,然后master分支又更新了,然后你需要提交一個合并請求到master分支,由于你在dev分支上做了修改(未提交), 合并的時候基礎分支master已經發生了改變,這時候會合并失敗,所以要用rebase.
rebase原理是把你的dev分支修改先從當前分支上移除, 然后同步當前分支到master分支的更新. 之后在把你的更改一個個加回去dev分支.
git checkout dev
git rebase master
從此進入rebase狀態,退出rebase執行git rebase --abort
,開始合并代碼執行以下命令
git merge master
如果成功合并,執行git rebase --continue
直到所有修改都成功恢復.
git rebase --continue
rebase和merge的區別是rebase是把修改加到當前分支原分叉節點后,merge是把修改加到當前分支當前節點后.并且rebase是一步步接回去的, 每一步有沖突比較容易發現, merge是一步操作,一旦有沖突會比較多. 如果是在自己的分支上, 需要合入其他分支的更新,則使用merge, 如果是自己的修改沒有提交, 則直接使用rebase即可.
3.11 git log查看日志
查看commit日志
git log
3.12 git 解決沖突
當出現沖突后,git會提示哪些文件有沖突,如test.txt在pull的時候有沖突
git pull
Auto-merging test.txt
CONFLICT (content): Merge conflict in test.txt
Automatic merge failed; fix conflicts and then commit the result.
這時候我們打開沖突文件test.txt,找到有左右箭頭的部分
第一行
<<<<<<< HEAD
第二行
=======
修改過的第二行
>>>>>>> 6853e5ff961e684d3a6c02d4d06183b5ff330dcc
第三行
這時候在=======上面是當前分支的內容,下面是你修改的內容,你需要把這些部分修改成無沖突狀態. 無沖突狀態就是把你要的內容保留下來, 假如要保留修改的第二行, 那么修改成以下樣子.
第一行
修改過的第二行
第三行
注意要把<<<<<<<,=======,>>>>>>>的整行也刪掉.不然會被提交上去
在沖突解決后, 使用命令git add
把無沖突的文件加回去
git add test.txt
這樣test.txt就無沖突了.
還有其他沖突解決方法,比如提交合并請求的時候可以直接使用網頁上的提示解決沖突.
3.13 風格指南
未詳述的風格,請參考Git 風格指南
3.13.1 分支命名
一般遵循命名慣例,如master, dev等. 多個單詞的一般用短橫線分割.當需要開發新功能或者修復某個bug的時候,推薦"類型/具體描述"的方式命名, 類型我們一般使用單個單詞. 如新功能我們有以下命名示例
feature/support-rpm
feature/fast-boot
feature/download-prompt
對于修復bug有以下命名示例
fix/page-not-open
fix/cannot-boot
具體還有其他命名示例可以參考git branch naming best practices
3.14 .gitignore文件
該文件說明了那些文件應該被忽略,被忽略的文件將不被追蹤,在提交的時候忽略.經常把一些臨時文件,如.o文件,編譯目標等加入到這個文件中. .gitignore模板
4 Git與持續集成
有了git那么方便的工具后,可以讓持續集成的實現更方便. 本文的持續集成主要包含以下步驟:自動編譯,測試,部署.并且本文采用Gitlab CI這一工具來實現實現持續集成.
由于持續集成是一個流程, 本文在原本持續集成的基礎上, 再添加了平時開發項目應有的流程. 所以下面以項目開發流程來描述持續集成.
4.1 實施編碼規范
首先需要在團隊里面,采用標準的代碼規范. 代碼規范中應規定命名規范,開發規范,文本編碼等. C/C++的代碼規范可以參考Qt/C/C++推薦代碼規范,未說明的或者其他語言請參考Google 代碼規范,建議采用官方的代碼規范.如Python,則參考Python官方的規范.
4.2 項目開發
4.2.1 項目初始化設置
建議加入一些警告選項到編譯選項中,比如C/C++工程使用Makefile和GCC進行構建時,建議有以下編譯選項.
-W -Wall -Wextra -Wformat=2 -Wshadow -Wcast-qual -Wwrite-strings -Wmissing-include-dirs -Wunused-parameter -Wstrict-overflow=4 -Wfloat-equal
C++還可以使用以下更多選項
-Wshadow -Wcast-qual -Wwrite-strings
其他選項可以參考GCC官方文檔和其他教程.
對于內核開發,應該準備一個打開了大多數調試選項的開發版內核,如開啟死鎖檢測,魔術鍵支持等,并在虛擬機中運行該內核,避免影響主機系統.
4.2.1 編寫代碼
建議在統一代碼規范的前提下使用自己熟悉的IDE或編輯器編寫代碼,
建議建立新分支存放自己的代碼,每個新分支代表一個新功能或者一個bug修復方法.
代碼編寫的時候可用一些代碼自動格式化工具確保符合團隊代碼風格,如C/C++可以使用Clang-format工具,具體實施參考Qt/C/C++推薦代碼規范和網上教程,其他語言也有相關的工具或者IDE插件來格式化代碼.
4.2.2 靜態代碼檢查
當代碼編寫完成之后,應該使用一些代碼靜態檢查工具,C/C++有Cppcheck,Clang的scan-build工具,Visual Studio的自帶靜態代碼檢查工具.具體的使用方式請查詢相關文檔. 這些工具可以檢查代碼中一些編寫人員在編碼過程中犯的一些錯誤,如可能的空指針引用,內存泄漏,未初始化的變量,未使用的函數等.
4.2.3 動態代碼檢查
對于一些較復雜的bug, 需要使用代碼動態檢查工具才能檢查出來. 對于C/C++工程, 推薦的動態代碼檢查工具有GCC Sanitizer,Valgrind等. GCC Sanitizer是在編譯選項中加入sanitizer選項,使編譯出來的代碼在運行時能夠檢查, 會降低軟件性能, 所以一般在debug編譯中使用.
GCC Sanitizer可以支持內存泄漏,越界,線程數據競爭等眾多的錯誤,平時開發建議加入. 用法請看GCC Manual 3.11 Program Instrumentation Options
Valgrind由于比較敏感和較難自動化,一般手動調用,Valgrind也能支持很多錯誤檢測,但是平時用起來有較多的誤報,需要自己判斷一下.
4.2.4 編寫單元測試
當一個功能點開發完成后,應該編寫單元測試. 單元測試應該覆蓋關鍵函數和絕大多數路徑, 建議了解一些軟件測試的方法. 對于Qt/C/C++工程,可以使用如Google Test或者Qt Test的測試框架來實現單元測試. 其他語言也有相應的單元測試框架,在此不贅述.
4.2.5 代碼提交
當軟件功能完成, 并且編譯,靜態檢查,動態檢查,單元測試都通過時可以提交到主分支. 如果是提交到自己的開發分支,可以不一定每項測試在每次提交都要通過,但是最終提交需要都通過.每次commit建議一個完善的部分進行提交, 比如實現了某個功能的某部分,就提交. 建議小量多次提交, 后續容易恢復和查找問題.
當功能點完成之后,可以向主分支發起合入請求. 在提交合入請求之前請檢查測試都通過,并且符合代碼規范,同時沒有合并沖突.
發起合入請求后,把合入請求分配給另一個同事,其他同事如果發現有問題,填寫評論后給回提出合入請求的同事。問題都解決后分配給有合入權限的同事。
4.3 CI(Continuous integration,持續集成)部署
對于4.2節中的一些檢查部分,如果需要每次人工執行,必然會出現遺漏. 并且對于能夠自動化的東西,盡量要自動化,這樣才能提高開發效率.
在此,以Gitlab CI為例,實現項目的自動編譯,代碼檢查,測試和部署.
4.3.1 Gitlab Runner部署
Gitlab runner就是實際執行.gitlab-ci.yml中的命令的實體. 可以是Docker鏡像,VirtualBox虛擬機,也可以是真實的機器的Shell. 一般使用Docker鏡像進行構建,因為Docker鏡像每次重新運行環境是一樣的,使用真實機器的Shell需要項目保證環境的正確性.
一般Gitlab Runner的部署由管理員進行部署,部署好后就能夠被各個用戶進行使用,如果有特殊需要,需要自己的Gitlab runner,那么請參考部署自己的Gitlab CI Runner 進行部署.
要查看一個項目能夠使用的Runner,點開項目的Settings->Pipelines,綠色圖標的就是在線的可用Runner.
如果需要使用特定的Runner來執行命令,通過.gitlab-ci.yml中的tag或image字段來指定.
4.3.2 編寫.gitlab-ci.yml
Gitlab CI需要有一個.gitlab-ci.yml文件放在倉庫根目錄下對CI進行配置.
.gitlab-ci.yml文件采用的是yml格式,具體語法參考.gitlab-ci.yml的編寫,項目模板參考.gitlab-ci.yml模板.
當.gitlab-ci.yml文件編寫好后,放到倉庫根目錄并提交上去就可以, 如果沒有錯誤, Gitlab CI就會執行文件中編寫的步驟. 每次代碼提交都會觸發Gitlab CI的運行, 執行每個步驟, 如果某些修改,如只修改文檔,不會影響項目代碼正確性的話,可以跳過CI的執行.要跳過CI的執行,在commt的message里加入"[skip ci]"(不分大小寫)
一開始編寫yml文件時,可能會遇到一些問題,導致yml文件無效,建議在提交之前使用CI lint工具檢查一下yml文件的正確性, 該工具可以在gitlab項目的Pipeline->Jobs->CI lint中找到.
在.gitlab-ci.yml編寫好編譯,測試,部署的步驟并提交后,CI的配置就算是完成了.
參考資料與其他建議閱讀材料:
Git
項目開發
- 語義化版本
- Google 開源項目風格指南
- Linux下doxygen的使用
- Cppcheck 用法
- Scan-build用法
- GCC Manual 3.11 Program Instrumentation Options
- The Valgrind Quick Start Guide
- Google Test
- Qt Test
Gitlab CI部署
- 使用Gitlab進行持續集成
- CI(持續集成)入門,在gitlab上配置CI
- .gitlab-ci.yml的編寫
- .gitlab-ci.yml模板
-
部署自己的Gitlab CI Runner
以上為Gitlab CI的部署和使用,如果使用其他產品,如Github,也有很多類似服務,如Travis CI等