05.15 架構師,你需要了解的git知識都在這裡了

1. Git 簡介

Git 的誕生:

Linus(Linux之父)花了兩週時間自己用C寫了一個分佈式版本控制系統,這就是Git!一個月之內,Linux系統的源碼已經由Git管理了!

幾個概念:

工作區、版本庫、暫存區如下圖所示:

架構師,你需要了解的git知識都在這裡了

1. 圖中左側為工作區,右側為版本庫。在版本庫中標記為index的區域是暫存區(stage,index),標記為master的是master分支所代表的目錄樹。

2. 圖中我們可以看出此時HEAD指針實際是指向master分支的一個"遊標"。所以圖示的命令中出現 HEAD 的地方可以用 master 來替換。

3. 圖中的objects標識的區域為Git的對象庫,實際位於.git/objects目錄下。

4. 當對工作區修改(或新增)的文件執行git add命令時,暫存區的目錄樹被更新,同時工作區修改(或新增)的文件內容被寫入到對象庫中的一個新的對象中,而該對象的ID被記錄在暫存區的文件索引中。

5. 當執行提交操作git commit時,暫存區的目錄樹寫到版本庫(對象庫)中,master分支會做相應的更新。即master指向的目錄樹就是提交時暫存區的目錄樹。

6. 當執行git reset HEAD命令時,暫存區的目錄樹會被重寫,被master分支指向的目錄樹所替換,但是工作區不受影響。

7. 當執行git rm --cached <file>命令時,會直接從暫存區刪除文件,工作區則不做出改變。/<file>

8. 當執行git checkout .或者git checkout -- <file>命令時,會用暫存區全部或指定的文件替換工作區的文件。這個操作很危險,會清除工作區中未添加到暫存區的改動。/<file>

9. 當執行git checkout HEAD .或者git checkout HEAD <file>命令時,會用HEAD指向的master分支中的全部或者部分文件替換暫存區和以及工作區中的文件。這個命令也是極具危險性的,因為不但會清除工作區中未提交的改動,也會清除暫存區中未提交的改動。/<file>

2. 基本命令

2.1. git config: 環境設置命令

通常情況下,安裝完Git後的第一件事就是設置用戶名稱郵件地址。每一個Git的提交都會使用這些信息,如果不設置則無法進行提交。

$ git config --global user.name "goto456" // 設置用戶名稱$ git config --global user.email "[email protected]" // 設置郵件地址

使用--global參數表示設置了全局的環境,如果想對與特定的項目使用不同的用戶名和郵件地址,則可已在該項目目錄下不使用--global參數設置不同的用戶名和郵件地址。

git config --list命令可以列出當前Git所有的配置信息。

2.2. git init: 初始化本地倉庫

獲取一個 Git 倉庫有2中方法:

1. 本地初始化一個倉庫

2. 從遠程克隆一個倉庫到本地

對於第1種方式,如果想對本地現有的一個項目用 Git 來管理,可以直接進入該項目的目錄下執行如下命令,就可以將其初始化成一個 Git 倉庫了。$ git init

2.3. git clone: 克隆遠程倉庫到本地

對於第二種方式,也是最常用的方式,比如你在 GitHub 上(或者其他代碼託管網站)已經建立了一個項目,你就可以將該項目從遠程克隆到本地,這就有了該項目在本地的 Git 倉庫。

$ git clone [email protected]:goto456/leetcode.git // 通過ssh方式克隆$ git clone https://github.com/goto456/leetcode.git // 通過https方式克隆

以上2種方式有如下區別:

1. https方式:不管是誰,只要拿到該項目的 url 可以隨便 clone,但是在 push 到遠程的時候需要驗證用戶名和密碼;

2. ssh方式:需要現將你電腦的SSH key(SSH公鑰)添加到GitHub(或者其他代碼託管網站)上,這樣在 clone 項目和 push 項目到遠程時都不需要輸入用戶名和密碼。

如何生成SSH key,參見下一條命令:ssh-keygen

2.4. ssh-keygen: 生成SSH公鑰

生成公鑰之前先檢查系統中是否已經有了公鑰,公鑰一般在~/.ssh/目錄下。如果該目錄下存在id_rsa.pub文件,這就是公鑰(id_rsa 文件是私鑰);如果不存在此文件,甚至連.ssh目錄都不存在,則需要用 ssh-keygen 命令來生成。如下所示:

$ ssh-keygen // 然後一直按回車鍵

