如果你覺得學習 Git 很枯燥,那是因為你還沒玩過這款遊戲!

民工哥發表於2022-01-24

大家好!我是民工哥。

對於Git,相信大多數程式設計師並不會感到陌生。

作為目前世界上最先進的分散式版本控制系統(沒有之一),Git 是一個開源的分散式版本控制軟體,用以有效、高速的處理從很小到非常大的專案版本管理。 Git 最初是由Linus Torvalds設計開發的,用於管理Linux核心開發。隨著時間的推移,Git 發展到今天,已經成為了眾多開發者必備的開發工具。

如果你平時學習Git時感覺到枯燥乏味,不妨試一試這個好玩的小遊戲,通過別一種方式,在娛樂中去學習。

下面是其中的演示例子:
image.png
需要這款遊戲的讀者可以點選下方公眾號名片回覆關鍵詞 Git小遊戲 獲取

Git 簡介

Git 是一個開源的分散式版本控制系統。

什麼是版本控制?

版本控制是一種記錄一個或若干檔案內容變化,以便將來查閱特定版本修訂情況的系統。

什麼是分散式版本控制系統?

介紹分散式版本控制系統前,有必要先了解一下傳統的集中式版本控制系統。

集中化的版本控制系統,諸如 CVS,Subversion 等,都有一個單一的集中管理的伺服器,儲存所有檔案的修訂版本,而協同工作的人們都通過客戶端連到這臺伺服器,取出最新的檔案或者提交更新。

這麼做最顯而易見的缺點是中央伺服器的單點故障。如果當機一小時,那麼在這一小時內,誰都無法提交更新,也就無法協同工作。要是中央伺服器的磁碟發生故障,碰巧沒做備份,或者備份不夠及時,就會有丟失資料的風險。最壞的情況是徹底丟失整個專案的所有歷史更改記錄。

分散式版本控制系統的客戶端並不只提取最新版本的檔案快照,而是把程式碼倉庫完整地映象下來。這麼一來,任何一處協同工作用的伺服器發生故障,事後都可以用任何一個映象出來的本地倉庫恢復。因為每一次的提取操作,實際上都是一次對程式碼倉庫的完整備份。

可參考:Git 從入門到精通

Git vs SVN

Git 和 SVN 孰優孰好,每個人有不同的體驗。

Git是分散式的,SVN是集中式的

這是 Git 和 SVN 最大的區別。若能掌握這個概念,兩者區別基本搞懂大半。因為 Git 是分散式的,所以 Git 支援離線工作,在本地可以進行很多操作,包括接下來將要重磅推出的分支功能。而 SVN 必須聯網才能正常工作。

  • Git複雜概念多,SVN簡單易上手

所有同時掌握 Git 和 SVN 的開發者都必須承認,Git 的命令實在太多了,日常工作需要掌握add,commit,status,fetch,push,rebase等,若要熟練掌握,還必須掌握rebase和merge的區別,fetch和pull的區別等,除此之外,還有cherry-pick,submodule,stash等功能,僅是這些名詞聽著都很繞。

在易用性這方面,SVN對於新手來說會更有好一些。但是從另外一方面看,Git 命令多意味著功能多,若我們能掌握大部分 Git 的功能,體會到其中的奧妙,會發現再也回不去 SVN 的時代了。

  • Git分支廉價,SVN分支昂貴

在版本管理裡,分支是很常使用的功能。在釋出版本前,需要釋出分支,進行大需求開發,需要 feature 分支,大團隊還會有開發分支,穩定分支等。在大團隊開發過程中,常常存在建立分支,切換分支的求。

Git 分支是指標指向某次提交,而 SVN 分支是拷貝的目錄。這個特性使 Git 的分支切換非常迅速,並且建立成本非常低。

而且 Git 有本地分支,SVN 無本地分支。在實際開發過程中,經常會遇到有些程式碼沒寫完,但是需緊急處理其他問題,若我們使用 Git,便可以建立本地分支儲存沒寫完的程式碼,待問題處理完後,再回到本地分支繼續完成程式碼。

更多關注Git與Svn的比較請參閱:通俗易懂|用好Git 和 SVN ,輕鬆駕馭版本管理

Git 工作原理

文字不好理解,請看 圖文詳解 Git 工作原理

