Git (wiki: en chs )是一個免費開源的分佈式版本控制系統,由linux內核做者linus Torvalds開發,大型開源項目linux kernel、Android、chromium、mono、dotnet、UE4等都使用Git管理項目html
著名github網站使用Git託管全部項目代碼,Git的代碼也託管在github上,連接爲:github.com/gitjava
與集中式版本控制系統(開源軟件:SVN;免費軟件:CVS;商業軟件:微軟的VSS、IBM的Rational ClearCase)相比linux
Git優勢:android
① 本地是版本庫的完整鏡像,所以支持離線工做git
② 絕大多數操做都只須要訪問本地文件和資源,並且與每一個提交都是全部文件的完整副本,所以速度很是快github
注:SVN等集中式版本控制系統存儲每一個文件與初始化版本的差別web
注:Git每一個提交都是全部文件的完整副本,使得Git在回溯到某個提交時,不會對全部文件執行差別計算還原,所以速度會很是快shell
③ 強大快捷的分支功能,很是適合非線性開發過程數據庫
Git缺點:vim
① 只能全量總體,而不能以子目錄和分支爲單位進行更新、提交等操做
② 子目錄和分支不能單獨進行權限控制
③ 因爲每一個提交都是全部文件的完整副本,所以更佔磁盤空間
這使得源代碼、配置文件等更適合用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 checkout -- <file>①②步驟的含義是當在暫存區中有修改時,優先使用暫存區中的修改覆蓋工做區
svn命令對比一覽
svn | git | 說明 |
svn checkout | git clone | 檢出項目 |
svn update | git fetch git pull |
更新 |
svn commit | git commit git push |
提交 |
svn add | git add | 添加 |
svn mv | git mv | 移動 |
svn rm | git rm | 刪除 |
svn status | git status | 查看狀態 |
svn log | git log | 查看log |
svn diff | git diff | 查看差別 |
svn revert | git checkout git reset git revert |
撤銷、丟棄修改 |
svn copy | git checkout -b/-B git branch |
建立分支 |
svn switch | git checkout | 切換分支 |
svn copy | git 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對象
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 // 使用類型爲10064四、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目錄結構以下:
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
注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 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
(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分支(當前的發佈分支)。
參考
《IVWEB 技術週刊》 震撼上線了,關注公衆號:IVWEB社區,每週定時推送優質文章。
週刊文章集合: weekly
團隊開源項目: Feflow