超詳實Git簡明教程與命令大全

騰訊IVWEB團隊發表於2018-10-26

Git (wiki: en chs )是一個免費開源的分散式版本控制系統,由linux核心作者linus Torvalds開發,大型開源專案linux kernelAndroidchromiummonodotnetUE4等都使用Git管理專案

著名github網站使用Git託管所有專案程式碼,Git的程式碼也託管在github上,連結為:github.com/git

與集中式版本控制系統(開源軟體:SVN;免費軟體:CVS;商業軟體:微軟的VSS、IBM的Rational ClearCase)相比

Git優點

① 本地是版本庫的完整映象,因此支援離線工作

② 絕大多數操作都只需要訪問本地檔案和資源,而且與每個提交都是所有檔案的完整副本,因此速度非常快

超詳實Git簡明教程與命令大全


注:SVN等集中式版本控制系統儲存每個檔案與初始化版本的差異

超詳實Git簡明教程與命令大全


注:Git每個提交都是所有檔案的完整副本,使得Git在回溯到某個提交時,不會對所有檔案執行差異計算還原,因此速度會非常快

③ 強大快捷的分支功能,非常適合非線性開發過程

Git缺點

① 只能全量整體,而不能以子目錄和分支為單位進行更新、提交等操作

② 子目錄和分支不能單獨進行許可權控制

③ 由於每個提交都是所有檔案的完整副本,因此更佔磁碟空間

這使得原始碼、配置檔案等更適合用Git來管理,而資源等較大的二進位制檔案則容易導致版本庫體積膨脹

在專案實踐中,對於資源等較大的二進位制檔案可以採用Git-LFS來管理,UE4則是使用自己開發的GitDependencies來管理

基本概念

origin:預設遠端版本庫名

master:預設分支名

origin/master:遠端預設分支名

HEAD:當前分支頂端Commit的別名,即當前分支最近的一個提交的SHA-1雜湊值

ORIG_HEAD:上次HEAD指標的位置。注:當執行git reset/git pull/git merge命令時,git會把老的HEAD拷貝到檔案.git/ORIG_HEAD中,在後續命令中可以使用ORIG_HEAD引用這個提交

commit(提交):每個commit都是全部檔案的完整快照,並用一個 commitID(基於檔案的內容或目錄結構計算出來的40位十六進位制的SHA-1雜湊值) 來唯一標誌。從某個角度上來說,Git維護的就是一個commitID有向無環圖

detached HEAD:HEAD沒有指向任何分支的狀態。一般有以下幾種情況會出現這種情況:

① 使用checkout命令跳到某個沒有分支指著的commit時

② rease處理衝突時所處的狀態

③ 切換到某個遠端分支cache上時

在Git中,在執行命令時,一定要清楚:你在哪?對誰執行這個命令?

本文使用git版本為:git version 2.13.0.windows

執行命令列建議使用:git bash(可通過右鍵選單 Git Bash here來啟動),主要有3個原因:

① 在windows的cmd下執行git log等需要顯示多頁內容的命令時,會導致cmd卡死(有時按Q鍵也沒法退出)

② git bash中可以使用MinGW中自帶的linux環境下常用的命令工具

③ git bash著色做得更好,利於閱讀

圖解常見操作

Working Directory:即工作區。作業系統層面的目錄樹結構,也可以理解為一個tree目錄物件

Stage(Index):即暫存區,為等待Commit的檔案列表。是以扁平的檔案清單實現的,不過從理解層面上也可以理解為tree目錄物件

Local Repository(History):本地版本庫。有向無環圖,其每一個節點都是一個tree目錄物件

Remote Repository:遠端版本庫。有向無環圖,其每一個節點都是一個tree目錄物件

超詳實Git簡明教程與命令大全


注:圖中git checkout -- <file>①②步驟的含義是當在暫存區中有修改時,優先使用暫存區中的修改覆蓋工作區

svn命令對比一覽

svngit說明
svn checkoutgit clone檢出專案
svn update

git fetch

git pull

更新
svn commit

git commit

git push

提交
svn addgit add新增
svn mvgit mv移動
svn rmgit rm刪除
svn statusgit status檢視狀態
svn loggit log檢視log
svn diffgit diff檢視差異
svn revert

git checkout

git reset

git revert

撤銷、丟棄修改
svn copy

git checkout -b/-B

git branch

建立分支
svn switchgit checkout切換分支
svn copygit tag建立tag
svn merge

git merge

git rebase

分支合併

檔案儲存機制

Git儲存使用的是一個內容定址的檔案系統,其核心部分是一個簡單的鍵值對(key-value)資料庫,當向資料庫中插入任意型別的內容,它會返回一個40位十六進位制的SHA-1雜湊值用作索引。

在版本庫中,Git維護的資料結構有:以下4種物件及索引,並通過儲存commitID有向無環圖的log日誌來維護與管理專案的修訂版本和歷史資訊。

blob -- 1個blob儲存1個檔案的1個版本的資料

tree -- 表示1個目錄,記錄著目錄裡所有檔案blob雜湊值、檔名子目錄名及其他後設資料。通過遞迴引用其他目錄樹,從而建立一個包含檔案和子目錄的完整層次結構

commit -- 1個提交物件儲存版本庫中每一次變化的後設資料,每個提交物件指向一個版本的git目錄樹物件

tag -- 分為輕量標籤和附註標籤。輕量標籤實際上是一個特定提交的引用,附註標籤是儲存在git中的一個完整可被校驗的物件(儲存在.git/refs/tags中),還包含打標籤者的名字、e-mail、日誌、註釋等資訊

git使用zlib將頭部資訊(物件型別:blob或tree或commit + 1個空格 + 資料內容長度 + 1個空位元組)和物件資料拼接一起的內容進行壓縮儲存成一個檔案

