git學(xué)習(xí)總結(jié)
GIT命令
設(shè)置與配置
$ git help // 命令用來顯示任何命令的 Git 自帶文檔。
$ git config // 配置郵箱用戶名焕刮,別名,默認(rèn)項(xiàng)等
獲取與創(chuàng)建項(xiàng)目
$ git init // 初始化新git項(xiàng)目
$ git clone
/*
1模捂、它創(chuàng)建了一個(gè)新目錄班缰,切換到新的目錄贤壁。
2、git init 來初始化一個(gè)空的 Git 倉庫
3埠忘、為你指定的 URL 添加一個(gè)(默認(rèn)名稱為 origin 的)遠(yuǎn)程倉庫(git remote add)
4脾拆、針對遠(yuǎn)程倉庫執(zhí)行 git fetch
5、通過 git checkout 將遠(yuǎn)程倉庫的最新提交檢出到本地的工作目錄莹妒。
*/
快照基礎(chǔ)
$ git add // 將內(nèi)容從工作目錄添加到暫存區(qū)(或稱為索引(index)區(qū))名船,以備下次提交。 當(dāng) git commit 命令執(zhí)行時(shí)动羽,默認(rèn)情況下它只會(huì)檢查暫存區(qū)域包帚,因此 git add 是用來確定下一次提交時(shí)快照的樣子的渔期。
$ git status // 顯示工作區(qū)及暫存區(qū)域中不同狀態(tài)的文件运吓。 其中包含了已修改但未暫存,或已經(jīng)暫存但沒有提交的文件疯趟。
$ git diff // 查看你工作環(huán)境與你的暫存區(qū)的差異(git diff 默認(rèn)的做法)
$ git diff --staged // 你暫存區(qū)域與你最后提交之間的差異
$ git diff master branchB // 或者比較兩個(gè)提交記錄的差異
$ git commit // 將所有通過 git add 暫存的文件內(nèi)容在數(shù)據(jù)庫中創(chuàng)建一個(gè)持久的快照拘哨,然后將當(dāng)前分支上的分支指針移到其之上。
$ git reset // 用來根據(jù)你傳遞給動(dòng)作的參數(shù)來執(zhí)行撤銷操作信峻。 它可以移動(dòng) HEAD 指針并且可選的改變 index 或者暫存區(qū)倦青,如果你使用 --hard 參數(shù)的話你甚至可以改變工作區(qū)。
$ git rm // Git 用來從工作區(qū)盹舞,或者暫存區(qū)移除文件的命令产镐。 在為下一次提交暫存一個(gè)移除操作上,與 git add 相反踢步。
$ git mv // 移到一個(gè)文件并且在新文件上執(zhí)行`git add`命令及在老文件上執(zhí)行`git rm`命令癣亚。
$ git clean // 從工作區(qū)中移除不想要的文件的命令
分支與合并
$ git branch // 分支管理工具: 它可以列出你所有的分支、創(chuàng)建新分支获印、刪除分支及重命名分支述雾。
$ git checkout // 命令用來切換分支,或者檢出內(nèi)容到工作目錄兼丰。
$ git merge // 合并一個(gè)或者多個(gè)分支到你已經(jīng)檢出的分支中玻孟。 然后它將當(dāng)前分支指針移動(dòng)到合并結(jié)果上。
$ git log // 展示一個(gè)項(xiàng)目的可達(dá)歷史記錄鳍征,從最近的提交快照起黍翎。 默認(rèn)情況下,它只顯示你當(dāng)前所在分支的歷史記錄艳丛,但是可以顯示不同的甚至多個(gè)頭記錄或分支以供遍歷玩敏。 此命令通常也用來在提交記錄級別顯示兩個(gè)或多個(gè)分支之間的差異斗忌。
$ git stash // 臨時(shí)地保存一些還沒有提交的工作,以便在分支上不需要提交未完成工作就可以清理工作目錄旺聚。
$ git tag // 用來為代碼歷史記錄中的某一個(gè)點(diǎn)指定一個(gè)永久的書簽织阳。 一般來說它用于發(fā)布相關(guān)事項(xiàng)。
項(xiàng)目分享與更新
$ git fetch // 命令與一個(gè)遠(yuǎn)程的倉庫交互砰粹,并且將遠(yuǎn)程倉庫中有但是在當(dāng)前倉庫的沒有的所有信息拉取下來然后存儲在你本地?cái)?shù)據(jù)庫中.
$ git pull // 命令基本上就是 git fetch 和 git merge 命令的組合體唧躲,Git 從你指定的遠(yuǎn)程倉庫中抓取內(nèi)容,然后馬上嘗試將其合并進(jìn)你所在的分支中碱璃。
$ git push // 命令用來與另一個(gè)倉庫通信弄痹,計(jì)算你本地?cái)?shù)據(jù)庫與遠(yuǎn)程倉庫的差異,然后將差異推送到另一個(gè)倉庫中嵌器。 它需要有另一個(gè)倉庫的寫權(quán)限肛真,因此這通常是需要驗(yàn)證的。
$ git remote // 你遠(yuǎn)程倉庫的管理工具,可以列舉爽航、添加蚓让、移除、重命名功能等
補(bǔ)丁
$ git cherry-pick // 命令用來獲得在單個(gè)提交中引入的變更讥珍,然后嘗試將作為一個(gè)新的提交引入到你當(dāng)前分支上历极。
$ git rebase // 命令基本是是一個(gè)自動(dòng)化的 cherry-pick 命令。 它計(jì)算出一系列的提交衷佃,然后再以它們在其他地方以同樣的順序一個(gè)一個(gè)的 cherry-picks 出它們趟卸。
管理
$ git gc // 執(zhí)行 “garbage collection”,刪除數(shù)據(jù)庫中不需要的文件和將其他文件打包成一種更有效的格式氏义。
$ git fsck // 命令用來檢查內(nèi)部數(shù)據(jù)庫的問題或者不一致性锄列。
$ git reflog // 命令分析你所有分支的頭指針的日志來查找出你在重寫歷史上可能丟失的提交。
GIT基礎(chǔ)
git項(xiàng)目中各文件的各個(gè)狀態(tài)及其關(guān)系
檢查當(dāng)前狀態(tài): git status
$ git status
/*
On branch master
Your branch is up-to-date with 'origin/master'.
nothing to commit, working directory clean
*/
跟蹤新文件:git add
, 后面可以跟文件名或者文件夾名惯悠,添加文件或者文件夾所有文件邻邮。
提交文件:git commit
, 接-m參數(shù)傳遞 commit 信息吮螺,提交代碼生成一個(gè)SHA-1值
add饶囚, commit命令合并:
git commit -a -m 'added new benchmarks'
更新遠(yuǎn)程代碼:
git fetch
命令從服務(wù)器上抓取本地沒有的數(shù)據(jù)時(shí),它并不會(huì)修改工作目錄中的內(nèi)容鸠补,需要自己合并萝风。
git pull
= git fetch
+ git merge
推送代碼:git push
忽略文件:.gitignore
,規(guī)則如下:
所有空行或者以
#
開頭的行都會(huì)被 Git 忽略紫岩。可以使用標(biāo)準(zhǔn)的 glob 模式(shell 所使用的簡化了的正則表達(dá)式)匹配规惰,它會(huì)遞歸地應(yīng)用在整個(gè)工作區(qū)中。
匹配模式可以以(
/
)開頭防止遞歸泉蝌。匹配模式可以以(
/
)結(jié)尾指定目錄歇万。要忽略指定模式以外的文件或目錄揩晴,可以在模式前加上嘆號(
!
)取反。
查看提交歷史:git log
按時(shí)間先后順序列出所有的提交贪磺,最近的更新排在最上面硫兰。
參數(shù):
1、-p
或 --patch
:它會(huì)顯示每次提交所引入的差異(按 補(bǔ)丁 的格式輸出)寒锚。 你也可以限制顯示的日志條目數(shù)量劫映,例如使用 -2
選項(xiàng)來只顯示最近的兩次提交。
2刹前、--stat
:每次提交的簡略統(tǒng)計(jì)信息
3泳赋、--pretty
:使用不同于默認(rèn)格式的方式展示提交歷史,例如
$ git log --pretty=oneline
喇喉,將所有信息一行顯示祖今,另外默認(rèn)的參數(shù)還有short
,full
和 fuller
git log --pretty=format:"%h - %an, %ar : %s"
:定制記錄的顯示格式
format
接受的常用格式占位符的寫法及其代表的意義拣技。
無法復(fù)制加載中的內(nèi)容
$ git commit --amend
重新提交
這個(gè)命令會(huì)將暫存區(qū)中的文件提交千诬。 如果自上次提交以來你還未做任何修改(例如,在上次提交后馬上執(zhí)行了此命令)过咬, 那么快照會(huì)保持不變大渤,而你所修改的只是提交信息制妄。例如:
$ git commit -m 'initial commit' // 此時(shí)發(fā)現(xiàn)有遺漏的修改
$ git add forgotten_file
$ git commit --amend
最終你只會(huì)有一個(gè)提交——第二次提交將代替第一次提交的結(jié)果掸绞。用一個(gè) 新的提交 替換舊的提交,從效果上來說耕捞,就像是舊有的提交從未存在過一樣衔掸,它并不會(huì)出現(xiàn)在倉庫的歷史中。
撤銷操作
1俺抽、git checkout -- <file>
個(gè)文件在本地的任何修改都會(huì)消失——Git 會(huì)用最近提交的版本覆蓋掉它敞映。
標(biāo)簽管理:
1、 git tag
:查看標(biāo)簽 (可帶上可選的 -l
選項(xiàng) --list
)
2磷斧、git tag -a <tagname> -m <info>
$ git tag -a v1.0 -m "my version 1.0"
// -m 選項(xiàng)指定了一條將會(huì)存儲在標(biāo)簽中的信息振愿。
// 如果沒有為附注標(biāo)簽指定一條信息,Git 會(huì)啟動(dòng)編輯器要求你輸入信息弛饭。
$ git show v1.0
/*
tag v1.0
Tagger: ***
Date: ***
my version 1.0
commit ....
*/
// 輸出顯示了打標(biāo)簽者的信息冕末、打標(biāo)簽的日期時(shí)間、附注信息侣颂,然后顯示具體的提交信息档桃。
3虽画、$ git tag -a <tagname>``<SHA-1>
: 對指定Commit ID 打tag
注意:
默認(rèn)情況下撒犀,git push
命令并不會(huì)傳送標(biāo)簽到遠(yuǎn)程倉庫服務(wù)器上创千。 在創(chuàng)建完標(biāo)簽后你必須顯式地推送標(biāo)簽到共享服務(wù)器上间学。 這個(gè)過程就像共享遠(yuǎn)程分支一樣——你可以運(yùn)行 git push origin <tagname>
。
4嘹屯、git tag -d <tagname>
:刪除標(biāo)簽(并不會(huì)從任何遠(yuǎn)程倉庫中移除這個(gè)標(biāo)簽)
git push <remote> --delete <tagname>
刪除遠(yuǎn)程分支攻询,或者:
git push <remote> :refs/tags/<tagname>
5、git checkout <tagname>
:檢出該標(biāo)簽下文件.
注意:如果你做了某些更改然后提交它們州弟,標(biāo)簽不會(huì)發(fā)生變化蜕窿, 你的新提交將不屬于任何分支,并且將無法訪問呆馁,除非通過確切的提交哈希才能訪問桐经。 因此,如果你需要進(jìn)行更改浙滤,比如你要修復(fù)舊版本中的錯(cuò)誤阴挣,那么通常需要?jiǎng)?chuàng)建一個(gè)新分支:
git checkout -b version2 <tagname>
別名:
$ git config --global alias.co checkout // git checkout == git co
$ git config --global alias.br branch
$ git config --global alias.ci commit
$ git config --global alias.st status
GIT分支
遠(yuǎn)程倉庫
git remote
查看你已經(jīng)配置的遠(yuǎn)程倉庫服務(wù)器,指定選項(xiàng) -v
纺腊,會(huì)顯示需要讀寫遠(yuǎn)程倉庫使用的 Git 保存的簡寫與其對應(yīng)的 URL畔咧。
$ git remote -v
/*
origin https://github.com/schacon/ticgit (fetch)
origin https://github.com/schacon/ticgit (push)
*/
git remote add <shortname> <url>
: 添加遠(yuǎn)程倉庫
git fetch <remote>
: 從指定源拉取數(shù)據(jù)(只會(huì)將數(shù)據(jù)下載到你的本地倉庫——它并不會(huì)自動(dòng)合并或修改你當(dāng)前的工作)
git push <remote> <branch>
:推送到遠(yuǎn)程分支。例如:
$ git push origin master
/*
只有當(dāng)你有所克隆服務(wù)器的寫入權(quán)限揖膜,并且之前沒有人推送過時(shí)誓沸,這條命令才能生效。
當(dāng)你和其他人在同一時(shí)間克隆壹粟,他們先推送到上游然后你再推送到上游拜隧,你的推送就會(huì)毫無疑問地被拒絕。
你必須先抓取他們的工作并將其合并進(jìn)你的工作后才能推送趁仙。
*/
git remote rename
: 重命名遠(yuǎn)程分支
git remote remove <shortname>
: 移除遠(yuǎn)程倉庫
1洪添、git branch <branchname>
:創(chuàng)建分支(一個(gè)可以移動(dòng)的新的指針),例如創(chuàng)建一個(gè) testing 分支:
$ git branch testing
注意:HEAD指針指向當(dāng)前所在的分支(可以將 HEAD
想象為當(dāng)前分支的別名)雀费,使用git checkout
可以切換當(dāng)前分支干奢,例如:
git checkout testing
git 指針狀態(tài)
當(dāng)我們修改testing分支上的內(nèi)容,并且commit時(shí)盏袄,此時(shí)指針狀態(tài)如下
此時(shí)忿峻,如果我們checkout master,
git將完成兩部分工作: 一是使 HEAD 指回 master
分支辕羽,二是將工作目錄恢復(fù)成 master
分支所指向的快照內(nèi)容逛尚。
繼續(xù)向master提交修改
此時(shí)將產(chǎn)生分叉,可通過git log --oneline --decorate --graph --all
Git 的分支實(shí)質(zhì)上僅是包含所指對象校驗(yàn)和(長度為 40 的 SHA-1 值字符串)的文件逛漫,所以它的創(chuàng)建和銷毀都異常高效黑低。 創(chuàng)建一個(gè)新分支就相當(dāng)于往一個(gè)文件中寫入 41 個(gè)字節(jié)(40 個(gè)字符和 1 個(gè)換行符)。
經(jīng)典??:
實(shí)際工作中你可能會(huì)用到類似的工作流。 你將經(jīng)歷如下步驟:
- 開發(fā)某個(gè)網(wǎng)站克握。
- 為實(shí)現(xiàn)某個(gè)新的用戶需求蕾管,創(chuàng)建一個(gè)分支。
- 在這個(gè)分支上開展工作菩暗。
正在此時(shí)掰曾,你突然接到一個(gè)電話說有個(gè)很嚴(yán)重的問題需要緊急修補(bǔ)。 你將按照如下方式來處理:
- 切換到你的線上分支(production branch)停团。
- 為這個(gè)緊急任務(wù)新建一個(gè)分支旷坦,并在其中修復(fù)它。
- 在測試通過之后佑稠,切換回線上分支秒梅,然后合并這個(gè)修補(bǔ)分支,最后將改動(dòng)推送到線上分支舌胶。
- 切換回你最初工作的分支上捆蜀,繼續(xù)工作。
// master
$ git checkout -b iss53 // iss53
$ git add . // iss53
$ git commit -m '**' // iss53
$ git checkout master // master
$ git checkout -b hotfix // hotfix
$ git add . // hotfix
$ git commit -m '**' // hotfix
// 測試驗(yàn)證沒問題以后
$ git checkout master // master
$ git merge hotfix // master
// 合并以后就可以刪除該分支了(最好不用動(dòng)被人的分支辆它,除非是自己新建的)
$ git branch -d hotfix // master
$ git checkout i3353 // iss53分支繼續(xù)開發(fā)并提交了C5
此時(shí) 如果你把iss53分支合并到master:這和你之前合并 hotfix
分支的時(shí)候看起來有一點(diǎn)不一樣切心。master
分支所在提交并不是 iss53
分支所在提交的直接祖先啼县,Git 不得不做一些額外的工作。 出現(xiàn)這種情況的時(shí)候挺峡,Git 會(huì)使用兩個(gè)分支的末端所指的快照(C4
和 C5
)以及這兩個(gè)分支的公共祖先(C2
)葵孤,做一個(gè)簡單的三方合并,并產(chǎn)生一個(gè)新的commit橱赠。
綜上:當(dāng)我們需要commit新代碼時(shí)尤仍,最好是先stash本地代碼,然后同步遠(yuǎn)程的代碼狭姨,使本地的最新commit跟遠(yuǎn)程的最新commit ID一致宰啦,我們再繼續(xù)commit,此時(shí)我們推送代碼時(shí)饼拍,就會(huì)HEAD指針直接Fast-forward,不會(huì)產(chǎn)生新的merge commit
git stash
或 git stash push
:存儲改動(dòng)
git stash list
: 查看存儲列表
git stash list
/*
stash@{0}: On wallet-page: 1018-unit-test
stash@{1}: On wallet-page: 1013
*/
git stash apply
:彈出存儲
git stash apply // 默認(rèn)彈出最新的存儲
git stash apply stash@{1} // 彈出指定存儲
分支跟蹤:從一個(gè)遠(yuǎn)程跟蹤分支檢出一個(gè)本地分支會(huì)自動(dòng)創(chuàng)建所謂的“跟蹤分支”赡模,如果在一個(gè)跟蹤分支上輸入 git pull
,Git 能自動(dòng)地識別去哪個(gè)服務(wù)器上抓取师抄、合并到哪個(gè)分支纺裁。
git checkout -b <branch> <remote>/<branch>
git checkout --track origin/serverfix
由于這個(gè)操作太常見了,該捷徑本身還有一個(gè)捷徑司澎。 如果你嘗試檢出的分支 (a) 不存在且 (b) 剛好只有一個(gè)名字與之匹配的遠(yuǎn)程分支欺缘,那么 Git 就會(huì)為你創(chuàng)建一個(gè)跟蹤分支,例如:
$ git checkout serverfix
/*
Branch serverfix set up to track remote branch serverfix from origin.
Switched to a new branch 'serverfix'
*/
設(shè)置一個(gè)已有的本地分支與遠(yuǎn)程分支關(guān)聯(lián):使用 -u
或 --set-upstream-to
選項(xiàng)運(yùn)行 git branch
來顯式地設(shè)置挤安,例如:git branch -u origin/serverfix
刪除遠(yuǎn)程分支:可以運(yùn)行帶有 --delete
選項(xiàng)的 git push
命令來刪除一個(gè)遠(yuǎn)程分支谚殊。 例如刪除遠(yuǎn)程serverfix
分支:
git push origin --delete serverfix
變基
再來看下merge的時(shí)候分支的情況
此時(shí)會(huì)多一個(gè)merge的commit C5,往往會(huì)使人疑惑,接下來介紹一個(gè)方法使之不產(chǎn)生額外的分支來合并代碼蛤铜,變基(rebase):提取在 **C4**
中引入的補(bǔ)丁和修改嫩絮,然后在 **C3**
的基礎(chǔ)上應(yīng)用一次。
下面將展示如何操作:
$ git checkout experiment
$ git rebase master
它的原理是首先找到這兩個(gè)分支(即當(dāng)前分支 experiment
围肥、變基操作的目標(biāo)基底分支 master
) 的最近共同祖先 C2
剿干,然后對比當(dāng)前分支相對于該祖先的歷次提交,提取相應(yīng)的修改并存為臨時(shí)文件穆刻, 然后將當(dāng)前分支指向目標(biāo)基底 C3
, 最后以此將之前另存為臨時(shí)文件的修改依序應(yīng)用置尔。
注意,此時(shí)只是提交了rebase
氢伟,還需回到master進(jìn)行合并
$ git checkout master
$ git merge experiment
到此為止榜轿,rebase工作才算完成。
請注意朵锣,rebase
和 merge
整合的最終結(jié)果所指向的快照始終是一樣的谬盐,只不過提交歷史不同罷了。 變基是將一系列提交按照原有次序依次應(yīng)用到另一分支上诚些,而合并是把最終結(jié)果合在一起飞傀。
GIT原理
底層命令和上層命令:
由于 Git 最初是一套面向版本控制系統(tǒng)的工具集,而不是一個(gè)完整的、用戶友好的版本控制系統(tǒng)砸烦, 所以它還包含了一部分用于完成底層工作的子命令犀被。 這些命令被設(shè)計(jì)成能以 UNIX 命令行的風(fēng)格連接在一起,抑或由腳本調(diào)用外冀,來完成工作寡键。 這部分命令一般被稱作“底層(plumbing)”命令,而那些更友好的命令則被稱作“上層(porcelain)”命令雪隧。
git項(xiàng)目目錄介紹
config // 項(xiàng)目特有的配置選項(xiàng)
description // GitWeb
HEAD // 目前被檢出的分支
hooks/ // 戶端或服務(wù)端的鉤子腳本(
info/ // 全局性排除(global exclude)文件
objects/ // 存儲所有數(shù)據(jù)內(nèi)容
refs/ // 存儲指向數(shù)據(jù)(分支西轩、遠(yuǎn)程倉庫和標(biāo)簽等)的提交對象的指針
index/ // 文件保存暫存區(qū)信息
GIT 存儲
Git 是一個(gè)內(nèi)容尋址文件系統(tǒng),核心部分是一個(gè)簡單的鍵值對數(shù)據(jù)庫(key-value data store)。這意味著在Git 倉庫中插入任意類型的內(nèi)容脑沿,它會(huì)返回一個(gè)唯一的鍵(40 個(gè)字符,前兩個(gè)字符用于命名子目錄藕畔,余下的 38 個(gè)字符則用作文件名),通過該鍵可以在任意時(shí)刻再次取回該內(nèi)容庄拇。
git數(shù)據(jù)對象
$ git init test
$ cd test
$ find .git/objects
// 寫入內(nèi)容
$ echo 'test content' | git hash-object -w --stdin // d670460b4b4aece5915caf5c68d12f560a9fe3e4
/*
git hash-object 會(huì)接受你傳給它的東西注服,而它只會(huì)返回可以存儲在 Git 倉庫中的唯一鍵。
-w 選項(xiàng)會(huì)指示該命令不要只返回鍵措近,還要將該對象寫入數(shù)據(jù)庫中溶弟。
--stdin 選項(xiàng)則指示該命令從標(biāo)準(zhǔn)輸入讀取內(nèi)容;
若不指定此選項(xiàng)瞭郑,則須在命令尾部給出待存儲文件的路徑辜御。
*/
$ find .git/objects -type f // .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
$ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 // test content
// -p 指示該命令自動(dòng)判斷內(nèi)容的類型
$ echo 'version 1' > test.txt
$ git hash-object -w test.txt // 83baae61804e65cc73a7201a7252750c76066a30
$ echo 'version 2' > test.txt
$ git hash-object -w test.txt // 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a
$ find .git/objects -type f
/*
.git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a
.git/objects/83/baae61804e65cc73a7201a7252750c76066a30
.git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4
*/
// 查看對象類型
$ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a // blob
git樹對象
樹對象解決了文件名保存的問題,也允許我們將多個(gè)文件組織到一起屈张。 所有內(nèi)容均以樹對象和數(shù)據(jù)對象的形式存儲擒权。 一個(gè)樹對象包含了一條或多條樹對象記錄(tree entry),每條記錄含有一個(gè)指向數(shù)據(jù)對象或者子樹對象的 SHA-1 指針阁谆,以及相應(yīng)的模式碳抄、類型、文件名信息
$ git cat-file -p master^{tree}
/*
100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README
100644 blob 8f94139338f9404f26296befa88755fc2598c289 Rakefile
040000 tree 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 lib
*/
$ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0
//100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb
創(chuàng)建樹對象场绿,例如
// 1.寫入暫存區(qū)
$ git update-index --add --cacheinfo 100644 \
83baae61804e65cc73a7201a7252750c76066a30 test.txt
// -- add:不在緩存區(qū)內(nèi)的(首次)文件添加
// --cacheinfo 添加的文件位于 Git 數(shù)據(jù)庫中, 位于當(dāng)前目錄下
// 100644 表示普通文件剖效,【指定文件模式】100755表示一個(gè)可執(zhí)行文件;120000裳凸,表示一個(gè)符號鏈接(參考了常見的 UNIX 文件模式)
// 83baae61804e65cc73a7201a7252750c76066a30 SHA-1
// test.txt 文件名
// 2.創(chuàng)建樹對象
$ git write-tree // 將暫存區(qū)內(nèi)容寫入一個(gè)樹對象贱鄙。返回d8329fc1cc938780ffdd9f94e0d364e0ea74f579
$ git cat-file -p d8329fc1cc938780ffdd9f94e0d364e0ea74f579
// 100644 blob 83baae61804e65cc73a7201a7252750c76066a30 test.txt
$ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579 // tree
提交對象:記錄保存的快照信息。
commit-tree
創(chuàng)建提交對象姨谷,例如:
$ echo 'first commit' | git commit-tree d8329f // fdf4fc3344e67ab068f836878b6c4951e3b15f3d
// 查看提交對象
$ git cat-file -p fdf4fc3
/*
tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579
author ***
committer ***
first commit
*/
GIT引用
如果你對倉庫中從一個(gè)提交(比如 1a410e
)開始往前的歷史感興趣,那么可以運(yùn)行 git log 1a410e
這樣的命令來顯示歷史映九,不過你需要記得 1a410e
是你查看歷史的起點(diǎn)提交梦湘。 如果我們有一個(gè)文件來保存 SHA-1 值,而該文件有一個(gè)簡單的名字, 然后用這個(gè)名字指針來替代原始的 SHA-1 值的話會(huì)更加簡單捌议。
在 Git 中哼拔,這種簡單的名字被稱為“引用(references,或簡寫為 refs)”瓣颅。 你可以在 .git/refs
目錄下找到這類含有 SHA-1 值的文件倦逐。
一個(gè)用來保存SHA-A記錄的文件夾。
$ find .git/refs
/*
.git/refs
.git/refs/heads
.git/refs/tags
*/
// 創(chuàng)建一個(gè)新引用來幫助記憶最新提交所在的位置宫补,
$ echo 1a410efbd13591db07496601ebc7a059dd55cfe9 > .git/refs/heads/master
// 此時(shí)檬姥,你就可以在 Git 命令中使用這個(gè)剛創(chuàng)建的新引用來代替 SHA-1 值了:
$ git log --pretty=oneline master
/*
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
*/
// 更新某個(gè)引用
$ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9
HEAD 引用
當(dāng)你執(zhí)行 git branch <branch>
時(shí)粉怕,Git 如何知道最新提交的 SHA-1 值呢? 答案是 HEAD 文件贫贝。
HEAD 文件通常是一個(gè)符號引用(symbolic reference)(指向其他引用的指針),指向目前所在的分支崇堵。
$ cat .git/HEAD // ref: refs/heads/master
當(dāng)我們執(zhí)行 git commit
時(shí),該命令會(huì)創(chuàng)建一個(gè)提交對象筑辨,并用 HEAD 文件中那個(gè)引用所指向的 SHA-1 值設(shè)置其父提交字段幸逆。
維護(hù)與數(shù)據(jù)恢復(fù)
維護(hù)
Git 會(huì)不定時(shí)地自動(dòng)運(yùn)行一個(gè)叫做 “auto gc” 的命令。 大多數(shù)時(shí)候楚昭,這個(gè)命令并不會(huì)產(chǎn)生效果。 然而抚太,如果有太多松散對象(不在包文件中的對象)或者太多包文件,Git 會(huì)運(yùn)行一個(gè)完整的 git gc
命令昔案。 “gc” 代表垃圾回收尿贫,這個(gè)命令會(huì)做以下事情:收集所有松散對象并將它們放置到包文件中, 將多個(gè)包文件合并為一個(gè)大的包文件踏揣,移除與任何提交都不相關(guān)的陳舊對象庆亡。
或者手動(dòng)回收:git gc --auto
該命令通常并不會(huì)產(chǎn)生效果。 大約需要 7000 個(gè)以上的松散對象或超過 50 個(gè)的包文件才能讓 Git 啟動(dòng)一次真正的 gc 命令捞稿。
gc
將會(huì)做的另一件事是打包你的引用到一個(gè)單獨(dú)的文件又谋。 假設(shè)你的倉庫包含以下分支與標(biāo)簽:
$ find .git/refs -type f
.git/refs/heads/experiment
.git/refs/heads/master
.git/refs/tags/v1.0
.git/refs/tags/v1.1
如果你執(zhí)行了 git gc
命令拼缝,refs
目錄中將不會(huì)再有這些文件。 為了保證效率 Git 會(huì)將它們移動(dòng)到名為 .git/packed-refs
的文件中彰亥,就像這樣:
$ cat .git/packed-refs
# pack-refs with: peeled fully-peeled
cac0cab538b970a37ea1e769cbbde608743bc96d refs/heads/experiment
ab1afef80fac8e34258ff41fc1b867c702daa24b refs/heads/master
cac0cab538b970a37ea1e769cbbde608743bc96d refs/tags/v1.0
9585191f37f7b0fb9444f35a9bf50de191beadc2 refs/tags/v1.1
^1a410efbd13591db07496601ebc7a059dd55cfe9
如果你更新了引用咧七,Git 并不會(huì)修改這個(gè)文件,而是向 refs/heads
創(chuàng)建一個(gè)新的文件任斋。 為了獲得指定引用的正確 SHA-1 值继阻,Git 會(huì)首先在 refs
目錄中查找指定的引用,然后再到 packed-refs
文件中查找废酷。 所以瘟檩,如果你在 refs
目錄中找不到一個(gè)引用,那么它或許在 packed-refs
文件中锦积。
注意這個(gè)文件的最后一行芒帕,它會(huì)以 ^
開頭。 這個(gè)符號表示它上一行的標(biāo)簽是附注標(biāo)簽丰介,^
所在的那一行是附注標(biāo)簽指向的那個(gè)提交背蟆。
數(shù)據(jù)恢復(fù)
舉個(gè)例子將硬重置你的測試倉庫中的 master
分支到一個(gè)舊的提交,以此來恢復(fù)丟失的提交哮幢。
$ git log --pretty=oneline
/*
ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit
484a59275031909e19aadb7c92262719cfcdf19a added repo.rb
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
*/
現(xiàn)在带膀,我們將 master
分支硬重置到第三次提交:
$ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9
/*
HEAD is now at 1a410ef third commit
$ git log --pretty=oneline
1a410efbd13591db07496601ebc7a059dd55cfe9 third commit
cac0cab538b970a37ea1e769cbbde608743bc96d second commit
fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit
*/
現(xiàn)在 怎么處理橙垢?
1嗽元、最常用的方法:git reflog
當(dāng)你正在工作時(shí)剂癌,Git 會(huì)默默地記錄每一次你改變 HEAD 時(shí)它的值佩谷。 每一次你提交或改變分支谐檀,引用日志都會(huì)被更新桐猬。 引用日志(reflog)也可以通過 git update-ref
命令更新课幕,我們在 Git 引用 有提到使用這個(gè)命令而不是是直接將 SHA-1 的值寫入引用文件中的原因乍惊。 你可以在任何時(shí)候通過執(zhí)行 git reflog
命令來了解你曾經(jīng)做過什么:
$ git reflog
1a410ef HEAD@{0}: reset: moving to 1a410ef
ab1afef HEAD@{1}: commit: modified repo.rb a bit
484a592 HEAD@{2}: commit: added repo.rb
找到丟失的那個(gè)id润绎,然后從該id新建一個(gè)分支:
git branch recover-branch ab1afef
2、當(dāng)丟失的分支在reflog日志里也找不到時(shí)惶傻,使用 git fsck
實(shí)用工具涂佃,將會(huì)檢查數(shù)據(jù)庫的完整性辜荠。如果使用一個(gè) --full
選項(xiàng)運(yùn)行它伯病,它會(huì)向你顯示出所有沒有被其他對象指向的對象:
$ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (18/18), done.
dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4
dangling commit ab1afef80fac8e34258ff41fc1b867c702daa24b
dangling tree aea790b9a58f6cf6f2804eeac9f0abbe9631e4c9
dangling blob 7108f7ecb345ee9d0084193f147cdad4d2998293
在這個(gè)例子中午笛,你可以在 “dangling commit” 后看到你丟失的提交。 現(xiàn)在你可以用和之前相同的方法恢復(fù)這個(gè)提交誉察,也就是添加一個(gè)指向這個(gè)提交的分支驼卖。