這就可以生成 SSH key 了,公鑰id_rsa.pub文件的內容大致如下所示:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/bdrJjo6HNCuzhpTZNVsTju5NnksTca2kRzfbZlFs+8S4bs8hTlo6aV/GJPkTT0zxJfuOgfd4B4O8Xh0NQg51Zl4yCsFdnIKFA0tgBOg/H5oi48Ypoo8h3LO+S8gd8HR5eqndjINx3kCrQx4gISCW25d7GKTm3c40YPoUCIL0Zg4+iuu2ioeVCpv+FSCKhlcrYew7c2aEe3p/oOmATT3UX9S4t94qzy8KkxRlnQ4a8zQ3OTRE23r7+PPHGN8oBAen//NQNn9COUhqU3pHfvtxqYrG1Blhf0t6HhkHz9Fd8StCUIDQv7yHHvuuPFumh3/8PNG8DDPQqWsqXmK2XozT

2.5. git status 查看當前狀態

可以在任何時候使用該命令查看當前的狀態。一般會顯示當前所處的分支,以及當前工作區是否乾淨,是否有文件要提交。當你克隆遠程倉庫到本地後,通過該命令查看當前狀態時,顯示信息如下圖所示:

架構師,你需要了解的git知識都在這裡了

當你修改了一個文件後,再用該命令查看當前狀態,顯示信息如下圖所示:

架構師,你需要了解的git知識都在這裡了

它會提示你把當前的變更添加到暫存區或者丟棄該變更。

當你新增一個文件後,用該命令查看當前狀態,顯示信息如下圖所示:

架構師,你需要了解的git知識都在這裡了

它會顯示新增的文件狀態是未跟蹤,並且提示用git add命令將其添加到暫存區。

2.6. git add: 添加到暫存區

無論你新增了一個文件或者對已有的文件進行了修改,都需要將其添加到暫存區,然後提交到版本庫。

$ git add hello.txt //後面接文件名,表示將某個文件添加到暫存區

$ git add . //後面接一個點,表示將全部文件添加到暫存區

分別執行上述2條命令後,如下圖所示:

架構師,你需要了解的git知識都在這裡了

架構師,你需要了解的git知識都在這裡了

將新增/修改的文件添加到暫存區後,並未提交到版本庫,還需要通過git commit命令提交到版本庫。

2.7. git commit: 提交到版本庫

該命令是將添加到暫存去的變更提交到版本庫,主要有一下幾個常用的:

$ git commit -m "變更的說明信息" //標準用法,提交到版本庫並填寫相關說明信息

$ git commit -am "變更的說明信息" //加上-a參數,則不需要上一步的git add過程,可以直接將修改過的變更直接提交到版本庫,但不會把新增的文件提交

分別執行上述2條命令後,如下圖所示:

架構師,你需要了解的git知識都在這裡了

架構師,你需要了解的git知識都在這裡了

注:第2條命令一般在不想把新增的文件提交到版本庫時用的比較多

執行完git commit命令提交到版本庫後,一次簡單的流程就算走完了。接下來可以通過git log命令來查看所有的提交歷史。

2.8. git log: 查看提交歷史

如果發現提交了一個錯誤版本,想回退到上個版本時,就可以通過該命令來查看所有的歷史版本,以選擇回退到歷史的哪個版本。

$ git log //查看歷史版本

$ git log --graph //以圖形的方式查看歷史(這個我比較常用,能很好的顯示各個分支之間的關係)

執行後,如下圖所示:

架構師,你需要了解的git知識都在這裡了

架構師,你需要了解的git知識都在這裡了

可以看出第2個圖的左邊顯示出了分支的圖形

2.9. git diff: 顯示變更內容

當你對文件進行了修改,想查看進行了哪些修改時,可以通過該命令查看。git diff命令會顯示修改的文件中哪些內容進行了修改,包括新增了哪些內容,刪除了哪些內容。

$ git diff //後面不接參數,表示顯示所有修改文件的變更

$ git diff README.md //後面接文件名,表示只顯示該文件的變更

例如:我對 README.md 文件進行了修改,刪除了1行,新增了2行,然後用該命令查看進行了哪些修改,如下圖所示: ("+" 表示新增的內容,"-" 表示刪除的內容)

架構師,你需要了解的git知識都在這裡了

2.10. git reset: 回退版本

常用於回退版本或者在各個版本間進行跳躍切換。 我們可以先用 git log 看一下當前歷史版本,如下圖所示:

架構師,你需要了解的git知識都在這裡了