壓縮的檔案被十六進位制的SHA-1雜湊值命名,該檔案可以用pigz.exe -dz < 檔案路徑來解壓檢視。注:windows版的pigz.exe可以從這兒 下載

40位十六進位制的SHA-1雜湊值 = sha1("blob/tree/commit " + filesize + "\0" + data) 如:sha1("blob 7\0foobar\n") = "323fae03f4606ea9991df8befbb2fca795e648fa" 注:\n的二進位制為0a

超詳實Git簡明教程與命令大全


底層命令 -- 剖析Git物件

find .git/objects -type f // 用find命令檢視.git/objects目錄(遞迴子目錄)中的所有檔案

git rev-list --objects --all // 檢視所有git物件的SHA-1雜湊值與檔名的對應關係

git rev-list --objects --all | grep 83c4fbc43a6f187d4e8a247a1c9aced872b2315d // 檢視SHA-1雜湊值為83c4fbc43a6f187d4e8a247a1c9aced872b2315d的檔名

echo "Hello World!" | git hash-object --stdin // 計算內容為Hello World!檔案的SHA-1雜湊值

echo "Hello World!" | git hash-object -w --stdin // 計算內容為Hello World!檔案的SHA-1雜湊值並寫入到當前git本地版本庫中

git hash-object README.txt // 檢視README.txt的SHA-1雜湊值

git hash-object -w README.txt // 檢視README.txt的SHA-1雜湊值並寫入到當前git本地版本庫中

git cat-file -p master^^{tree} // 檢視master分支HEAD指標git目錄(tree物件)下的各子目錄(tree物件)和檔案(blob物件)的SHA-1雜湊值

100644 blob 7abd3a56703ad4a7120571967f5d06607b5e5502 README.txt
040000 tree 9f448c40e684dc38109574007c661277c815fb7e ss

注:040000:表示目錄 100644:表示一般檔案 100755:表示可執行檔案 120000:表示符號連結

git cat-file -p 7abd3a56703ad4a7120571967f5d06607b5e5502 // 檢視SHA-1雜湊值為7abd3a56703ad4a7120571967f5d06607b5e5502檔案的內容

git show 7abd3a56703ad4a7120571967f5d06607b5e5502 // 檢視SHA-1雜湊值為7abd3a56703ad4a7120571967f5d06607b5e5502檔案的內容

git cat-file -t f3961f5 // 檢視f3961f5提交物件的型別:顯示為commit

git cat-file -p f3961f5 // 檢視f3961f5提交物件的資訊:包含git目錄(tree物件)、上次提交物件的SHA-1雜湊值及提交時Author、Date和註釋資訊

tree ead34240822030a3f71df4fc351057d80d7d83f8
parent 33d5bbc5d61b024aab5078e40548c4e3da808e0e
author nicochen <nicochen@tencent.com> 1537258258 +0800
committer nicochen <nicochen@tencent.com> 1537258258 +0800

123 desc txt

git cat-file -p tag1.0 // 檢視輕量標籤或附註標籤tag1.0資訊

git cat-file tag tag1.0 // 檢視附註標籤tag1.0資訊

git ls-tree ead34240822030a3f71df4fc351057d80d7d83f8 // 檢視tree目錄物件ead34240822030a3f71df4fc351057d80d7d83f8中包含的blob檔案物件和tree目錄物件

git ls-tree HEAD // 檢視HEAD所指向tree目錄物件中包含的blob檔案物件和tree目錄物件

git verify-pack -v .git/objects/pack/pack-a9282552b62cbe3f255fbb20374695a17c1ba2a2.idx // 檢視pack-a9282552b62cbe3f255fbb20374695a17c1ba2a2.pack壓縮包中的內容

git update-index n.txt // 將修改狀態的n.txt檔案新增到暫存區

git update-index --add n.txt // 將未追蹤狀態或修改狀態的n.txt檔案新增到暫存區

git update-index --add --cacheinfo 100644 5d11580eed65ffd34b6786274a60460b3582aa7d n.txt // 使用型別為100644、SHA-1雜湊值為5d11580eed65ffd34b6786274a60460b3582aa7d的資訊將追蹤狀態或修改狀態的n.txt新增到暫存區

git write-tree // 將整個暫存區內容生成一個tree物件,並輸出其SHA-1雜湊值

echo "add n.txt" | git commit-tree 31b7ca405196ca9e8fb4d5404b315bef9f2c841f -p HEAD // 用git write-tree得到的31b7ca405196ca9e8fb4d5404b315bef9f2c841f樹物件建立一個註釋為add n.txt的提交物件,並將提交物件的父親設定為當前HEAD

git update-ref refs/heads/master 372aa8e425b57ca30e2974b8e7737133caaa0b7f // 若當前分支為master,更新HEAD指向上面git commit-tree命令得到的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交物件,此時用git log就可以看到這條commit記錄

git write-tree --prefix=ss // 將暫存區中ss目錄下的內容 生成一個tree物件,並輸出其SHA-1雜湊值

git update-ref -d refs/remotes/origin/v1.0 // 刪除v1.0遠端分支cache

git update-index --chmod=+x engine_mac.sh // 為engine_mac.sh增加可執行許可權(linux、unix、mac os x系統上需要)

命令大全

檢視命令幫助

git config --help // 檢視git config命令詳細用法

git help config // 功能同上

配置

git config --global user.name "kekec" // 配置提交使用者名稱
git config --global user.email "kekec@qq.com" // 配置e-mail資訊

git config --global core.editor vim // 配置預設文字編輯器,當Git 需要你輸入資訊時會呼叫它

git config --global alias.st status // 為status配置別名st,這樣git status就可以寫成git st

git config --list // 檢視當前倉庫的所有配置資訊(包括分支相關的資訊)

