Git 看這一篇就夠了
- 2020 年 10 月 14 日
- 筆記
上一篇講 Git 的文章發出來沒想到效果特別好,很多讀者都要求繼續深入的寫。
那今天齊姐簡單講下 Git 的實現原理,知其所以然才能知其然;並且梳理了日常最常用的 12 個命令,分為三大類分享給你。
本文的結構如下:
-
作者和開發原由
-
Git 的數據模型
-
常用命令
-
資源推薦
作者和開發原由
Talk is cheap. Show me the code.
這句話就出自 Linux 和 Git 的作者
Linus Torvalds
。
原本 Linux 內核的版本控制系統是用的 BitKeeper,然而 2005 年,BitMover 公司不再讓 Linux 開發團隊免費使用了。。
Linus 一聽,不給用了?老子自己寫!
於是,大佬十天之內完成了 Git 的第一個版本。
所以 Git 是一個免費的、開源的版本控制系統。
版本控制系統
版本控制其實每個人都用過,那些年修改過的簡歷:
小齊簡歷 2012 版
小齊簡歷 2013 版
小齊簡歷 2014 版
小齊簡歷 2015 版
小齊簡歷 2016 版
小齊簡歷 2017 版
小齊簡歷 2018 版
小齊簡歷 2019 版
…
還有那些年打死都不再改的畢業論文:
畢業論文最終版
畢業論文最最終版
畢業論文最最最終版
畢業論文最最最最終版
畢業論文最終不改版
畢業論文最終真不改版
畢業論文最終真真不改版
畢業論文最終打死不改版
畢業論文最終打死不改版 2
…
沒錯,這就是本地版本控制系統。
很明顯,好處是簡單,但是只能一個人在這改,無法和他人完成合作。那麼以下兩種主流的版本控制系統應運而生。
1. 集中化版本控制系統
Centralized Version Control Systems (CVCS)
比如:CVS, Subversion, Perforce, etc.
這種版本控制系統有一個單一的集中管理的服務器,保存所有文件的最新版本,大家可以通過連接到這台服務器上來獲取或者提交文件。
這種模式相對本地版本控制系統是有所改進的,但是缺點也很明顯,如果服務器宕機,那麼輕則耽誤工作、重則數據丟失。於是分佈式版本控制系統應運而生。
2. 分佈式版本控制系統
Distributed Version Control Systems (DVCS)
比如:Git, Mercurial, Bazaar, etc.
分佈式的版本控制系統會把代碼倉庫完整地鏡像下來,這樣任何一個服務器發生故障,都可以用其他的倉庫來修復。
更進一步,這種模式可以更方便的和不同公司的人進行同一項目的開發,因為兩個遠程代碼倉庫可以交互,這在之前的集中式系統中是無法做到的。
那麼什麼叫「把代碼倉庫完整地鏡像下來」呢?
CVCS 每個版本存放的是當前版本與前一個版本的差異,因此也被稱作基於差異的版本控制 (delta-based);
Git 存儲的是所有文件的一個快照 (snapshot),如果有的文件沒有修改,那就只保留一個 reference 指向之前存儲的文件。
不是很好理解?那接着看吧~
Git 的數據模型
1. 什麼是快照 (snapshot) 呢?
首先我們來學兩個 Git 中的術語:
- blob, 就是單個的文件;
- tree, 就是一個文件夾。
快照則是被追蹤的最頂層的樹。
比如我的「公眾號」文件夾的這麼一個結構:
那麼一個快照就是追蹤的「公眾號」這顆樹。
2. 本地庫的數據模型
Git 記錄了每個快照的 parent,也就是當前這個文件夾的上一個版本。
那麼快照的迭代更新的過程就可以表示為一個有向無環圖,是不是很熟悉?我們在「拓撲」那篇文章里講過,忘了的小夥伴快去公眾號內回復「拓撲」獲取拓撲的入門文章吧~
每個快照其實都對應了一次 commit
,我們用代碼來表示一下:
class commit {
array<commit> parents
String author
String message
Tree snapshot
}
這就是 Git 的數據模型。
blob, tree, snapshot 其實都一樣,它們在 Git 中都是對象
,都可以被引用或者被搜索,會基於它們的 SHA-1 hash
進行尋址。
git cat-file -t
: 查看每個 SHA-1 的類型;
git cat-file -p
: 查看每個對象的內容和簡單的數據結構。
但是通過這個哈希值來搜索也太不方便了,畢竟這是一串 40 位的十六進制字符,就是第二部分 git log
里輸出的那個編碼
。
因此,Git 還給了一個引用 reference
。
比如,我們常見的 HEAD
就是一個特殊的引用。
本地庫就是由 對象
和 引用
構成的,或者叫 Repositories
.
在硬盤上,Git 只存儲 對象
和 引用
,所有的 Git 命令都對應提交一個快照。
那有哪些常用命令呢?
常用命令
本章分三大部分介紹日常常用命令:
- 本地操作
- 和遠程庫的交互
- 團隊協作 – 分支
本地操作
在學習常用命令之前,你首先需要知道的 Git 的「三個分區」和對應的文件的「三種狀態」:
-
工作區
:就是你本地實際寫代碼的地方,無論你是用 vim 直接改也好,還是在 IDE 里寫,都無所謂。- 對應的文件狀態是:
modified
,已修改,但還沒保存到數據庫中。
- 對應的文件狀態是:
-
暫存區
:就是臨時存放的地方。- 對應的文件狀態是:
staged
,Git 已經對該文件做了標記,下次提交知道要包含它。
- 對應的文件狀態是:
-
本地庫
:存放本地歷史版本信息。- 對應的文件狀態是:
committed
,文件已經安全的保存在本地數據庫中。
- 對應的文件狀態是:
1. $ git add
工作區改完了代碼,就用 git add
提交到暫存區。
這裡如果文件改動的比較多,但又不是每個都需要提交,我會設置 git ignore file
,就表示這些文件不要提交,比如在 build project 的時候會自動生成的那些文件等等。
2. $ git commit -m “comment”
從暫存區提交到本地庫,就需要用 commit。
一般後面都會跟個 -m
加句 comment
,簡單說下改動的內容或者原因,我們公司大家默認也會把 Jira
鏈接附上,這樣就知道這個改動對應哪個任務。
那如果想再改,再重新 git add
即可,但是 commit
這句需要改成
$ git commit --amend
這樣就還是一條 git log 信息。
3. $ git log
git log
可以查看到提交過的信息,從近到遠顯示每次 commit 的 comment 還有作者、日期等信息,比如大概長這個樣子:
commit 5abcd17dggs9s0a7a91nfsagd8ay76875afs7d6
Author: Xiaoqi<[email protected]>
Date: xxx xxx xxx
改了 Test 文件
commit 後面的這個編號
,是每次歷史記錄的一個索引
。比如如果需要對版本進行前進或者後退的時候,就需要用到它。
這樣打印的 log 太多,更簡潔的打印方式是:
$ git log --oneline
就一行打印出來了。
或者:
$ git reflog
更常用一些。
4. $ git reset
那我們剛剛說過,如果需要前進或退回到某個版本,就用
$ git reset --hard <編號>
這樣就直接跳到了這個編號
對應的那個版本。
那麼這個 hard
是什麼意思呢?
這裡有 3 個參數:hard
, soft
, mixed
,我們一一來說一下。
回到我們最重要的這張圖上來:
我們剛剛說的前進或後退到某一版本,是對本地庫
進行的操作。
那有個問題:
本地庫的代碼跳到那個版本之後,工作區和暫存區的代碼就和本地庫的不同步了呀!
那這些參數就是用來控制這些是否同步的。
$ git reset –hard xxx
三個區都同步,都跳到這個 xxx 的版本上。
$ git reset –soft xxx
前面兩個區不同步,就只有本地庫跳到這個版本。
$ git reset –mixed xxx
暫存區同步,工作區不動。
所以呢,用的多的就是 hard.
遠程交互
和遠程庫的交互主要是推
、拉
,也就是寫入和讀取。
5. $ git push
小齊寫完了代碼,要提交到公司的代碼庫里,這個過程要用 git push
.
當然了,這麼用會被打的。。畢竟還要 cr 呢。
5. $ git clone
新來的實習生首先要 clone 整個項目到本地來,然後才能增刪改查。
當然了實際工作中也沒人這麼用。。因為每家公司都會有自己包裝的工具。不過如果是做 Github 上的開源項目,就用得上了。
6. $ git pull
小齊提交了新的代碼之後,領導要審查呀,所以用 git pull
把最新的代碼拉取下來瞅瞅。
實際上呢,
git pull = fetch + merge
7. $ git fetch
git fetch
這個操作是將遠程庫的數據下載到本地庫,但是工作區中的文件沒有更新。
而要談 get merge
,我們還需要先講下分支
。
merge
是 git pull
默認的選項,合併其實還有另外一種方法:rebase
,中文叫做變基。
8. $ git rebase
rebase 的作用更多的是來整合分叉的歷史,可以將某個分支上的所有修改都移到另一分支上,就像是變了基底。
分支與合併
首先我們來看幾個關於分支的基本操作:
9. 查看分支:
$ git branch
類似於ls
,能夠列出當前所有分支。
git branch -v
能夠顯示更多信息。
10. 創建分支:
$ git branch <branchName>
11. 切換分支:
$ git checkout <branchName>
有了分支之後必然會有合併:
12. 合併分支:
$ git merge <branchName>
而合併時就可能會有衝突,什麼時候會有衝突呢?:
在同一個文件的同一個位置修改時。
因為 Git 會努力的把你們改動不同的地方合併在一起,但如果實在是在同一個地方改的,那它也沒辦法了,只能留給程序員去手動處理了。
當然了,每個命令延伸下去還有無限多個,本文不可能涵蓋全部,所以在此重磅推薦齊姐精心挑選的三大學習資源,大家可以自行享用~
學習資源
git help
其實我個人使用最多的是git help
真心方便又好用啊!
比如 git help pull
:
先介紹了有哪些參數,然後 description 詳細解釋了它的工作原理,下面還有圖解,有木有太香!!
不過這種方式更像是 cheatsheet
,當你已經知道了這個命令、只是忘了它的用法的時候去查。
如果你想系統的學習,那麼下面 👇 的更適合你。
Pro Git
這本書是強烈推薦了!!
Pro Git 這本書不僅講了 Git 的基礎用法、高級用法,以及最後還深入講解了 Git 的原理,非常細緻全面。
書的電子版也能在網站上直接下載。
英文版:
//git-scm.com/book/en/v2
中文版:
//git-scm.com/book/zh/v2
玩遊戲
Practice makes perfect!
推薦一個寶藏資源:玩遊戲來練 Git
項目://github.com/pcottle/learnGitBranching
網址://learngitbranching.js.org/
我熟悉很多工具都是通過小遊戲來練習的,比如 vim 的操作,還是蠻推薦這種方式的。就不劇透啦,大家自己去探索吧~
如果你喜歡這篇文章,記得給我點贊留言哦~你們的支持和認可,就是我創作的最大動力,我們下篇文章見!
我是小齊,紐約程序媛,終生學習者,每天晚上 9 點,雲自習室里不見不散!
更多乾貨文章見我的 Github: //github.com/xiaoqi6666/NYCSDE