一、Git介紹
所有的版本控制系統(tǒng),其實(shí)只能跟蹤文本文件的改動(dòng),比如TXT文件,網(wǎng)頁(yè),所有的程序代碼等等,Git也不例外。不幸的是,Microsoft的Word格式是二進(jìn)制格式,因此,版本控制系統(tǒng)是沒(méi)法跟蹤Word文件的改動(dòng)的。
二、Git工作原理
1. Git幾個(gè)區(qū)域理解

- Workspace:工作區(qū)也就是working directory
- Index / Stage:暫存區(qū)
- Repository:倉(cāng)庫(kù)區(qū)(或本地倉(cāng)庫(kù))
- Remote:遠(yuǎn)程倉(cāng)庫(kù)
工作區(qū)
是對(duì)項(xiàng)目的某個(gè)版本獨(dú)立提取出來(lái)的內(nèi)容。 這些從 Git 倉(cāng)庫(kù)的壓縮數(shù)據(jù)庫(kù)中提取出來(lái)的文件,放在磁盤(pán)
上供你使用或修改。這些文件就是你直接看到的文件
暫存區(qū)
.git目錄下的index文件, 暫存區(qū)會(huì)記錄git add添加文件的相關(guān)信息(文件名、大小、timestamp…),不保存文件實(shí)體, 通過(guò)id指向每個(gè)文件實(shí)體。可以使用git status查看暫存區(qū)的狀態(tài)。暫存區(qū)標(biāo)記了你當(dāng)前工作區(qū)中,哪些內(nèi)容是被git管理的。
本地倉(cāng)庫(kù)
git commit后同步index的目錄樹(shù)到本地倉(cāng)庫(kù),方便從下一步通過(guò)git push同步本地倉(cāng)庫(kù)與遠(yuǎn)程倉(cāng)庫(kù)的同步。
遠(yuǎn)程倉(cāng)庫(kù)
遠(yuǎn)程倉(cāng)庫(kù)是指托管在因特網(wǎng)或其他網(wǎng)絡(luò)中的你的項(xiàng)目的版本庫(kù),本質(zhì)和本地倉(cāng)庫(kù)相同。
2. 文件狀態(tài)
你工作目錄下的每一個(gè)文件都不外乎這兩種狀態(tài):已跟蹤或未跟蹤。
- 已跟蹤的文件是指那些被納入了
版本控制的文件,在上一次快照中有它們的記錄,在工作一段時(shí)間后,它們的狀態(tài)可能處于未修改,已修改或已
放入暫存區(qū)。 - 工作目錄中除已跟蹤文件以外的所有其它文件都屬于未跟蹤文件,它們既不存在于上次快照的記
錄中,也沒(méi)有放入暫存區(qū)。 新添加一個(gè)文件,其就處于未跟蹤狀態(tài)