git config user.name // 檢視當前倉庫的使用者名稱資訊

git config -e --global // 編輯全域性配置檔案(使用者名稱和e-mail資訊就記錄在其中) 所在目錄:c:/users/<使用者名稱>/.gitconfig

git config -e // 編輯當前倉庫的配置檔案 所在目錄:.git\config

建立版本庫

git init // 在當前目錄建立一個空的git程式碼庫

git init MyGame // 在當前目錄建立一個名為MyGame的資料夾,然後在其中建立一個空的git程式碼庫

.git目錄結構如下:

超詳實Git簡明教程與命令大全


hooks:不同操作時執行的hook指令碼

info/exclude:與.gitignore檔案(該檔案需放在.git資料夾的同級目錄中,windows下可通過命令列type nul > .gitignore來建立)一樣,用作檔案過濾。不同的是:該檔案不會提交到版本庫,因此過濾只對本地生效,不影響其他人

# 忽略所有.so 結尾的檔案
*.so
# 但 game.so 除外
!game.so
# 僅僅忽略專案根目錄下的 README.md 檔案,不包括 subdir/README.md
/README.md
# 忽略 .svn/ 目錄下的所有檔案
.svn/
# 會忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# 忽略 doc/ 目錄下所有副檔名為 txt 的檔案
doc/**/*.txt複製程式碼

logs/refs/heads:各個本地分支的版本log記錄

logs/refs/remotes:各個遠端分支cache的log記錄

logs/refs/stash:儲藏區資料

logs/HEAD:git操作記錄

objects:2級檔案索引(把SHA-1雜湊值拆成了:2位+38位),儲存commit資料、blob檔案資料和tree目錄資料

objects/pack:pack檔案為儲存commit、tree目錄及blob檔案的壓縮資料;idx檔案為pack檔案中各資料物件的索引

objects/info/packs:該檔案記錄所有git庫的pack檔案列表

refs/heads:各個本地分支HEAD

refs/remotes:各個遠端分支cache的HEAD

refs/tags:各個附註標籤的資訊

COMMIT_EDITMSG:上一次提交的註釋

config:版本庫相關的配置資訊

description:倉庫描述資訊,供gitweb程式使用

index:暫存區相關的資訊

HEAD:指向當前分支的最近提交(如:ref: refs/heads/master)

ORIG_HEAD:執行git merge/git pull/git reset操作時,會把調整為新值之前的先前版本的HEAD記錄到OERG_HEAD中,用於恢復或回滾之前的狀態

FETCH_HEAD:git fech將所有抓取分支的HEAD記錄到.git/FETCH_HEAD中

MERGEHEAD:正在合併進HEAD的commit id

packed-refs:遠端版本庫cache和遠端標籤cache

日誌與檔案狀態

git reflog // 檢視操作記錄 注:每條操作記錄使用HEAD@{n}來標識

git show HEAD@{5} // 檢視索引為5的操作記錄的詳細資訊

git status // 檢視當前所處的分支暫存區和工作區的檔案(會顯示當前所處分支)

注1:處於暫存區的檔案狀態::staged(已暫存);處於工作區的檔案狀態::untrack(未跟蹤)、modified(已修改)

注2:工作區中的空目錄不會被git追蹤

git status -s --ignored // 以簡潔模式檢視暫存區和工作區的檔案(全部顯示,不執行檔案過濾)

git status -uno // 檢視暫存區和工作區的非untrack(未跟蹤)狀態檔案

git status -uall // 檢視暫存區和工作區的狀態檔案(遞迴子目錄顯示出裡面的檔案)

git log // 檢視本地版本庫提交記錄(會顯示當前所處分支,HEAD指標指向哪個分支的哪條提交)

git log --stat // 檢視本地版本庫提交記錄(會顯示當前所處分支,HEAD指標指向哪個分支的哪條提交和每次提交的檔案變更簡略統計資訊)

git log -- README.md // 檢視README.md檔案的本地版本庫提交記錄

git log --graph -- README.md // 以圖形化方式檢視README.md檔案的本地版本庫提交記錄

git log -p README.md // 檢視README.md檔案的本地版本庫提交記錄(顯示出每次的修改內容)

git log --grep "test" // 顯示註釋中含有test字串的提交

git log --author=kekec // 檢視本地版本庫中作者為kekec的提交記錄

git log -S "SplitPath(FString& str)" // 檢視SplitPath(FString& str)內容是什麼時候加到專案中那些檔案中去的

git log --since=2.weeks // 檢視最近2周的提交記錄

git log --since="2 weeks 3 days 2 hours 30 minutes 59 seconds ago" // 檢視2周3天2小時30分59秒以前的提交記錄

git log --after="2018-10-7" --before="2018-10-12" // 檢視2018.10.7~2018.10.12之間的提交記錄

git log --since="2018-10-7" --until="2018-10-12" // 功能同上:git log --after="2018-10-7" --before="2018-10-12"

注:--since、--until 標記和 --after、--before 標記分別是等價的

git whatchanged README.md // 檢視README.md檔案的本地版本庫提交記錄(包括檔案改名)

git log --follow README.md // 功能同上:git whatchanged README.md

git log -3 // 檢視最近3條本地版本庫提交記錄

git log -3 --pretty --oneline // 檢視最近3條本地版本庫提交記錄(簡潔模式,一行顯示一個提交)

git log --graph --oneline // 以圖形化簡潔模式檢視當前分支的本地版本庫提交記錄

git log release --graph --oneline // 以圖形化簡潔模式檢視release分支的本地版本庫提交記錄

git log --graph --oneline --no-merges // 以圖形化簡潔模式檢視當前分支的本地版本庫提交記錄(過濾merge過來的提交)

git log --graph --oneline --merges // 以圖形化簡潔模式檢視當前分支的本地版本庫提交記錄(只顯示有2個及以上父親節點的提交)