Git 安裝

  • Debian/Ubuntu 環境安裝

如果你使用的系統是 Debian/Ubuntu , 安裝命令為:

$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
> libz-dev libssl-dev
$ apt-get install git-core
$ git --version
git version 1.8.1.2
  • Centos/RedHat 環境安裝

如果你使用的系統是 Centos/RedHat ,安裝命令為:

$ yum install curl-devel expat-devel gettext-devel \
> openssl-devel zlib-devel
$ yum -y install git-core
$ git --version
git version 1.7.1
  • Windows 環境安裝

在 Git 官方下載地址下載 exe 安裝包。按照安裝嚮導安裝即可。

建議安裝 Git Bash 這個 git 的命令列工具。

  • Mac 環境安裝

在 Git 官方下載地址下載 mac 安裝包。按照安裝嚮導安裝即可。

Git配置

Git 自帶一個 git config 的工具來幫助設定控制 Git 外觀和行為的配置變數。這些變數儲存在三個不同的位置:

/etc/gitconfig 檔案: 包含系統上每一個使用者及他們倉庫的通用配置。如果使用帶有 --system 選項的 git config 時,它會從此檔案讀寫配置變數。

\~/.gitconfig 或 \~/.config/git/config 檔案:只針對當前使用者。可以傳遞 --global 選項讓 Git 讀寫此檔案。

當前使用倉庫的 Git 目錄中的 config 檔案(就是 .git/config):針對該倉庫。

每一個級別覆蓋上一級別的配置,所以 .git/config 的配置變數會覆蓋 /etc/gitconfig 中的配置變數。

在 Windows 系統中,Git 會查詢 $HOME 目錄下(一般情況下是 C:\Users\$USER)的 .gitconfig 檔案。Git 同樣也會尋找 /etc/gitconfig 檔案,但只限於 MSys 的根目錄下,即安裝 Git 時所選的目標位置。

Git 基本概念

  • 版本庫

當你一個專案到本地或建立一個 git 專案,專案目錄下會有一個隱藏的 .git 子目錄。這個目錄是 git 用來跟蹤管理版本庫的,千萬不要手動修改。

  • 雜湊值

Git 中所有資料在儲存前都計算校驗和,然後以校驗和來引用。這意味著不可能在 Git 不知情時更改任何檔案內容或目錄內容。這個功能建構在 Git 底層,是構成 Git 哲學不可或缺的部分。若你在傳送過程中丟失資訊或損壞檔案,Git 就能發現。

Git 用以計算校驗和的機制叫做 SHA-1 雜湊(hash,雜湊)。這是一個由 40 個十六進位制字元(0-9 和 a-f)組成字串,基於 Git 中檔案的內容或目錄結構計算出來。SHA-1 雜湊看起來是這樣:

24b9da6552252987aa493b52f8696cd6d3b00373
Git 中使用這種雜湊值的情況很多,你將經常看到這種雜湊值。實際上,Git 資料庫中儲存的資訊都是以檔案內容的雜湊值來索引,而不是檔名。

  • 檔案狀態

在 GIt 中,你的檔案可能會處於三種狀態之一:

  • 已修改(modified) - 已修改表示修改了檔案,但還沒儲存到資料庫中。
  • 已暫存(staged) - 已暫存表示對一個已修改檔案的當前版本做了標記,使之包含在下次提交的快照中。
  • 已提交(committed) - 已提交表示資料已經安全的儲存在本地資料庫中。
  • 工作區域

與檔案狀態對應的,不同狀態的檔案在 Git 中處於不同的工作區域。

  • 工作區(working) - 當你 git clone 一個專案到本地,相當於在本地克隆了專案的一個副本。工作區是對專案的某個版本獨立提取出來的內容。這些從 Git 倉庫的壓縮資料庫中提取出來的檔案,放在磁碟上供你使用或修改。
  • 暫存區(staging)- 暫存區是一個檔案,儲存了下次將提交的檔案列表資訊,一般在 Git 倉庫目錄中。有時候也被稱作 `‘索引’',不過一般說法還是叫暫存區。
  • 本地倉庫(local) - 提交更新,找到暫存區域的檔案,將快照永久性儲存到 Git 本地倉庫。
  • 遠端倉庫(remote) - 以上幾個工作區都是在本地。為了讓別人可以看到你的修改,你需要將你的更新推送到遠端倉庫。同理,如果你想同步別人的修改,你需要從遠端倉庫拉取更新。

  • 分支(Branch)

分支是為了將修改記錄的整個流程分開儲存,讓分開的分支不受其它分支的影響,所以在同一個資料庫裡可以同時進行多個不同的修改

主分支(Master)前面提到過 master 是 Git 為我們自動建立的第一個分支,也叫主分支,其它分支開發完成後都要合併到 master

  • 標籤(Tag)

標籤是用於標記特定的點或提交的歷史,通常會用來標記釋出版本的名稱或版本號(如:publish/0.0.1),雖然標籤看起來有點像分支,但打上標籤的提交是固定的,不能隨意的改動,參見上圖中的1.0 / 2.0 / 3.0

  • HEAD

HEAD 指向的就是當前分支的最新提交圖片

以上概念瞭解的差不多,那就可以繼續往下看。

Git 命令

  • 建立倉庫

克隆一個已建立的倉庫:

# 通過 SSH
$ git clone ssh://user@domain.com/repo.git

#通過 HTTP
$ git clone http://domain.com/user/repo.git

建立一個新的本地倉庫:

$ git init
  • 新增修改
    新增修改到暫存區:

    # 把指定檔案新增到暫存區
    $ git add xxx
    
    # 把當前所有修改新增到暫存區
    $ git add .
    
    # 把所有修改新增到暫存區
    $ git add -A

    提交修改到本地倉庫:

    # 提交本地的所有修改
    $ git commit -a
    
    # 提交之前已標記的變化
    $ git commit
    
    # 附加訊息提交
    $ git commit -m 'commit message'
  • 儲藏

有時,我們需要在同一個專案的不同分支上工作。當需要切換分支時,偏偏本地的工作還沒有完成,此時,提交修改顯得不嚴謹,但是不提交程式碼又無法切換分支。這時,你可以使用 git stash 將本地的修改內容作為草稿儲藏起來。

官方稱之為儲藏,但我個人更喜歡稱之為存草稿。

# 1. 將修改作為當前分支的草稿儲存
$ git stash

# 2. 檢視草稿列表
$ git stash list
stash@{0}: WIP on master: 6fae349 :memo: Writing docs.

# 3.1 刪除草稿
$ git stash drop stash@{0}

# 3.2 讀取草稿
$ git stash apply stash@{0}
  • 撤銷修改

撤銷本地修改:

# 移除快取區的所有檔案(i.e. 撤銷上次git add)
$ git reset HEAD

# 將HEAD重置到上一次提交的版本,並將之後的修改標記為未新增到快取區的修改
$ git reset <commit>

# 將HEAD重置到上一次提交的版本,並保留未提交的本地修改
$ git reset --keep <commit>

# 放棄工作目錄下的所有修改
$ git reset --hard HEAD

# 將HEAD重置到指定的版本,並拋棄該版本之後的所有修改
$ git reset --hard <commit-hash>

# 用遠端分支強制覆蓋本地分支
$ git reset --hard <remote/branch> e.g., upstream/master, origin/my-feature

# 放棄某個檔案的所有本地修改
$ git checkout HEAD <file>

刪除新增.gitignore檔案前錯誤提交的檔案:

$ git rm -r --cached .
$ git add .
$ git commit -m "remove xyz file"

撤銷遠端修改(建立一個新的提交,並回滾到指定版本):

$ git revert <commit-hash>

徹底刪除指定版本:

# 執行下面命令後,commit-hash 提交後的記錄都會被徹底刪除,使用需謹慎
$ git reset --hard <commit-hash>
$ git push -f
  • 更新與推送

更新:

# 下載遠端端版本,但不合併到HEAD中
$ git fetch <remote>

# 將遠端端版本合併到本地版本中
$ git pull origin master

# 以rebase方式將遠端分支與本地合併
$ git pull --rebase <remote> <branch>

推送:

# 將本地版本推送到遠端端
$ git push remote <remote> <branch>

# 刪除遠端端分支
$ git push <remote> :<branch> (since Git v1.5.0)
$ git push <remote> --delete <branch> (since Git v1.7.0)

# 釋出標籤
$ git push --tags
  • 檢視資訊

顯示工作路徑下已修改的檔案:

$ git status

顯示與上次提交版本檔案的不同:

$ git diff

顯示提交歷史:

# 從最新提交開始,顯示所有的提交記錄(顯示hash, 作者資訊,提交的標題和時間)
$ git log

# 顯示某個使用者的所有提交
$ git log --author="username"

# 顯示某個檔案的所有修改
$ git log -p <file>
  • 顯示搜尋內容:

    # 從當前目錄的所有檔案中查詢文字內容
    $ git grep "Hello"
    
    # 在某一版本中搜尋文字
    $ git grep "Hello" v2.5
  • 分支

增刪查分支:

# 列出所有的分支
$ git branch

# 列出所有的遠端分支
$ git branch -r

# 基於當前分支建立新分支
$ git branch <new-branch>

# 基於遠端分支建立新的可追溯的分支
$ git branch --track <new-branch> <remote-branch>

# 刪除本地分支
$ git branch -d <branch>

# 強制刪除本地分支,將會丟失未合併的修改
$ git branch -D <branch>

切換分支:

# 切換分支
$ git checkout <branch>

# 建立並切換到新分支
$ git checkout -b <branch>

標籤

# 給當前版本打標籤
$ git tag <tag-name>

# 給當前版本打標籤並附加訊息
$ git tag -a <tag-name>

合併與重置

merge 與 rebase 雖然是 git 常用功能,但是強烈建議不要使用 git 命令來完成這項工作。

因為如果出現程式碼衝突,在沒有程式碼比對工具的情況下,實在太艱難了。

你可以考慮使用各種 Git GUI 工具。

合併:

# 將分支合併到當前HEAD中
$ git merge <branch>

重置:

# 將當前HEAD版本重置到分支中,請勿重置已釋出的提交
$ git rebase <branch>

更多命令參考:三年 Git 使用心得 & 常見問題整理

Git 分支開發

Git 是目前最流行的原始碼管理工具。為規範開發,保持程式碼提交記錄以及 git 分支結構清晰,方便後續維護,現規範 git 的相關操作。

分支命名

1、master 分支

master 為主分支,也是用於部署生產環境的分支,確保master分支穩定性, master 分支一般由develop以及hotfix分支合併,任何時間都不能直接修改程式碼

2、develop 分支

develop 為開發分支,始終保持最新完成以及bug修復後的程式碼,一般開發的新功能時,feature分支都是基於develop分支下建立的。

  • feature 分支

開發新功能時,以develop為基礎建立feature分支。
分支命名: feature/ 開頭的為特性分支, 命名規則: feature/user_module、 feature/cart_module

  • release分支

release 為預上線分支,釋出提測階段,會release分支程式碼為基準提測。當有一組feature開發完成,首先會合併到develop分支,進入提測時會建立release分支。如果測試過程中若存在bug需要修復,則直接由開發者在release分支修復並提交。當測試完成之後,合併release分支到master和develop分支,此時master為最新程式碼,用作上線。

  • hotfix 分支

分支命名: hotfix/ 開頭的為修復分支,它的命名規則與feature分支類似。線上出現緊急問題時,需要及時修復,以master分支為基線,建立hotfix分支,修復完成後,需要合併到master分支和develop分支

更多開發規範請參閱:全網最全的 Git 分支開發規範手冊 | 掌握這10條規範,輕鬆搞定Git!

Git這些高階用法,喜歡就拿去用!

Git 提交規範

為什麼需要規範?

無規矩不成方圓,程式設計也一樣。

如果你有一個專案,從始至終都是自己寫,那麼你想怎麼寫都可以,沒有人可以干預你。可是如果在團隊協作中,大家都張揚個性,那麼程式碼將會是一團糟,好好的專案就被糟踐了。不管是開發還是日後維護,都將是災難。

這時候,有人提出了何不統一標準,大家都按照這個標準來。於是 ESLint,JSHint 等程式碼工具如雨後春筍般湧現,成為了專案構建的必備良品。

Git Commit 規範可能並沒有那麼誇張,但如果你在版本回退的時候看到一大段糟心的 Commit,恐怕會懊惱不已吧。所以,嚴格遵守規範,利人利己。

具體請參閱:你可能會忽略的 Git 提交規範

Git使用技巧

只有在遇到問題的時候,才體會到技巧帶來的好處!

常見企業工作流程

主要介紹,企業中常用的 Git 工作流程!

  • Git Flow
  • 主幹分支
  • 穩定分支
  • 開發分支
  • 補丁分支
  • 修改分支

Github Flow
  • 建立分支
  • 新增提交
  • 提交 PR 請求
  • 討論和評估程式碼
  • 部署檢測
  • 合併程式碼

Gitlab Flow
  • 帶生產分支
  • 帶環境分支
  • 帶釋出分支

日常使用最佳實踐

總結日常工作中應該遵循的 Git 使用方式和方法!

  • 使用命令列代替圖形化介面
  • 使用命令列來操作,簡潔且效率高
  • 提交應該儘可能的表述提交修改內容
  • 區分 subject 和 body 內容,使用空行隔開
  • subject 一般不超過 50 個字元
  • body 每一行的長度控制在 72 個字元
  • subject 結尾不需要使用句號或者點號結尾
  • body 用來詳細解釋此次提交具體做了什麼
  • 使用 .gitignore 檔案來排除無用檔案
  • 可使用模板檔案,然後根據專案實際進行修改
  • 基於分支或 fork 的開發模式
  • 不要直接在主幹分支上面進行開發
  • 在新建的分支上進行功能的開發和問題的修復
  • 使用 release 分支和 tag 標記進行版本管理
  • 使用 release 分支釋出程式碼和版本維護(release/1.32)
  • 使用 tag 來標記版本(A-大feature功能.B-小feature功能.C-只修bug)

常用命令彙總整理

日常使用只要記住 6 個命令就可以了。

無論是開發、運維,還是測試,大家都知道Git在日常工作中的地位。所以,也是大家的必學、必備技能之一。

但是呢,民工哥,也經常在後臺看到讀者說,命令太多了不好記啊,時間長了不用又忘記了等等的吐槽。是啊,要學一門技術真難,何況現在技術更新、迭代這麼快.....

所以,對於學習Git這門技術,要是有一個一看就懂,一學就會的入門資料就好了。前不久,國外的一位小姐姐寫了一篇這樣的文章《CS Visualized: Useful Git Commands》。作者是來自英屬哥倫比亞的小姐姐 Lydia Hallie,在這篇文章裡面,她通過生動形象的動畫,以更加直觀的方式,向開發者展示 Git 命令中的 merge、rebase、reset、revert、cherry-pick 等常用騷操作的具體原理。小姐姐用動畫圖解Git命令,一看就懂!

# 工作區 -> 暫存區
$ git add <file/dir>

# 暫存區 -> 本地倉庫
$ git commit -m "some info"

# 本地倉庫 -> 遠端倉庫
$ git push origin master  # 本地master分支推送到遠端origin倉庫 
# 工作區 <- 暫存區
$ git checkout -- <file>  # 暫存區檔案內容覆蓋工作區檔案內容

# 暫存區 <- 本地倉庫
$ git reset HEAD <file>   # 本地倉庫檔案內容覆蓋暫存區檔案內容

# 本地倉庫 <- 遠端倉庫
$ git clone <git_url>        # 克隆遠端倉庫
$ git fetch upstream master  # 拉取遠端程式碼到本地但不應用在當前分支
$ git pull upstream master   # 拉取遠端程式碼到本地但應用在當前分支
$ git pull --rebase upstream master  # 如果平時使用rebase合併程式碼則加上
# 工作區 <- 本地倉庫
$ git reset <commit>          # 本地倉庫覆蓋到工作區(儲存回退檔案內容修改)
$ git reset --mixed <commit>  # 本地倉庫覆蓋到工作區(儲存回退檔案內容修改)
$ git reset --soft <commit>   # 本地倉庫覆蓋到工作區(保留修改並加到暫存區)
$ git reset --hard <commit>   # 本地倉庫覆蓋到工作區(不保留修改直接刪除掉)

更多關於Git的使用技巧介紹請查閱:學會這 11 條,你離 Git 大神就不遠了!

Git 知識體系動態更新看這裡:Git 技術學習

相關文章