3. Git分支理解
- Git每次的提交對(duì)象都包含上一次提交的指針,故所有提交會(huì)形成唯一的鏈結(jié)構(gòu)。
-
Git 的分支,其實(shí)本質(zhì)上僅僅是指向提交對(duì)象的可變指針
分支示意 - 每個(gè)分支都是一個(gè)指針,指向某一次提交,例如master指針指向
f30ab的提交,testing分支指向87ab2的提交 - 當(dāng)前分支使用HEAD指針指向,例如切換會(huì)master分支,則HEAD就指向master
三、Git常用命令
1. 創(chuàng)建版本庫(kù)
git clone <url>
克隆遠(yuǎn)程的版本庫(kù)到本地,eg:git clone https://github.com/breezenan/getskills.git
git init
初始化一個(gè)本地Git倉(cāng)庫(kù),會(huì)在當(dāng)前目錄下產(chǎn)生.git文件夾,然后當(dāng)前文件夾下的文件就會(huì)被git進(jìn)行管理
2. 修改和提交
git status // 顯示
.git版本庫(kù)的所有文件狀態(tài)
git status . // 顯示當(dāng)前文件夾下的文件狀態(tài)
git diff // 比較工作區(qū)和暫存區(qū)差異
git diff --cached [<path>...] // 比較暫存區(qū)與最新本地版本庫(kù)(本地庫(kù)中最近一次commit的內(nèi)容)
git diff HEAD [<path>...] // 比較工作區(qū)與最新本地版本庫(kù)
git diff commit-id [<path>...] // 比較工作區(qū)與指定commit-id的差異
git diff --cached [<commit-id>] [<path>...] // 比較暫存區(qū)與指定commit-id的差異
git diff [<commit-id>] [<commit-id>] // 比較兩個(gè)commit-id之間的差異
git add [<path>...] // 將指定文件或文件夾加入到暫存區(qū)。如果該文件是新文件,則新文件由未跟蹤狀態(tài)變?yōu)楦櫊顟B(tài)并放入暫存區(qū)
git rm <file> // 將指定的已刪除文件放入暫存區(qū),或者將指定文件刪除并放入暫存區(qū),git add無(wú)法將已刪除文件加入到暫存區(qū)
git rm --cached <file> // 對(duì)指定文件不跟蹤,但不刪除,相當(dāng)于將指定文件變?yōu)樾略鑫募?/p>
git commit // 直接提交,會(huì)彈出提交信息窗口
git commit -m "your commit info" // 直接提交,-m指定提交信息
git commit --amend // 將最新的提交重新提交,如果暫存區(qū)存在快照,也會(huì)和本次提交作為一次提交
3. 查看提交歷史
git log // 查看提交歷史記錄
git log <file> // 查看指定文件提交歷史(不帶具體修改變化)
git log -p <file> // 查看指定文件提交歷史(帶具體修改變化)
git show <commitid> // 查看指定提交的修改內(nèi)容
git show <commitid> <file> // 查看指定提交指定文件的修改內(nèi)容
git show --name-only <commitid> // 查看指定提交修改的文件的文件名
4. 撤銷(xiāo)
git checkout -- <file> // 本地修改的(不包含新增)文件還原到倉(cāng)庫(kù)狀態(tài)或暫存狀態(tài)
git reset HEAD // 把暫存區(qū)的修改撤銷(xiāo)掉(unstage),重新放回工作區(qū)
git reset HEAD <file> // 把暫存區(qū)的指定修改文件撤銷(xiāo)掉(unstage),重新放回工作區(qū)
git reset --hard <commitid> // 回退到指定版本,此時(shí)HEAD就指向指定commitid,并且版本內(nèi)容會(huì)完全覆蓋工作區(qū),故會(huì)導(dǎo)致工作區(qū)內(nèi)容丟失
git revert <commitid> // 將制定提交內(nèi)容移除(會(huì)產(chǎn)生一個(gè)新的提交)
git remote
git remote 列出每個(gè)遠(yuǎn)程服務(wù)器的簡(jiǎn)寫(xiě)
nan@breeze:~/work/getskills$ git remote
gitee
origin
git remote -v 列出遠(yuǎn)程服務(wù)
nan@breeze:~/work/getskills$ git remote -v
gitee https://gitee.com/wangyannan/getskills.git (fetch)
gitee https://gitee.com/wangyannan/getskills.git (push)
origin https://github.com/breezenan/getskills.git (fetch)
origin https://github.com/breezenan/getskills.git (push)
提交暫存區(qū)內(nèi)容到倉(cāng)庫(kù)
git branch
git branch -v 查看分支,并顯示各個(gè)分支的最后一次提交
git branch --merged
git branch --no-merged
git branch -d testing
git branch -vv
git checkout
git reset HEAD <file> 取消暫存
git status 查看狀態(tài)
git status -s 狀態(tài)簡(jiǎn)覽
git cherry-pick
git merge
fast-forward模式merge
例如倉(cāng)庫(kù)如下圖,有三個(gè)分支master,hotfix,iss53

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)
由于當(dāng)前 master 分支所指向的提交是你當(dāng)前提交(有關(guān) hotfix 的提交)的直接上游,所以 Git 只是簡(jiǎn)單的將指針向前移動(dòng)。 換句話(huà)說(shuō),當(dāng)你試圖合并兩個(gè)分支時(shí),如果順著一個(gè)分支走下去能夠到達(dá)另一個(gè)分支,那么 Git 在合并兩者的時(shí)候,只會(huì)簡(jiǎn)單的將指針向前推進(jìn)(指針右移),因?yàn)檫@種情況下的合并操作沒(méi)有需要解決的分歧——這就叫做快進(jìn)(fast-forward)。