git log --graph --oneline --name-only // 以圖形化簡潔模式檢視當前分支的本地版本庫提交記錄(並顯示每次提交的檔名稱清單)

git log --graph --oneline --name-status // 以圖形化簡潔模式檢視當前分支的本地版本庫提交記錄(並顯示每次提交的檔案狀態、名稱清單)

git log --graph --oneline --stat // 以圖形化簡潔模式檢視當前分支的本地版本庫提交記錄(並顯示每次提交的檔案變化統計、各檔名及增刪記錄)

git log --graph --oneline --shortstat // 以圖形化簡潔模式檢視當前分支的本地版本庫提交記錄(並顯示每次提交的檔案變化統計及增刪記錄)

git log --graph --oneline --decorate --all // 以圖形化簡潔模式檢視所有分支的本地版本庫提交記錄樹

git log --graph --pretty=format:"%H - %an, %ad : %s" // 自定義格式圖形化檢視所有分支的本地版本庫提交記錄樹

%H 提交物件(commit)的完整雜湊字串
%h 提交物件的簡短雜湊字串
%T 樹物件(tree)的完整雜湊字串
%t 樹物件的簡短雜湊字串
%P 父物件(parent)的完整雜湊字串
%p 父物件的簡短雜湊字串
%an 作者(author)的名字
%ae 作者的電子郵件地址
%ad 作者修訂日期(可以用 --date= 選項定製格式)
%ar 作者修訂日期,按多久以前的方式顯示
%cn 提交者(committer)的名字
%ce 提交者的電子郵件地址
%cd 提交日期
%cr 提交日期,按多久以前的方式顯示
%s 提交說明

git log master..v5.0 // 檢視v5.0分支還未合併到master分支上的提交記錄列表

git log v5.0..master // 檢視master分支還未合併到v5.0分支上的提交記錄列表

git log master...v5.0 // git log master..v5.0 + git log v5.0..master

git shortlog -sn // 統計各個提交者的次數

git blame README.md // 顯示README.md最近一次的修改資訊

git show 3a6c702376168aa15a2f3d7bc98000d07a70d023 README.md // 檢視README.md檔案的3a6c702376168aa15a2f3d7bc98000d07a70d023提交的修改內容

git show HEAD // 檢視最近一次提交的修改內容

git show --name-only HEAD // 檢視最近一次提交的檔案列表(不顯示具體的修改內容)

標籤(檢視/新建/切換/刪除)

git tag // 列出所有的標籤

git tag -l 'tag1*' // 列出所有tag1開頭的標籤

git tag tag1.0 // 建立名為tag1.0的輕量標籤

git tag -a tag1.0 -m "tag1.0 desc" // 新增tag1.0 desc註釋並建立名為tag1.0的附註標籤

git tag tag2.0 abffefc5d82078cbaea7fcbb5106ab0c21cbeba9 // 在abffefc5d82078cbaea7fcbb5106ab0c21cbeba9提交處建立名為tag2.0的輕量標籤

git tag -a tag2.0 -m "tag2.0 desc" abffefc // 在abffefc提交處建立名為tag2.0的附註標籤

git tag -d tag2.0 // 刪除名為tag2.0的標籤

git show tag1.0 // 檢視名為tag1.0相關的資訊

git ls-remote --tags // 檢視所有遠端的標籤

分支(檢視/新建/切換/刪除)

git branch // 列出所有本地分支

git branch -r // 列出所有遠端分支cache

git branch -a // 列出所有本地分支和遠端分支cache

git branch -av // 列出所有本地分支和遠端分支cache(含簡單說明)

git branch -vv // 檢視所有本地分支和遠端分支cache之間的追蹤關係

git branch v1.0 // 在當前分支的HAED指標下建立名為v1.0的分支(建立完不會切到v1.0分支上)

git branch --track v1.0 origin/v1.0 // 若v1.0分支不存在則先新建,然後將其與遠端分支origin/v1.0建立追蹤關係 ① 遠端分支origin/v1.0要存在,否則命令執行失敗 ② 執行完不會切到v1.0分支上

git branch v2.0 372aa8e425b57ca30e2974b8e7737133caaa0b7f // 在372aa8e425b57ca30e2974b8e7737133caaa0b7f提交處建立名為v2.0的分支(建立完不會切到v2.0分支上)

git branch -m v1.0 x1.0 // 將分支v1.0重新命名為x1.0

git checkout v1.0 // 切換到v1.0分支上(v1.0分支不存在則命令執行失敗)

git checkout -b v1.0 // 建立並切換到v1.0分支上(v1.0分支存在則命令執行失敗)

git checkout -B v1.0 // 不存在則建立,並切換到v1.0分支上

git checkout -b v1.0 5a95f2d // 在5a95f2d提交處建立並切換到v1.0的分支上

git checkout -b v1.0 tag1.0 // 在標籤tag1.0處建立並切換到v1.0的分支上

git checkout -t origin/v1.0 // 建立並切換到origin/v1.0遠端分支cache的名為v1.0本地分支上,並建立兩者追蹤關係(本地分支v1.0存在則命令執行失敗)

git checkout -b x1.0 -t origin/v1.0 // 建立並切換到origin/v1.0遠端分支cache的名為x1.0本地分支上,並建立兩者追蹤關係(本地分支x1.0存在則命令執行失敗)

注1:切換分支前,必須處理工作區(未追蹤的檔案不用處理)和暫存區的修改才能切換成功

注2:切換成功後,工作區會被設定成分支的內容

注3:不允許在遠端分支cache上提交,需要建立對應關聯的本地分支,然後在本地分支上進行提交

git checkout -f v1.0 // 強制切換到v1.0分支上,丟棄暫存區和工作區中的所有檔案的修改(工作區中未追蹤的檔案不受影響)