如果要回退到前一個版本,則只需要輸入:git reset HEAD~1,執行完再看一下歷史版本:

架構師,你需要了解的git知識都在這裡了我們已經回退到前一個版本了。

如果需要回退到前2個版本,命令是:git reset HEAD~2,回退到前n個版本就是:git reset HEAD~n注意:在 Git 中,用 HEAD 表示指向當前版本的指針

如果需要回退到任何一個版本,則需要替換成該版本的 commit id 就可以了,例如:git reset a8336834b50daafa0793370,執行完再看一下歷史:

架構師,你需要了解的git知識都在這裡了發現我們已經回退到該版本了。

一般情況下會加一個 --hard 參數:git reset --hard HEAD~1 或 git reset --hard a8336834b50daafa0793370,表示回退到某個版本並且丟棄調工作區進行的修改,而不加該參數表示回退到某個版本但保留工作區的修改。

2.11. git push: 推送本地分支到遠程

當修改完成,本地的改動都已經提交到本地庫,則可以將本地分支推送到遠程代碼庫了。

命令:git push origin masterorigin 表示遠程代碼庫的一個別名(也可以修改為其他名字,可通過 git remote 修改),master 表示需要推送的分支名稱。

如果,push 的過程中提示當前分支進度落後於遠程的分支,則需要通過 git pull 命令來拉取遠程最新狀態和本地分支進行合併,完成之後再 push 到遠程就可以了。

2.12. git pull: 拉取遠程分支到本地併合並

一般是本地分支的進度落後於遠程分支時,需要使用該命令。

命令:git pull origin masterorigin 表示遠程代碼庫的一個別名(也可以修改為其他名字,可通過 git remote 修改),master 表示需要拉取合併的分支名稱。

常用 git pull --rebase origin master 用 rebase 的方式進行,不會產生 merge 保持分支幹淨、整潔

3. 分支管理

3.1. git branch: 分支操作

命令:git branch 用於顯示本地所有分支以及當前所在哪個分支。

架構師,你需要了解的git知識都在這裡了圖中顯示本地有 master 和 dev 兩個分支,並且正處在 master 分支上。

命令:git branch branchName 用於新建名為 branchName 的新分支。

架構師,你需要了解的git知識都在這裡了圖中新建了一個名為 test 的新分支。

命令:git branch -d branchName 用於刪除名為 branchName 的分支。

架構師,你需要了解的git知識都在這裡了圖中刪除了一個名為 test 的分支。

命令:git branch -D branchName 用於強制刪除分支。

3.2. git checkout: 分支間切換

該命令除了進行分支間切換功能外,還可以用來丟棄工作區中的修改內容,這裡就不作介紹了,僅介紹分之間的切換功能。

命令:git checkout branchName 用於從當前分支切換到名為 branchName 的分支上。

架構師,你需要了解的git知識都在這裡了圖中先顯示在 master 分支上,後來切換到了 dev 分支上。

命令:git checkout -b branchName 用於新建名為 branchName 的分支並切換到該分支上。

架構師,你需要了解的git知識都在這裡了圖中新建了 test 分支並切換到了該分支上。

注意與 git branch 新建分支的區別,此處除了新建分支外還進行了切換操作

3.3. git merge: 合併分支

該命令用於合併兩個分支。命令:git merge branchName 用於將名為 branchName 的分支合併到當前分支。有兩種合併方式:

1. fast-forward 方式合併:命令:git merge dev

架構師,你需要了解的git知識都在這裡了

2. 非fast-forward 方式合併:命令:git merge dev

架構師,你需要了解的git知識都在這裡了

注意兩種方式的區別:fast-forward 方式僅僅是移動了 HEAD 指針,而非 fast-forward 方式則是新建了一個節點

3.4. git rebase: 分支的變基

命令:git rebase master 將當前分支 rebase 到 master 分支命令:git rebase master dev 將 dev 分支 rebase 到 master 分支

這種操作很難用語言解釋,我用一個圖來說明其與 merge 操作的區別:

架構師,你需要了解的git知識都在這裡了由圖可知,rebase 操作相當於將 C3 節點拿下來換了一個位置重新放置。最後不會產生合併的痕跡,所有分支都是同一條直線。

我們來看一個詳細的例子:你從 master 分支的 C2 上創建了一個新分支 server,為服務端添加了一些功能,提交了 C3 和 C4。 然後從 C3 上創建了特性分支 client,為客戶端添加了一些功能,提交了 C8 和 C9。 最後,你回到 server 分支,又提交了 C10。