master 被快進(jìn)到 hotfix
三方合并
例如倉(cāng)庫(kù)如下圖,有兩個(gè)分支master和iss53

一次典型合并中所用到的三個(gè)快照
出現(xiàn)這種情況的時(shí)候,Git 會(huì)使用兩個(gè)分支的末端所指的快照(C4 和 C5
)以及這兩個(gè)分支的工作祖先(C2),做一個(gè)簡(jiǎn)單的三方合并Git。將此次三方合并的結(jié)果做了一個(gè)新的快照并且自動(dòng)創(chuàng)建一個(gè)新的提交指向它。 這個(gè)被稱(chēng)作一次合并提交,它的特別之處在于他有不止一個(gè)父提交。
合并后如下

Git 會(huì)自行決定選取哪一個(gè)提交作為最優(yōu)的共同祖先,并以此作為合并的基礎(chǔ)
git fetch
基本知識(shí)
我們本地的.git文件夾里面對(duì)應(yīng)也存儲(chǔ)了git本地倉(cāng)庫(kù)master分支的commit ID 和 跟蹤的遠(yuǎn)程分支origin/master的commit ID(可以有多個(gè)遠(yuǎn)程倉(cāng)庫(kù))。那什么是跟蹤的遠(yuǎn)程分支呢,打開(kāi)git文件夾可以看到如下文件:
.git/refs/head/[本地分支]
.git/refs/remotes/[正在跟蹤的分支]
其中head就是本地分支,remotes是跟蹤的遠(yuǎn)程分支,這個(gè)類(lèi)型的分支在某種類(lèi)型上是十分相似的,他們都是表示提交的SHA1校驗(yàn)和(就是commitID)
git fetch origin 會(huì)更新遠(yuǎn)程服務(wù)器的最新提交到本地的遠(yuǎn)程跟蹤分支,會(huì)更新.git/refs/remotes/下的文件commitid

通過(guò)git merge origin/master 即可將跟蹤的遠(yuǎn)程分支記錄合并到本地倉(cāng)庫(kù)master分支并更新工作區(qū)
git pull
git pull 相當(dāng)于直接更新了跟蹤的遠(yuǎn)程分支記錄并更新了本地倉(cāng)庫(kù)提交并進(jìn)行merge
git rebase
rebase翻譯為變基

現(xiàn)在experiment分支以master為基準(zhǔn),合并記錄
$ git checkout experiment
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: added staged command
它的原理是首先找到這兩個(gè)分支(即當(dāng)前分支 experiment、變基操作的目標(biāo)基底分支 master)的最近共同祖先 C2,然后對(duì)比當(dāng)前分支相對(duì)于該祖先的歷次提交,提取相應(yīng)的修改并存為臨時(shí)文件,然后將當(dāng)前分支指向目標(biāo)基底 C3, 最后以此將之前另存為臨時(shí)文件的修改依序應(yīng)用