git checkout -f -B v1.0 origin/v1.0 // 不存在則建立,強制切換到v1.0分支上,丟棄暫存區和工作區中的所有檔案的修改,並將HEAD指向origin/v1.0處(工作區中未追蹤的檔案不受影響)

git checkout - // 切換到上一次分支

git branch -d v2.0 // 刪除名為v2.0的分支(必須先切到其他分支上才能執行刪除操作)

git branch -D v2.0 // 強制刪除名為v2.0的分支(必須先切到其他分支上才能執行刪除操作)

git branch -dr origin/v2.0 // 刪除遠端分支origin/v2.0 cache

檔案(增加/刪除/提交/撤銷)

git add README.md // 將當前目錄下的README.md檔案加入到暫存區

git add . // 將當前目錄下(遞迴子目錄)所有檔案加入到暫存區

git add -u . // 將當前目錄下(遞迴子目錄)所有追蹤狀態的檔案加入到暫存區

git add Doc/\*.txt // 將當前目錄的Doc資料夾下(遞迴子目錄)所有txt字尾的檔案加入到暫存區

git rm README.md // 刪除工作區檔案,並且將這次刪除放入暫存區(若README.md在工作區或暫存區中有修改,命令會執行失敗)

git rm -f README.md // 強制刪除工作區檔案,並且將這次刪除放入暫存區(即使README.md在工作區或暫存區中有修改,也會執行刪除操作)

git rm --cached README.md // 不刪除工作區對應的檔案,只將README.md刪除放入暫存區以供提交

git mv README.md test.md // 將README.md改名為test.md,並且將這個改名放入暫存區

git commit -m "desc" // 新增desc註釋並將暫存區中的所有修改提交到本地倉庫

git commit README.md -m "desc" // 新增desc註釋並將暫存區中的README.md的修改提交到本地倉庫

git commit --amend -m "desc" // 新增desc註釋使用當前提交覆蓋上一次的提交(若上一次提交包含1.txt和2.txt的修改,當前提交只包含1.txt的修改;執行命令後,本地版本庫中為本次的1.txt和上一次2.txt)。若沒有提交內容,則用來改寫上一次提交的日誌資訊

git commit -m "desc" --amend README.txt // 新增desc註釋使用README.txt的當前提交覆蓋上一次的提交

git commit -a -m "desc" // 新增desc註釋並將工作區和暫存區中的所有修改提交到本地倉庫

git commit -am "desc" // 功能同上

git commit -c b5cad94d229e72bd7aff5fe2c6f022b29c30e7a8 // 拿372aa8e425b57ca30e2974b8e7737133caaa0b7f提交的資訊(作者、提交者、註釋、時間戳等)來提交當前修改

git reset -- README.md // 丟棄暫存區中的README.md檔案的修改

git reset README.md // 功能如上 丟棄暫存區中的README.md檔案的修改

git reset b5cad94 README.md // 使用本地版本庫b5cad94提交處的README.md版本覆蓋暫存區中的README.md

git reset // 丟棄暫存區中的所有檔案的修改(工作區不受影響)

git reset --mixed // --mixed為預設引數,命令與上面git reset一樣

git reset --hard // 丟棄暫存區和工作區中的所有檔案的修改(工作區中未追蹤的檔案不受影響)

git reset --soft b5cad94d229e72bd7aff5fe2c6f022b29c30e7a8 // 僅將當前分支的HEAD指向372aa8e425b57ca30e2974b8e7737133caaa0b7f提交(暫存區和工作區中的所有檔案的修改都不丟棄)

git reset --soft HEAD~ // 僅將當前分支的HEAD指向上一次提交(暫存區和工作區中的所有檔案的修改都不丟棄)

git reset --soft HEAD~2 // 僅將當前分支的HEAD指向上兩次提交(暫存區和工作區中的所有檔案的修改都不丟棄)

git reset --merge <commit> // 在被汙染的工作區中回滾merge或者pull

$ git pull                         (1) 
Auto-merging nitfol 
Merge made by recursive. 
nitfol                |   20 +++++---- 
... 
$ git reset --merge ORIG_HEAD      (2)複製程式碼

(1) 即便你已經在本地更改了一些你的工作區,你也可安全的git pull,前提是你知道將要pull的內容不會覆蓋你的工作區中的內容。

(2) git pull完後,你發現這次pull下來的修改不滿意,想要回滾到pull之前的狀態,我們可以執行git reset --hard ORIG_HEAD,但是這個命令有個副作用就是清空你的工作區,即丟棄你的本地未add的那些改變。

為了避免丟棄工作區中的內容,可以使用git reset --merge ORIG_HEAD,注意其中的--hard 換成了 --merge,這樣就可以避免在回滾時清除工作區。

git reset --keep <commit> // 保留工作區並丟棄一些之前的提交

假設你正在編輯一些檔案,並且已經提交,接著繼續工作,但是現在你發現當前在工作區中的內容應該屬於另一個分支,與之前的提交沒有什麼關係。此時,可以開啟一個新的分支,並且保留著工作區中的內容。

$ git tag start 
$ git checkout -b branch1 
$ edit 
$ git commit ...                            (1) 
$ edit 
$ git checkout -b branch2                   (2) 
$ git reset --keep start                    (3)複製程式碼

(1) 這次是把在branch1中的改變提交了。

(2) 此時發現,之前的提交不屬於這個分支,此時新建了branch2分支,並切換到了branch2上。

(3) 此時可以用reset --keep把在start之後的提交清除掉,但是保持工作區不變。

git checkout -- README.md // -- 符號非常重,否則就變成了切換到README.md分支了

// 當README.md在暫存區中有修改時,使用暫存區中的修改覆蓋工作區中的README.md