架構師,你需要了解的git知識都在這裡了

假設你希望將 client 中的修改合併到主分支併發布,但暫時並不想合併 server 中的修改,因為它們還需要經過更全面的測試。這時,你就可以使用 git rebase 命令的 --onto 選項,選中在 client 分支裡但不在 server 分支裡的修改(即 C8 和 C9),將它們在 master 分支上重放:

命令:git rebase --onto master server client以上命令的意思是:"取出 client 分支,找出處於 client 分支和 server 分支的共同祖先之後的修改,然後把它們在 master 分支上重放一遍"。 這理解起來有一點複雜,不過效果非常酷。

架構師,你需要了解的git知識都在這裡了

現在可以快進合併 master 分支了。(如下圖 快進合併 master 分支,使之包含來自 client 分支的修改):

$ git checkout master$ git merge client

架構師,你需要了解的git知識都在這裡了

接下來你決定將 server 分支中的修改也整合進來。 使用 git rebase master server 命令可以直接完成,這樣做能省去你先切換到 server 分支,再對其執行變基命令的多個步驟。

$ git rebase master server如下圖 將 server 中的修改變基到 master 上,server 中的代碼被"續"到了 master 後面。

架構師,你需要了解的git知識都在這裡了

然後就可以快進合併主分支 master 了:

$ git checkout master$ git merge server至此,client 和 server 分支中的修改都已經整合到主分支裡了,你可以刪除這兩個分支,最終提交歷史會變成下圖的樣子,非常乾淨、整潔:

$ git branch -d client$ git branch -d server

架構師,你需要了解的git知識都在這裡了

3.5. git cherry-pick: 挑揀節點合併到當前分支上

該命令一般用於從其他分支上挑揀某些節點到當前分支。命令:git cherry-pick commit_id

架構師,你需要了解的git知識都在這裡了上圖中我想把 ruby_client 分支上的 e43a6 這個節點合併到 master 分支上,但不需要 5ddae 這個節點,那麼我們就可以使用下面的命令:$ git checkout master 先切換到 master 分支$ git cherry-pick e43a6 將 e43a6 節點挑揀合併到當前分支完成後如下圖所示:

架構師,你需要了解的git知識都在這裡了

注意:該節點被挑揀合併到 master 上後會產生一個新的節點

4. 其他命令

4.1. git revert: 撤銷某次提交

該命令用於撤銷歷史上的某次提交,注意該撤銷操會作為一個新節點存在於分支上:

架構師,你需要了解的git知識都在這裡了上圖中顯示了當前的歷史提交,當我要撤銷 ab1591eb4e06c1e93fdd50126b9fab8a88d89155 這個節點時,執行如下命令:命令:git revert ab1591eb4e06c1e93fdd50126b9fab8a88d89155

架構師,你需要了解的git知識都在這裡了從圖中可以看出,完成操作後,會產生一個新的節點,該節點就是撤銷操作產生的。

注意與 git reset 的區別

4.2. git tag: 標籤的操作

用於給某次提交打個標籤,例如截止到某次提交後完成了某個重大版本的開發,則可以在該次提交打上一個版本的 tag 。

架構師,你需要了解的git知識都在這裡了例如,截止到圖中的最近一次提交,我們完成了 1.0 版本的開發,則可以通過以下命令為其打上版本的標籤。命令:git tag v1.0 為當前提交打上 v1.0 的標籤命令:git tag v1.0 ab1591eb4e06c1e93fdd50126b9fab8a88d89155 為這個節點打上 v1.0 的標籤

架構師,你需要了解的git知識都在這裡了圖中可以看出 v1.0 標籤已經打上了。如果發現標籤打錯了,想刪除某個標籤,則可以通過如下命令來執行。命令:git tag -d v1.0 刪除 v1.0 標籤

如果想將標題推送到遠程庫,則可以使用如下命令來完成。命令:git push origin --tags 將打的 tag 都推送到遠程庫

4.3. git show: 顯示信息

可用於顯示某次提交或者某個 tag 相關的信息。命令:git show commit_id 顯示某次提交的詳細信息

架構師,你需要了解的git知識都在這裡了

架構師,你需要了解的git知識都在這裡了

命令:git show tag_name 顯示某個 tag 的詳細信息

架構師,你需要了解的git知識都在這裡了

4.4. git blame: 查看文件每行的提交歷史(追責)