如果experiment分支還有C5記錄,那么git rebase master后,還會(huì)出現(xiàn)C5'。
git stash
git log
git tag
git remote
HEAD意義
首先,Git必須知道當(dāng)前版本是哪個(gè)版本,在Git中,用HEAD表示當(dāng)前版本,也就是最新的提交,上一個(gè)版本就是HEAD^,上上一個(gè)版本就是HEAD^^,當(dāng)然往上100個(gè)版本寫(xiě)100個(gè)^比較容易數(shù)不過(guò)來(lái),所以寫(xiě)成HEAD~100。
git diff HEAD
-
git diff HEAD -- filename命令可以查看工作區(qū)和版本庫(kù)里面最新版本的區(qū)別
遠(yuǎn)程倉(cāng)庫(kù)
添加遠(yuǎn)程倉(cāng)庫(kù)
git remote add <shortname> <url>添加一個(gè)新的遠(yuǎn)程 Git 倉(cāng)庫(kù),同時(shí)指定一個(gè)你可以輕松引用的簡(jiǎn)
寫(xiě)
nan@breeze:~/work/gitskills$ git remote add origin https://github.com/breezenan/getskills.git
nan@breeze:~/work/gitskills$ git remote
origin
nan@breeze:~/work/gitskills$ git remote -v
origin https://github.com/breezenan/getskills.git (fetch)
origin https://github.com/breezenan/getskills.git (push)
origin當(dāng)然可以換成其他名字,例如pig,dog,為了容易標(biāo)識(shí)寫(xiě)github也不錯(cuò),因?yàn)樵撨h(yuǎn)程倉(cāng)庫(kù)就是github托管,如果在碼云(gitee)上也有個(gè)遠(yuǎn)程倉(cāng)庫(kù),則可以給其起名為gitee
git push -u origin master 推送提交到指定分支,并設(shè)置上游分支對(duì)應(yīng)關(guān)系, -u就是--set-upstream
該命令等效于
git push origin master 推送代碼到遠(yuǎn)程名為origin的master分支
git branch --set-upstream-to master origin/master 設(shè)置master分支的默認(rèn)上游遠(yuǎn)程分支為origin/master
當(dāng)建立本地分支和上游分支的關(guān)系時(shí),就不用指定遠(yuǎn)程分支了,默認(rèn)采用上游分支,例如git push,此時(shí)默認(rèn)推送到origin master分支
clone遠(yuǎn)程倉(cāng)庫(kù)到本地
git clone https://github.com/breezenan/getskills.git克隆倉(cāng)庫(kù)到本地,此時(shí)本地的遠(yuǎn)程倉(cāng)庫(kù)名稱(chēng)默認(rèn)為origin,示意圖如下

Git配置
Git 自帶一個(gè) git config 的工具來(lái)幫助設(shè)置控制 Git 外觀和行為的配置變量。 這些變量存儲(chǔ)在三個(gè)不同的位
置:
- /etc/gitconfig 文件: 包含系統(tǒng)上每一個(gè)用戶(hù)及他們倉(cāng)庫(kù)的通用配置。 如果使用帶有 --system 選項(xiàng)的
git config 時(shí),它會(huì)從此文件讀寫(xiě)配置變量。 - ~/.gitconfig 或 ~/.config/git/config 文件:只針對(duì)當(dāng)前用戶(hù)。 可以傳遞 --global 選項(xiàng)讓 Git
讀寫(xiě)此文件。 - 當(dāng)前使用倉(cāng)庫(kù)的 Git 目錄中的 config 文件(就是 .git/config):針對(duì)該倉(cāng)庫(kù)。
git config --system color.ui "auto" 針對(duì)所有用戶(hù)
git config --global user.name "John Doe" 針對(duì)當(dāng)前用戶(hù)
git config user.email = ynwang@grandstream.cn 針對(duì)當(dāng)前git倉(cāng)庫(kù)
git config --list 查看配置項(xiàng)
git config user.name 查看user.name的值
忽略文件
在工作區(qū)根目錄創(chuàng)建.gitignore文件,里面可以配置忽略跟蹤的文件類(lèi)型.例如:
*.[oa]
*.txt
第一行告訴 Git 忽略所有以 .o 或 .a 結(jié)尾的文件,第二行忽略.txt形式的文件
GitHub 有一個(gè)十分詳細(xì)的針對(duì)數(shù)十種項(xiàng)目及語(yǔ)言的 .gitignore 文件列表,你可以在
https://github.com/github/gitignore 找到它.
Git提交模板配置
- 新建模板文件
.git-commit-template.txt,名字任意,內(nèi)容例如:
[Bug 101010/INTERNAL/NBF]
Cause: None
Solution: None
Fixed Version:2019-04-20
Branch: Alapca
內(nèi)容就是你要提交的內(nèi)容,在你提交時(shí)會(huì)讓你重新編輯這段內(nèi)容
-
git config commit.template [剛才創(chuàng)建的模板文件全路徑]
這個(gè)命令只能設(shè)置當(dāng)前分支的提交模板,如果要針對(duì)當(dāng)前用戶(hù),加入--global即可 - 設(shè)置編輯器
git config --global core.editor [vi|vim] - git commit
參考
- 一篇文章,教你學(xué)會(huì)Git
- Git教程
- <<Pro Git>>