// 當README.md不在暫存區中時,使用本地版本庫中的HEAD指標處的修改覆蓋工作區中的README.md

git checkout -- . // 使用暫存區和本地版本庫來恢復當前目錄(遞迴子目錄)下的所有檔案 注:若暫存區中有修改,優先使用暫存區

git checkout HEAD README.md // 使用本地版本庫中的HEAD處提交覆蓋暫存區和工作區中的README.md

git checkout 9a387f22ff949fa16336508adc2284384bd6a890 README.md // 使用本地版本庫中的9a387f22ff949fa16336508adc2284384bd6a890修改覆蓋暫存區和工作區中的README.md

git checkout -b v2.0 tag2.0 // 在名為tag2.0的提交處建立並切換到v2.0分支上(v2.0分支存在則命令執行失敗)

git revert --no-edit 3a6c702376168aa15a2f3d7bc98000d07a70d023 // 回滾3a6c702376168aa15a2f3d7bc98000d07a70d023提交,然後提交到本地倉庫

git revert HEAD~ // 回滾HEAD的上一次提交,然後會彈出vim環境編輯註釋(輸入:q直接使用預設註釋內容、輸入:q!放棄修改使用預設註釋內容、輸入:x或:wq儲存當前修改的註釋內容),然後提交到本地倉庫

git revert -n HEAD~3 // 回滾掉HEAD~3處的提交,不自動提交到本地倉庫

git revert -n HEAD~2..HEAD // 回滾掉(HEAD~2, HEAD]之間的2次提交,不自動提交到本地倉庫

注:git reset是把HEAD向後移動來刪除提交,而git revert是用一次新的提交來回滾之前的提交(HEAD會繼續前進)

檢視差異

git diff README.md // 檢視當前目錄下的README.md在工作區和暫存區之間的差異

git diff --cached README.md // 檢視當前目錄下的README.md在暫存區和本地倉庫最後一次提交之間的差異

git diff --cached 372aa8e425b57ca30e2974b8e7737133caaa0b7f README.md // 檢視當前目錄下的README.md在暫存區和本地倉庫的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交之間的差異

git diff HEAD README.md // 檢視當前目錄下的README.md在工作區和本地倉庫HEAD指標處提交之間的差異

git diff 372aa8e425b57ca30e2974b8e7737133caaa0b7f README.md // 檢視當前目錄下的README.md在工作區和本地倉庫的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交之間的差異

git diff 372aa8e425b57ca30e2974b8e7737133caaa0b7f HEAD README.md // 檢視當前目錄下的README.md在本地倉庫的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交和最後一次提交之間的差異

git diff 372aa8e425b57ca30e2974b8e7737133caaa0b7f HEAD // 檢視本地倉庫的372aa8e425b57ca30e2974b8e7737133caaa0b7f提交和最後一次提交之間的差異

git diff 372aa8e b5cad94 README.md // 檢視當前目錄下的README.md在本地倉庫的372aa8e提交和b5cad94提交之間的差異

注:可以將git diff換成git difftool來使用外部diff工具(可以在c:/users/<使用者名稱>/.gitconfig檔案配置beyond compare作為預設的difftool和mergetool)來檢視差異

[diff]
    tool = bc3
[difftool]
    prompt = false
[difftool "bc3"]
    cmd = "\"e:/program files (x86)/beyond compare 3/bcomp.exe\" \"$LOCAL\" \"$REMOTE\""複製程式碼

分支合併

git merge-base Master Feature // 檢視Master和Feature分支的最優共同commit父節點

git merge Feature // 將Feature分支merge合併到當前分支Master(無衝突時會直接提交)

git merge -m "merge test" Feature // 將Feature分支merge合併到當前分支Master(無衝突時使用merge test註釋直接提交)

git merge --no-commit Feature // 將Feature分支merge合併到當前分支Master(不自動提交)

git rebase Feature // 將Feature分支rebase合併到當前分支Master

超詳實Git簡明教程與命令大全

注1:git rebase會先找出共同的祖先節點,從祖先節點把Feature分支的提交記錄全都剪下下來,然後合到Master 分支(合併前後commitID會不一樣)

注2:相對來說,git merge處理衝突更直接,但會增加一些冗餘的提交記錄;而git rebase能夠保證清晰線性的提交記錄,但這也將合併的操作沒有被記錄下來

注3:最好是用git rebase合併遠端分支到本地,git merge合併Feature分支到Master分支

注4:在合併Feature分支到Master分支前,務必先執行git pull -r origin Feature來進行遠端分支與本地分支的rebase合併

注5:處於衝突狀態(conflict)的檔案為UU(可通過git status -s --ignored來查詢),手動處理完衝突後,然後使用git add該檔案,最後繼續執行git merge/rebase --continue來完成合並的提交工作

注6:README.md檔案衝突內容如下

<<<<<<< HEAD
123 456 789 000 111 222 333 444 555 ss // 當前分支的內容
=======
123 456 789 000 ss tt // Feature分支的內容
>>>>>>> Feature

注7:可以使用git mergetool來使用外部merge工具(可以在c:/users/<使用者名稱>/.gitconfig檔案配置beyond compare作為預設的mergetool)來處理衝突。

修改完當前檔案後,可再次呼叫git mergetool來處理下一個衝突,直至全部處理完畢,然後使用git add該檔案,最後繼續執行git merge/rebase --continue來完成合並的提交工作

[merge]
    tool = bc3
[mergetool]
    prompt = false
[mergetool "bc3"]
    cmd = "\"e:/program files (x86)/beyond compare 3/bcomp.exe\" \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\""複製程式碼

超詳實Git簡明教程與命令大全

git rebase /i Feature // 將Feature分支採用手動互動方式rebase合併到當前分支Master

pick 07c5abd Introduce OpenPGP and teach basic usage

