企業發展能否“既要又要還要”?手握低程式碼,得工具者得天下
一、概述
這篇文章是本系列的第 3 篇。通過前兩篇,我們已經掌握了 git 的最常用的命令以及相關操作。在本篇文章,我們將學習企業開發中最常用的協同方式,那就是基於 git 分支進行協同開發。如果你還沒有閱讀過前兩篇文章,建議先閱讀。
1. git 基本操作方法,記錄幾條命令將自己的程式碼託管到 github
二、git 分支
1. 分支簡介
git 通過儲存一系列不同時刻的快照,來記錄檔案在不同時刻的差異。git 的分支,本質上是指向提交物件的可變指標。git 的預設分支名是 master
。在多次提交操作之後,你其實已經有一個指向最後那個提交物件的 master
master
分支會在每次提交時自動向前移動。
git 的 master
分支並不是一個特殊分支。跟其它分支完全沒有區別。之所以幾乎每一個倉庫都有 master
分支,是因為 git init
命令預設建立它,並且大多數人都懶得去改動它。
實際上,不同的開發團隊的分支管理規範不一樣,但原理是相同的。
下面是一個典型的 git 分支的工作流示例圖
Master:這裡指 master
主分支,master
分支記錄的重大版本更新
Develop:這裡指 develop
開發分支,從 master
分支建立,變動比較大,通常待上線的功能合併到這個分支
Feature:這裡指 feature
功能分支,從 develop
分支建立,在這類分支上去開發新的功能。開發功能的時候,這個功能屬於哪個目標發行還不知道。功能如果一直在開發,對應的這個功能分支就可以一直存在。待上線的時候,合併到 develop
分支上,進行整體功能測試。如果不想要開發的這個功能了,可以直接扔掉它。
2. 分支的基本操作
(1)檢視分支
我們先通過以下命令檢視分支資訊
git branch
看到如下資訊
(2)建立與切換分支
使用以下指令從當前分支建立新分支,並切換到新分支
# 建立develop分支
git branch develop
# 切換到 develop 分支
git checkout develop
或者我們使用以下命令建立之後直接切換到新分支
# checkout 指令使用 -b引數,建立之後即切換
git checkout -b develop
此時我們再使用 git branch
檢視分支資訊,如下圖
可以看到現在一共有兩個分支,而有“*”標識的是我們現在所在的分支。
(3)刪除分支
經過上面的操作,我們現在已經處在 develop
分支上,下面我們建立一個新分支,並刪除掉新建立的分支
# 建立並切換到 feature/211031
git checkout -b feature/211031
通過上面的指令我們建立了一個功能分支,假如這個功能不想要了,我們就可以刪除掉,使用以下指令
# 先切換回develop分支
git checkout develop
# 刪除 feature/211031 功能分支
git branch -d feature/211031
刪除遠端分支,為了演示刪除遠端分支,我們先將本地的develop
分支提交到遠端
# 將本地develop 分支提交到遠端
git push -u origin develop
如果遠端沒有 develop 分支將會自動建立。這裡還有個引數是 -u
,是--set-upstream
的簡寫,該引數用於推送程式碼是進行分支關聯,該引數與 push
指令聯用。另一個類似功能的引數--set-upstream-to
用於直接設定關聯,該引數與branch
指令聯用。如下指令
# 將遠端 master 關聯到 本地 develop分支
git branch --set-upstream-to origin/master develop
以上指令將遠端 master
分支關聯到本地的 develop
分支。換一種說法是,我們將本地 develop
分支追蹤遠端的 master
分支。以上的設定只是個示例,在實際中,根據分支名稱,本地分支應當與遠端分支一一對應。
上面講develop
分支推送到遠端倉庫之後,我們可執行遠端的分支刪除操作,如下指令
# 刪除遠端的 develop 分支
git push -u origin -d develop
origin 關鍵詞指的是一個指標,origin 指向的是本地的程式碼庫託管在遠端的倉庫,可以說 origin 對應的是遠端倉庫。
3. 同步遠端分支
(1)相關指令
使用下面的命令合併遠端程式碼
# 從遠端獲取最新版本資訊到本地
git fetch
# 將遠端版本合併到當前分支
git merge FETCH_HEAD
這裡出現一個關鍵詞FETCH_HEAD
,該關鍵詞同樣是一個指標,用於跟蹤從遠端儲存庫中獲取的內容。
以上的兩個指令可以用一個 git pull
來代替, 其實就是 git fetch
和 git merge FETCH_HEAD
的合併。命令格式如下
git pull <遠端主機名> <遠端分支名>:<本地分支名>
(2)例項
讓當前分支自動與其追蹤的分支進行合併
git pull
讓遠端的 master
分支,與本地的 develop
分支合併,如下指令
git pull origin master:develop
4. 分支的合併
通常情況下,需要單獨建一個分支來開發功能,開發完成之後需要合併到主分支。我們這裡說的主分支是功能分支的來源分支,假如 feature
分支是從 develop
分支建立的,我們就把這裡的 develop
分支叫做主分支。通過下圖可以看到合併的過程
每個節點代表一個提交,但功能分支在開發的時候,主分支也可能進行了好幾次提交。最後,功能分支要合併到主分支上。上圖的合併過程可以通過以下命令來實現
# 切換到develop分支
git checkout develop
# 將feature分支合併到develop分支
git merge feature
但很多時候,我們需要另外的效果,如下圖
將功能分支的提交記錄追加在主分支上,讓 git 保持一條線的提交記錄,我們可以使用以下命令
# 使用rebase的方式將feature分支合併到develop分支
git rebase feature
rebase
的方式不是直接合並,而是將 feature
分支變化的提交記錄直接追加到主分支之上。使得兩個分支的程式碼保持提交的記錄是一致的。
實際上不僅僅本地分支的合併可以使用rebase
的方式。將遠端程式碼合併到本地的分支,我們也可以使用--rebase
引數將本地分支的提交記錄追加到遠端的分支上,如下命令
git pull --rebase
5. 程式碼衝突解決辦法
因為 git 主要是用來做協同開發的,所以一個專案中的一個檔案,可能同時有多個人編輯,那麼就可能產生檔案的衝突。衝突主要來自以下方面
-
多人同時變更相同檔案的同一個地方:一定會產生衝突
-
多人同時編輯檔案的不同地方:可能會產生衝突
如果產生的衝突 git 能處理的 git 將會自動解決,但是如果 git 不能解決的衝突則需要我們手動解決。下面我們演示一下檔案產生衝突和解決的過程
(1)初始化git倉庫
# 建立一個 test2 目錄
mkdir test2
# 進入 test2 目錄
cd test2
# 建立一個原始碼檔案 main.cpp
touch main.cpp
# 初始化git倉庫
git init
# 將檔案新增git快取區
git add .
# 將git提交到版本庫
git commit -m "first commit"
(2)在新分支寫入程式碼
這時候,我們已經在 master 分支已經有了一個 git 的版本庫。現在需要從 master
分支建立新分支,如下命令
git checkout -b develop
現在我們在main.cpp
中新增以下程式碼
然後將程式碼進行提交,如下指令
git commit -a
你可能會疑問,這次提交怎麼跟之前的命令不一樣呢?實際上,以上命令就等價於下面的指令
git add .
git commit
但是沒有-m
引數,所以 git 會自動開啟其繫結的終端編輯器,讓我們手動輸資訊。輸好提交備註資訊之後,我們退出編輯器即可。
(2)在主分支上寫入程式碼
接著我們切換到 master
分支,如下指令
git checkout master
現在我們在 master 分支中對main.cpp
檔案新增另外一行程式碼,如下內容
再使用以下命令進行提交
git commit -a
(3)產生衝突
此時,master
分支到了第 2 個版本,develop
也在第 2 個版本,並且他們同一行檔案程式碼不一樣,程式碼合併後必定會產生衝突。接下來我們將 develop
分支合併到 master
分支,如下命令
# 在master分支上將develop分支合併進來
git merge develop
合併結果如下圖所示
可以看到提示資訊的關鍵詞CONFLICT
,此時程式碼已經產生了 git 無法自動解決的衝突,合併之後的程式碼如下所示
<<<<<<< HEAD
=======
>>>>>>> develop
現在我們開啟main.cpp
檔案,可以看到合併的程式碼中被分成了兩欄。上面部分的關鍵詞是HEAD
,我們在前面說過 HEAD
指標指向的是當前分支,即 master,而下面的部分是 develop 分支的程式碼。
(4)解決衝突
現在就需要我們手動解決衝突,假如我們兩行程式碼都想要,那麼刪除掉 git 產生的臨時行,同時保留兩個分支的程式碼即可,最終修改如下:
最後,我們再將修改之後的程式碼再次提交到版本庫即可,如下指令
git commit -a -m "解決衝突"
三、標籤
git 可以對某次版本提交進行打標籤,以表示一個重要更新或者是一個里程碑。一般情況下,我們在程式碼即將釋出的時候打一個標籤,以表示一個穩定的版本。
1. 檢視標籤
使用以下指令檢視已經存在的標籤
git tag
這個指令會根據標籤的字母順序列出,如果只想檢視某個關鍵字的分支,可以使用以下指令
# 檢視 帶有
git tag -l "v1.*"
2. 打標籤
git 支援兩種標籤:輕量標籤(lightweight)與附註標籤(annotated)。輕量標籤很像一個不會改變的分支,它只是某個特定提交的引用。而附註標籤是儲存在 git 資料庫中的一個完整物件。
使用當前分支最新的提交建立標籤輕量標籤
git tag v1.0 -m "version 1.0"
使用當前分支最新的提交建立附件標籤
git tag -a v1.0 -m "version 2.0"
我們也可以對過去的提交進行打標籤,使用以下指令檢視過去的提交日誌
git log --pretty=oneline
可以看到如下內容
667a8a76e994f9abe0624d5b14093af92de16ac2 (HEAD -> master, tag: v2.0, tag: v1.0, origin/master, develop) Merge branch 'develop'
db8f7cf7cadcfbf357a93b4a1cab3ee25a86db85 main commit 2
f9715e2aae67cf66b1d1348e872cb313f25ed514 develop commit 1
ba8703bd5151796106af7fe55109c9d80ea8b27f first commit
假如我們需要對第一次版本提交打標籤,可使用以下命令
# 使用提交id指定對應的提交
git tag -a v3.0 ba8703bd5151796106af7fe55109c9d80ea8b27f -m "tag v3.0"
或者直接用提交 id 的縮寫,如下指令
git tag -a v3.0 ba8703b -m "tag v3.1"
3. 將標籤提交到伺服器
我們在使用push
指令的時候,並不會直接將標籤遠端倉庫,所以我們需要使用如下指令提交對應的標籤
# 將 名為 v2.0 的標籤提交到遠端倉庫
git push origin v2.0
或者使用以下指令將所有的標籤提交到遠端倉庫
git push origin --tags
4. 刪除標籤
使用以下命令刪除本地標籤
git tag -d v1.0
本地標籤刪除後,如果遠端存在當前對應標籤,使用git pull
同時將遠端標籤同步到本地。我們可以使用下面的命令刪除遠端標籤
# 刪除遠端倉庫的 v1.0 標籤
git push origin :refs/tags/v1.0
上面這種操作的含義是,將冒號前面的空值推送到遠端標籤名,從而高效地刪除它。如果使用下面的指令刪除遠端標籤,更加直觀
# 刪除遠端 v1.0 標籤,-d 是 --delete 的縮寫,兩者的功能是等價的
git push origin --delete v1.0
這時候,你可能會疑問:刪除分支和刪除標籤的命令是一樣的?確實是,因為這種方式是通過引用名稱進行刪除。如果存在同名分支時,使用上述的第二種方法刪除標籤會刪除失敗。
同時我們也說明一下刪除分支的原始指令,如下
# 刪除 develop 分支
git push origin :refs/heads/develop
從上面的指令我們可以看出,分支的引用屬於
refs/heads
之下,而標籤的引用屬於refs/tags
之下
四、總結
通過這篇文章,我們把常見的 git 操作都演示了一遍。我們主要是以實踐的方式進行了程式碼的合併、程式碼的提交、衝突的解決、標籤的使用等。如果掌握這篇文章,幾乎就能滿足日常的開發 git 協作需求了。
實際上git
的功能也不止這些,限於篇幅,git 還有很多不常用的引數和功能這篇文章沒有介紹。如果你有興趣,可以通過閱讀官方文件的方式瞭解更多內容!
感謝你的耐心閱讀,歡迎訂閱博主的部落格,後續將更新更多的知識!