Git彙總--物件及版本庫儲存
下述內容為團隊內部分享整理所得,實用性較強,整體性偏差!
PS:關於完整的Git內容,請參照之前發表過一系列文章,詳見:Git Pro深入淺出(一)、Git Pro深入淺出(二)、Git Pro深入淺出(三)
推薦兩個地址:ProGit、GotGit
閱讀完內容,你會很快的解決下面問題,並瞭解其底層原理。
問題1:如何丟棄本地工作區修改的內容?
$ git checkout -- <filename>
問題2:如何丟棄本地工作區和暫存區修改的內容?
$ git checkout HEAD <filename>
問題3:誤刪了檔案且已經提交推送到遠端倉庫,如何恢復?
# 檢視遠端前一次提交的檔案樹 支援管道過濾 | grep <filename>
$ git ls-files --with-tree=origin/HEAD^
# 檢視前一次提交的指定檔案內容 > welcome.txt
$ git cat-file -p origin/HEAD^:<filename>
# 當然,也可以採用reflog形式
問題4:如何忽略某檔案?如何只讓其本地生效?
.git/info/exclude
中配置
簡介
Git作者Linus Torvalds,其是一款分散式版本控制系統。
- CVS:集中式版本控制系統。CVS採用客戶端/伺服器架構設計,版本庫位於伺服器端,實際上就是一個RCS檔案容器。每一個RCS檔案以“
.v
- SVN:集中式版本控制系統。擁有全域性版本號,每提交一次,SVN的版本號就會自動加一。利用輕量級拷貝,SVN在不同的名字空間下建立不同的目錄實現里程碑和分支的建立,輕鬆地解決了CVS中存在的里程碑、分支建立速度慢又不可見的問題。SVN還有一個突破,就是在工作區跟蹤目錄(
.svn
目錄)下為當前目錄中的每一個檔案都儲存一份冗餘的原始拷貝(工作區的根目錄和每一個子目錄下都有一個.svn
目錄)。這樣做的好處一個是提高了網路的效率,在提交時僅傳輸變更差異,另外一個好處是部分操作不再需要網路連線,如本地修改的差異比較,以及本地更改的回退等。 - Git:分散式版本控制系統。每個人都擁有一個完整的版本庫。分散式版本控制系統的幾乎所有操作包括檢視提交日誌、提交、建立里程碑和分支、合併分支、回退等都直接在本地完成而不需要網路連線。協同工作模型(版本庫間推送、拉回,及補丁檔案傳送等)讓開源專案的參與度有爆發式增長。
Git物件
git init
會建立一個 .git
目錄。這個目錄包含了幾乎所有 Git 儲存和操作的物件。 如若想備份或複製一個版本庫,只需把這個目錄拷貝至另一處即可。
$ ll .git
-rw-r--r-- 1 ligang staff 6B 11 1 10:13 COMMIT_EDITMSG
-rw-r--r-- 1 ligang staff 212B 10 31 10:02 FETCH_HEAD
-rw-r--r-- 1 ligang staff 23B 8 21 15:23 HEAD
-rw-r--r-- 1 ligang staff 41B 10 31 10:02 ORIG_HEAD
drwxr-xr-x 2 ligang staff 64B 8 15 2017 branches
-rw-r--r-- 1 ligang staff 311B 8 15 2017 config
-rw-r--r-- 1 ligang staff 73B 8 15 2017 description
drwxr-xr-x 31 ligang staff 992B 5 10 14:44 hooks
-rw-r--r-- 1 ligang staff 6.9M 11 1 10:13 index
drwxr-xr-x 4 ligang staff 128B 5 9 16:11 info
drwxr-xr-x 4 ligang staff 128B 5 9 16:11 logs
drwxr-xr-x 152 ligang staff 4.8K 11 1 10:13 objects
-rw-r--r-- 1 ligang staff 166B 5 9 16:11 packed-refs
drwxr-xr-x 6 ligang staff 192B 7 3 09:53 refs
-rw-r–r--:第一位用於標識檔案型別,d表示目錄、l表示連結檔案、-表示檔案;其他表示系統使用者許可權rw-rw-(Owner)r–(Group)r–(Other)【r可讀、w可寫、x可執行】
版本庫位於工作區根目錄下的.git
目錄中,且僅此一處,在工作區的子目錄下則沒有任何其他跟蹤檔案或目錄。Git的這種設計,將版本庫放在工作區根目錄下,所有的版本控制操作(除了和其他遠端版本庫之間的互操作)都在本地即可完成。
$ git log -1 --pretty=raw
# 本次提交的唯一標識
commit b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
# 本次提交所對應的目錄樹
tree 1e0c5cb85e1d2b4ff6875a5bbaa9183389ace668
# 本地提交的父提交(上一次提交)
parent 3365948518aad171336a52674cbdf0450679b4dc
author ligang <[email protected]> 1543761152 +0800
committer ligang <[email protected]> 1543761152 +0800
feat(git): git 彙總
研究Git物件ID的一個重量級武器就是git cat-file
命令。
檢視一下這三個ID的型別:
$ git cat-file -t b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
commit
$ git cat-file -t 1e0c5cb85e1d2b4ff6875a5bbaa9183389ace668
tree
$ git cat-file -t 3365948518aad171336a52674cbdf0450679b4dc
commit
檢視物件的內容:
$ git cat-file -p <commitID>
Git 有一個底層命令git rev-parse
可以用於顯示引用對應的提交ID
$ git rev-parse master
b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
$ git rev-parse refs/heads/master
b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
$ git rev-parse HEAD
b93afd2cce7e065dd4e7c33d1c6a4b3a7a75b259
可以看出它們都指向同一個物件!
- 顯示版本庫
.git
目錄所在的位置
$ git rev-parse --git-dir
/Users/ligang/Documents/github/practice/.git
- 顯示工作區根目錄
$ git rev-parse --show-toplevel
/Users/ligang/Documents/github/practice
git rev-parse
是Git的一個底層命令,其功能非常豐富(或者說雜亂),很多Git指令碼或工具都會用到這條命令。
- 顯示分支
$ git rev-parse --symbolic --branches
- 顯示tags
$ git rev-parse --symbolic --tags
- 顯示HEAD對應的SHA1雜湊值
$ git rev-parse HEAD
- …
版本庫儲存
本地(工作區、暫存區、HEAD)
說明 |
---|
工作區 |
Git暫存區(stage,或稱為index) |
HEAD(當前分支,注意非遠端) |
-
HEAD實際是指向master分支的一個“遊標”,HEAD全部可以使用master替換;
-
objects為Git的物件庫,位於
.git/objects
目錄下; -
工作區 <==> 暫存區
命令 說明 git add ./<filename>
將工作區變更提交到暫存區 git checkout ./<filename>
git checkout -- <filename>
暫存區內容覆蓋工作區 git rm --cached <file>
直接從暫存區刪除檔案,工作區則不做出改變 -
暫存區 <==> HEAD
命令 說明 git commit -s -m ""
將暫存區提交到master分支
(即master指向的目錄樹就是原暫存區的目錄樹)git reset HEAD ./<filename>
使用master指向的目錄樹替換快取區 git checkout HEAD ./<filename>
用HEAD指向的master分支內容替換暫存區及工作區的檔案
重點來了! 如何還原本地工作區某檔案
$ git reset HEAD <filename>
$ git checkout <filename>
# 替換命令
$ git checkout HEAD <filename>
本地(stash)
git stash
儲存當前工作進度,會分別對暫存區和工作區的狀態進行儲存。
$ git stash [save [–patch] [-k|–[no-]keep-index] [-q|–quiet] [<message>]]
save "message..."
儲存工作進度時使用指定說明--patch
會顯示工作區和HEAD的差異,通過對差異檔案的編輯決定在進度中最終要儲存的工作區的內容-k
或者--keep-index
引數,在儲存進度後不會將暫存區重置。預設會將暫存區和工作區強制重置!
注意: 本地沒有被版本控制系統跟蹤的檔案並不能儲存進度,即新建立檔案需要 git add
。
恢復工作進度,可以通過下述命令:
$ git stash apply [–index] [<stash>]
$ git stash drop [<stash>]
# 等價於上述兩條命令
$ git stash pop [–index] [<stash>]
遠端(remote)
$ cd .git/refs/remotes
$ ll
drwxr-xr-x 5 ligang staff 160B 11 28 10:42 origin
drwxr-xr-x 11 ligang staff 352B 11 27 00:11 upstream
$ ll origin
-rw-r--r-- 1 ligang staff 32B 11 8 09:43 HEAD
-rw-r--r-- 1 ligang staff 41B 11 28 10:42 feature-v2.1
-rw-r--r-- 1 ligang staff 41B 11 28 10:42 master
$ ll upstream
-rw-r--r-- 1 ligang staff 41B 11 27 00:11 develop
-rw-r--r-- 1 ligang staff 41B 11 27 00:11 master
-rw-r--r-- 1 ligang staff 41B 11 27 00:11 themes
$ cat origin/develop
eeaa2013d901bda74eaa9fe102abe1e474b7a5d6
$ git ls-tree eeaa2013d901bda74eaa9fe102abe1e474b7a5d6
Git 這樣的設計是非常巧妙的,在向遠端版本庫執行獲取操作時,不是把遠端版本庫的分支原封不動地複製到本地版本庫的分支中,而是複製到其名稱空間中。如在克隆一個版本庫時,會將遠端分支都複製到目錄 .git/refs/remotes/origin/
下。這樣向不同的遠端版本庫執行獲取操作,因為遠端分支相互隔離,所以就避免了相互的覆蓋。
- 新增新遠端版本庫
$ git remote add remote-name [email protected]:project-namespace/project-name.git
$ git remote -v