pick de9b1eb Fix PostChecker::Post#urls
pick 3e7ee36 Hey kids, stop all the highlighting
pick fa20af3 git interactive rebase, squash, amend

# Rebase 8db7e8b..fa20af3 onto 8db7e8b
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

git merge/rebase --abort // 撤銷當前merge或rebase操作

git merge/rebase --skip // 強制使用Feature分支的內容

git merge/rebase --continue // 手動處理完衝突後使用git add該檔案,最後繼續執行git merge/rebase --continue來完成合並的提交工作

git merge origin/master // fetch完之後,可以將遠端分支cache master分支merge合併到當前分支上

git rebase origin/master // fetch完之後,可以將遠端分支cache master分支rebase合併到當前分支上

git rebase --onto master 76cada~ // 將當前分支從[76cada, HEAD]區間段的提交ebase合併到master上

git cherry-pick 9a341e // 將9a341e提交合入當前分支。若不衝突,則直接使用9a341e的提交資訊進行commit,否則要先進行衝突處理,然後繼續執行git cherry-pick --continue來完成合並的提交工作

git cherry-pick 371c2…971209 // 將(371c2, 971209]提交合入當前分支(每個提交都會在當前分支上建立一個commit)

git cherry-pick 371c2~…971209 // 將 [371c2, 971209] 提交合入當前分支(每個提交都會在當前分支上建立一個commit)

git cherry-pick -n 9a341e d2f99e // 將9a341e和d2f99e提交合入當前分支(不提交),後續需要手動commit

git cherry-pick --abort // 撤銷當前cherry-pick操作

git cherry-pick --quit // 清理當前操作狀態,不撤銷修改強制退出cherry-pick操作過程

git cherry-pick --continue // 手動處理完衝突後,最後繼續執行git cherry-pick --continue來完成合並的提交工作

檢視遠端版本庫

git remote -v // 顯示遠端倉庫的URL 注:由於git是分散式的,所有遠端倉庫可能有很多個

origin https://github.com/kekec/Test.git (fetch)
origin https://github.com/kekec/Test.git (push)

git remote-ls // 檢視遠端倉庫URL和分支資訊

From https://github.com/kekec/Test.git
fae0fc82d711425daa897a63137d7e1af09512ba HEAD
fae0fc82d711425daa897a63137d7e1af09512ba refs/heads/master

git remote // 檢視遠端倉庫名稱 一般為origin

git remote rename origin test // 將遠端倉庫名稱從origin修改為test

git remote show origin // 顯示遠端倉庫的資訊

* remote origin
Fetch URL: https://github.com/kekec/Test.git
Push URL: https://github.com/kekec/Test.git
HEAD branch: master
Remote branches:
master tracked
v3.1 tracked
Local branch configured for 'git pull':
master merges with remote master
Local refs configured for 'git push':
master pushes to master (fast-forwardable)
v3.1 pushes to v3.1 (up to date)

git remote rm origin // 刪除.git/config檔案中新增remote origin相關的資訊

git remote add origin https://github.com/kekec/Test.git // 在.git/config檔案中新增remote origin指向的遠端倉庫URL(若已存在,則命令執行失敗)

[remote "origin"]
    url = https://github.com/kekec/Test.git
    fetch = +refs/heads/*:refs/remotes/origin/*複製程式碼

git remote set-url origin https://github.com/kekec/Test.git // 修改.git/config檔案中新增remote origin指向的遠端倉庫URL

git remote prune origin // 對於遠端倉庫不存在的分支,清除對應的遠端分支cache

遠端操作

git clone https://github.com/kekec/Test.git // 將https://github.com/kekec/Test.git上的當前分支克隆到本地(會建立一個名為Test目錄,遠端倉庫名稱使用預設名origin)

git clone https://github.com/kekec/Test.git MyProject // 將https://github.com/kekec/Test.git上的當前分支克隆到本地(會建立一個名為MyProject目錄,遠端倉庫名稱使用預設名origin)

git clone -b v1.0 https://github.com/kekec/Test.git // 將https://github.com/kekec/Test.git上的v1.0分支克隆到本地(會建立一個名為Test目錄,遠端倉庫名稱使用預設名origin)

git clone -b v1.0 https://github.com/kekec/Test.git d:\MyGame // 將https://github.com/kekec/Test.git上的v1.0分支克隆到d:\MyGame目錄(會在d:\MyGame中建立一個名為Test目錄,遠端倉庫名稱使用預設名origin)

git clone -o TestPrj https://github.com/kekec/Test.git // 將https://github.com/kekec/Test.git上的當前分支克隆到本地(會建立一個名為Test目錄,並將遠端倉庫名稱設定為TestPrj)

git fetch origin master // 從遠端倉庫拉取master分支狀態的變化資訊(工作區檔案不會更新)

git fetch // 從遠端倉庫拉取所有分支和tag狀態的變化資訊(工作區檔案不會更新)

git fetch -p // 從遠端倉庫拉取所有分支和tag狀態的變化資訊,並清除已被刪除的遠端分支和tag在本地的快取(工作區檔案不會更新)

git fetch origin --tags // 從遠端倉庫拉取所有tag到本地(工作區檔案不會更新)

git pull <遠端倉庫名> <遠端分支名>:<本地分支名>

git pull origin master // 先執行fetch,然後將遠端origin/master分支merge合併到當前分支(最後會更新origin/master, origin/HEAD指標到最新提交)

git pull https://github.com/kekec/Test.git master // 先執行fetch,將遠端origin/master分支merge合併到當前分支(最後不會更新origin/master, origin/HEAD指標到最新提交)

git pull origin v1.0:master // 先執行fetch,然後將遠端origin/v1.0分支merge合併到本地master分支

git pull origin // 先執行fetch,然後將對應的遠端分支merge合併到當前分支(當前分支需要預存遠端分支的追蹤關係)

git pull // 先執行fetch,然後將對應的遠端分支merge合併到當前分支(當前分支需要預存遠端分支的追蹤關係,而且當前分支只有一個遠端倉庫)

git pull -p // 先執行fetch,然後將對應的遠端分支merge合併到當前分支,並清除已被刪除的遠端分支和tag在本地的快取

git pull -r origin master // 先執行fetch,然後將遠端origin/master分支rebase合併到master分支

git push <遠端倉庫名> <本地分支名>:<遠端分支名>

git push -u origin master // 將本地倉庫的修改push到origin所指向的遠端倉庫URL的master分支上,並在.git/config檔案中記錄當前分支與遠端分支master的對應關係

git push origin // 將當前分支更新推送給對應的遠端分支

git push // 將當前分支更新推送給對應的遠端分支(當前分支只有一個遠端倉庫,可以省略倉庫名origin)

git push origin -f // 使用當前分支更新強行覆蓋對應的遠端分支(合入遠端分支有衝突時,也使用當前分支更新)

git push origin v1.0 // 將本地分支v1.0更新推送給對應的遠端分支remotes/origin/v1.0

git push origin --all // 將本地所有分支更新推送給各自對應的遠端分支

git push origin tag1.0 // 將本地標籤tag1.0更新到遠端標籤tag1.0

git push origin --tags // 將本地所有標籤更新到對應的遠端標籤

git push origin :v1.0 // 刪除遠端分支v1.0

git push origin :refs/tags/tag1.0 // 刪除遠端標籤tag1.0

git push origin -d v1.0 // 刪除遠端分支v1.0 功能同上

儲藏區

git stash // 將工作區中所有檔案的修改備份壓棧到儲藏區,然後丟棄工作區與暫存區的所有檔案的修改

git stash pop // 使用儲藏區的棧頂處備份(stash@{0})來恢復當前分支的工作區,並將棧頂備份移除

git stash apply stash@{1} // 使用儲藏區的棧頂下面一個備份(stash@{1})來恢復當前分支的工作區,但不移除儲藏區中任何備份

git stash list // 檢視儲藏區棧列表

git stash show -p stash@{0} // 檢視儲藏區的棧頂處備份中各個檔案的內容

git stash drop // 直接移除儲藏區的棧頂處備份(不用於恢復當前分支的工作區)

git stash clear // 清除儲藏區棧列表

工作區

git clean -nd // 探測工作區中哪些檔案和目錄(未追蹤狀態)會被刪除

git clean -fd // 刪除工作區中未追蹤狀態的檔案和目錄

暫存區

git ls-files // 查詢暫存區中的檔案列表(遞迴子目錄)

git ls-files -s // 檢視暫存區中所有檔案的blob資料塊資訊

git ls-files -s -- README.md // 檢視暫存區中的README.md檔案的blob資料塊資訊

其他命令

git fsck --full // 列出所有未引用的blob、tree、commit物件

git archive --format zip --output d:/file.zip master // 將當前master分支所有檔案使用zip壓縮方式打包到d:/file.zip

Git瘦身

git count-objects -v // 檢視git物件的統計資訊

find .git/objects -type f -print0 | xargs -0 du -hk | sort -nr | head -5 // 查詢git庫中最大的5個檔案(du -hk中的k代表單位為KB)

find .git/objects -type f -size +1M -print0 | xargs -0 du -hm | sort -nr | head -5 // 查詢git庫中size超過1M的最大的5個檔案(du -hm中的k代表單位為MB)

git verify-pack -v .git/objects/pack/pack-b340eea7566df839294b71ec91a327ca2ece0b94.idx | sort -k 3 -nr | head -5 // 對壓縮儲存的git庫查詢最大的5個檔案

git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch FramePro.cpp' --prune-empty --tag-name-filter cat -- --all // 從git庫的歷史記錄中徹底清理FramePro.cpp

git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin // 清理所有廢棄的ref引用

git gc --prune=now // ①將所有的物件壓縮儲存到pack二進位制檔案中,以節省空間和提高效率 ②移除與任何提交都不相關的陳舊物件

git reflog expire --expire=now --all // 清除所有操作記錄日誌

除了使用git原生命令外,可以使用專門的工具BFG(java實現)來對Git庫瘦身

經典Gitflow

超詳實Git簡明教程與命令大全

(1) master分支儲存了正式釋出的歷史(master分支上的所有提交都會分配一個版本號)

(2) develop分支作為功能的整合分支

(3) 每個新功能位於一個自己的Feature分支,該分支使用develop分支作為父分支。當新功能完成時,合併回develop分支。新功能提交應該從不直接與master分支互動

(4) 一旦develop分支上有了做一次釋出(或者說快到了既定的釋出日)的足夠功能,就從develop分支上fork一個release分支。

新建的分支用於開始釋出迴圈,所以從這個時間點開始之後新的功能不能再加到這個分支上。 這個分支只應該做Bug修復、文件生成和其它面向釋出任務。

對外發布的工作完成後,釋出分支會合併到master分支並分配一個版本號打好Tag。另外,這些從新建釋出分支以來的做的修改要合併回develop分支。

(5) hotfix分支用於生成快速給產品釋出版本(production releases)打補丁,修復完成,修改應該馬上合併回master分支(打好Tag)和develop分支(當前的釋出分支)。

參考

Pro Git第二版pdf

Git原理入門

常用 Git 命令清單

Git遠端操作詳解

Git 工作流程

Git 使用規範流程

Git分支管理策略

GIT基本概念和用法總結

Git工作流指南:Gitflow工作流


《IVWEB 技術週刊》 震撼上線了,關注公眾號:IVWEB社群,每週定時推送優質文章。

週刊文章集合: weekly

團隊開源專案: Feflow


相關文章