1. 程式人生 > 其它 >企業發展能否“既要又要還要”?手握低程式碼,得工具者得天下

企業發展能否“既要又要還要”?手握低程式碼,得工具者得天下

一、概述

這篇文章是本系列的第 3 篇。通過前兩篇,我們已經掌握了 git 的最常用的命令以及相關操作。在本篇文章,我們將學習企業開發中最常用的協同方式,那就是基於 git 分支進行協同開發。如果你還沒有閱讀過前兩篇文章,建議先閱讀。

1. git 基本操作方法,記錄幾條命令將自己的程式碼託管到 github

2. 通俗易懂地學習 git 中最常用的命令

二、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/211031git 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.cpptouch main.cpp# 初始化git倉庫git init# 將檔案新增git快取區git add .# 將git提交到版本庫git commit -m "first commit"

(2)在新分支寫入程式碼

這時候,我們已經在 master 分支已經有了一個 git 的版本庫。現在需要從 master 分支建立新分支,如下命令

git checkout -b develop

現在我們在main.cpp中新增以下程式碼

#include<iostream>

然後將程式碼進行提交,如下指令

git commit -a

你可能會疑問,這次提交怎麼跟之前的命令不一樣呢?實際上,以上命令就等價於下面的指令

git add .git commit

但是沒有-m引數,所以 git 會自動開啟其繫結的終端編輯器,讓我們手動輸資訊。輸好提交備註資訊之後,我們退出編輯器即可。

(2)在主分支上寫入程式碼

接著我們切換到 master 分支,如下指令

git checkout master

現在我們在 master 分支中對main.cpp檔案新增另外一行程式碼,如下內容

#include<stdlib.h>

再使用以下命令進行提交

git commit -a

(3)產生衝突

此時,master 分支到了第 2 個版本,develop 也在第 2 個版本,並且他們同一行檔案程式碼不一樣,程式碼合併後必定會產生衝突。接下來我們將 develop 分支合併到 master分支,如下命令

# 在master分支上將develop分支合併進來git merge develop

合併結果如下圖所示

可以看到提示資訊的關鍵詞CONFLICT,此時程式碼已經產生了 git 無法自動解決的衝突,合併之後的程式碼如下所示

<<<<<<< HEAD#include<stdlib.h>=======#include<iostream>>>>>>>> develop

現在我們開啟main.cpp檔案,可以看到合併的程式碼中被分成了兩欄。上面部分的關鍵詞是HEAD,我們在前面說過 HEAD指標指向的是當前分支,即 master,而下面的部分是 develop 分支的程式碼。

(4)解決衝突

現在就需要我們手動解決衝突,假如我們兩行程式碼都想要,那麼刪除掉 git 產生的臨時行,同時保留兩個分支的程式碼即可,最終修改如下:

#include<stdlib.h>#include<iostream>

最後,我們再將修改之後的程式碼再次提交到版本庫即可,如下指令

git commit -a -m "解決衝突"

三、標籤

git 可以對某次版本提交進行打標籤,以表示一個重要更新或者是一個里程碑。一般情況下,我們在程式碼即將釋出的時候打一個標籤,以表示一個穩定的版本。

1. 檢視標籤

使用以下指令檢視已經存在的標籤

git tag

這個指令會根據標籤的字母順序列出,如果只想檢視某個關鍵字的分支,可以使用以下指令

# 檢視 帶有 "v1." 關鍵字的標籤 星號("*")代表萬用字元號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

可以看到如下內容

pan@pandeMacBook-Pro test2 % git log --pretty=oneline667a8a76e994f9abe0624d5b14093af92de16ac2 (HEAD -> master, tag: v2.0, tag: v1.0, origin/master, develop) Merge branch 'develop'db8f7cf7cadcfbf357a93b4a1cab3ee25a86db85 main commit 2f9715e2aae67cf66b1d1348e872cb313f25ed514 develop commit 1ba8703bd5151796106af7fe55109c9d80ea8b27f 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 還有很多不常用的引數和功能這篇文章沒有介紹。如果你有興趣,可以通過閱讀官方文件的方式瞭解更多內容!

感謝你的耐心閱讀,歡迎訂閱博主的部落格,後續將更新更多的知識!