可用於查看某個文件中的每一行是那次提交產生的,是誰提交的,什麼時候提交的,提交的版本號是多少等等詳細信息,在實際工作中方便對出問題的代碼進行追責,找到產生 BUG 的責任人。

命令:git blame file_name

架構師,你需要了解的git知識都在這裡了上圖中可以看到 README.md 這個文件有 5 行,其中後 4 行都是我在 2018 年提交的,第 1 行是另外一個人在 2017 年提交的。

5. 團隊協作應用

在團隊協作過程中一般會有多個分支,比如有默認的 master 分支,有用於開發的 dev 分支,還有用於測試的 test 分支,用於對外發布的 release 分支,以及每個開發人員開發不同功能時用到的 feature_xx 分支等等。

公司中一般是用 GitLab 搭建的代碼託管服務,幾個人的小團隊也可以自己搭建。

每個團隊業務不一樣,分支數量的設置也會不一樣,下面我介紹一下我們團隊的分支設置,以及普通開發人員和項目 leader 對不同分支的不同權限以及不同的操作。

5.1 分支設置

我們常用的分支有3個(master 分支、dev 分支、test 分支)以及若干個 feature_xx 分支。

1. master 分支:是主分支,是最終上線代碼的分支,該分支被設置被保護分支(鎖住),普通開發人員沒有權限操作,只有團隊 leader 有合併的權限;

2. dev 分支:是用於開發的分支,該分支被設置為默認 clone 的分支,也用於合併到 master 之前進行測試的分支,普通開發人員從遠程 clone 到本地的默認分支,可以進行合併等操作;

3. test 分支:是用於測試的分支,測試人員可以將自己開發分支中的修改合併到 test 分支在測試環境進行測試,一般該分支不合併到任何分支;

4. feature_xx 分支:是用戶開發自己模塊功能的特徵分支,可以叫 feature_login, feature_ui, feature_payment 等與開發的功能相關的名稱,該分支上的功能開發完、測試無誤後可合併到 dev 分支上。

5.2 普通開發人員的操作

普通開發人員,一般按照如下幾個步驟來進行開發、測試工作就可以了:

1. 將遠程 dev 分支 clone 到本地,例如:git clone [email protected]:goto456/test.git;

2. 從 dev 分支拉出(新建)自己的 feature 分支用於開發,例如:git checkout -b feature_login;

3. 在自己的 feature 分支上進行開發工作;

4. 開發完了用 add、commit 等操作提交到當前分支;

5. 如果需要在測試環境進行測試,則將遠程 test 分支拉到本地,例如:git branch test origin/test;

6. 將自己的 feature 分支合併到 test 分支,並將 test 分支 push 到遠程,例如:git rebase test, git checkout test, git merge feature_login, git push origin test;(注意:我們推薦用 rebase 來合併,以保證分支的整潔、美觀)

7. 通過公司的發佈平臺將遠程 test 分支發佈到測試環境進行測試;

8. 如果測試沒問題或者開始就不需要測試,這可以直接將當前 feature 分支合併到 dev 分支,並 push 到遠程庫,例如:git rebase dev, git checkout dev, git merge feature_login, git push origin dev;(注意:我們推薦用 rebase 來合併,以保證分支的整潔、美觀)

9. 這時表示該功能已經開發完成了,代碼的 review 以及發佈,需要團隊 leader 在合併到 master 操作時進行;這時可以刪除了自己的 feature 分支,例如:git branch -d feature_login;

10. 如果在 push 到遠程的時候提示需要先 pull 時,我們推薦使用 rebase 的方式:git pull --rebase 以保持分支的整潔、美觀。

5.3 團隊 leader 的操作

因為只有 leader 有操作 master 分支的權限,所以需要完成 dev 分支到 master 分支的合併,以及後續打 tag 和正式上線發佈的工作:

1. 先切換到 dev 分支,並拉取最新的狀態,例如:git checkout dev, git pull --rebase origin dev;

2. 進行代碼 review 等過程後,合併到 master 分支,例如:git rebase master, git checkout master, git merge dev;(注意:我們推薦用 rebase 來合併,以保證分支的整潔、美觀)

3. 為本次完成的版本打上標籤,例如:git tag v1.0 -m "release version 1.0";

4. 將本地合併後的 master 分支以及標籤 push 到遠程庫,例如:git push orgin master --tags。

6. 結束語

以上就是我從自己平時的應用中整理出的一個比較簡潔的教程,以及我們團隊在實際工作中是如何使用的。希望對大家有所幫助!


分享到:


相關文章: