Git原理與命令大全


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

著名github網站使用Git托管所有項目代碼,Git的代碼也托管在github上,鏈接為:https://github.com/git

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

Git優點

① 本地是版本庫的完整鏡像,因此支持離線工作

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

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

注: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 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 kekec <kekec@qq.com> 1537258258 +0800
committer kekec <kekec@qq.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 config --global credential.helper wincred  // windows下刪除git憑據,后面執行git命令會彈框要求輸入用戶名和密碼

 

當沒有憑據時,會彈框要求輸入用戶名和密碼

當密碼有變化,可以在windows控制面板的憑據管理器中,找到對應的憑據進行修改:

 

git config --global credential.helper osxkeychain  // mac osx下刪除git憑據,后面執行git命令會彈框要求輸入用戶名和密碼

 

創建版本庫

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)  注:可通過git rev-parse HEAD命令打印當前HEAD的commit id

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 --hard 4.24.3-release // 僅將當前分支的HEAD指向tag為4.24.3-release的位置(丟棄暫存區和工作區中的所有文件的修改,工作區中未追蹤的文件不受影響)

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://username:password@github.com/kekec/Test.git  // 使用賬號為username密碼為password將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 --set-upstream origin v1.0  // 將本地分支v1.0更新推送給對應的遠端分支remotes/origin/v1.0,並將建立與遠程分支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分支(當前的發布分支)。

 

參考

Pro Git第二版pdf

Git原理入門

常用 Git 命令清單

Git遠程操作詳解

Git 工作流程

Git 使用規范流程

Git分支管理策略

GIT基本概念和用法總結

Git工作流指南:Gitflow工作流

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM