Git 知識點整理
在下方公眾號后臺回復:面試手冊,可獲取杰哥匯總的 3 份面試 PDF 手冊。
1. Git基本概念
repository
config
init
clone
fetch
pull
commit
push
branch
head
tag
merge
conflict
diff
log
show
status
2. Git工作空間和文件狀態(tài)
(1).工作空間

左側為工作區(qū),右側為版本庫。
工作區(qū)(
Working Directory) 就是在電腦里能看到的目錄,比如learngit文件夾就是一個工作區(qū)。版本庫(
Repository)工作區(qū)有一個隱藏目錄.git,是Git的版本庫。
在版本庫中標記為index的區(qū)域為暫存區(qū),標記為master的是Git為我們自動創(chuàng)建的第一個分支,代表的是目錄樹。此時HEAD實際是指向master分支的一個“游標”,所以圖示的命令中出現(xiàn)HEAD的地方可以用master來替換。圖中的objects標識的區(qū)域為git的對象庫,實際位于.git/objects目錄下。
當對工作區(qū)修改(或新增)的文件執(zhí)行
git add命令時,暫存區(qū)的目錄樹會被更新,同時工作區(qū)修改(或新增)的文件內容會被寫入到對象庫中的一個新的對象中,而該對象的id被記錄在暫存區(qū)的文件索引中。當執(zhí)行提交操作
git commit時,暫存區(qū)的目錄樹會寫到版本庫(對象庫)中,master分支會做相應的更新,即master最新指向的目錄樹就是提交時原暫存區(qū)的目錄樹。當執(zhí)行
git reset HEAD命令時,暫存區(qū)的目錄樹會被重寫,會被master分支指向的目錄樹所替換,但是工作區(qū)不受影響。當執(zhí)行
git rm --cached命令時,會直接從暫存區(qū)刪除文件,工作區(qū)則不做出改變。當執(zhí)行
git checkout .或git checkout --命令時,會用暫存區(qū)全部的文件或指定的文件替換工作區(qū)的文件。這個操作很危險,會清楚工作區(qū)中未添加到暫存區(qū)的改動。當執(zhí)行
git checkout HEAD .或git checkout HEAD命令時,會用HEAD指向的master分支中的全部或部分文件替換暫存區(qū)和工作區(qū)中的文件。這個命令也是極度危險的。因為不但會清楚工作區(qū)中未提交的改動,也會清楚暫存區(qū)中未提交的改動。
(1).文件狀態(tài)
Git 有三種狀態(tài),你的文件可能處于其中之一:已提交(committed)、已修改(modified)和已暫存(staged)。
3. Git配置系統(tǒng)級、全局、當前倉庫用戶名、郵箱的命令
系統(tǒng)級、全局、當前倉庫選項分別是:倉庫-system、-global、-local(或默認不填)
git?config?--global?user.name?"Jerry?Mouse"
git?config?--global?user.email?"[email protected]"
列出Git設置
git?config?--list
git?config?-l
4. Git fetch和pull的區(qū)別
git fetch:相當于是從遠程獲取最新版本到本地,不會自動merge.git pull:相當于是從遠程獲取最新版本并merge到本地.
(1). git fetch示例:
Git?fetch?origin?master
git?log?-p?master..origin/master
git?merge?origin/master
以上命令的含義:
首先從遠程的
origin的master主分支下載最新的版本到origin/master分支上然后比較本地的
master分支和origin/master分支的差別最后進行合并
上述過程其實可以用以下更清晰的方式來進行:
(1). git pull示例:
git?pull?origin?master
上述命令其實相當于git fetch和git merge。在實際使用中,git fetch更安全一些,因為在merge前,我們可以查看更新情況,然后再決定是否合并。
5. Git reset和revert的卻別
git revert是用一次新的commit來回滾之前的commit,git reset是直接刪除指定的commit。在回滾這一操作上看,效果差不多。但是在日后繼續(xù)merge以前的老版本時有區(qū)別。因為
git revert是用一次逆向的commit“中和”之前的提交,因此日后合并老的branch時,導致這部分改變不會再次出現(xiàn),但是git reset是之間把某些commit在某個branch上刪除,因而和老的branch再次merge時,這些被回滾的commit應該還會被引入。git reset是把HEAD向后移動了一下,而git revert是HEAD繼續(xù)前進,只是新的commit的內容和要revert的內容正好相反,能夠抵消要被revert的內容。git revert與git reset最大的不同是,git revert 僅僅是撤銷某次提交。
另外,說一下git revert, git reset –hard和 –soft的區(qū)別
git reset –mixed id: 是將git的HEAD變了(也就是提交記錄變了),但文件并沒有改變,(也就是working tree并沒有改變)。git reset –soft id: 實際上,是git reset –mixed id后,又做了一次git add。git reset –herd id: 是將git的HEAD變了,文件也變了。
6. Git merge和reabse的相同點和不同點
merge是合并的意思,rebase是復位基底的意思,相同點都是用來合并分支的。

不同點:
merge操作會生成一個新的節(jié)點,之前的提交分開顯示。而rebase操作不會生成新的節(jié)點,是將兩個分支融合成一個線性的提交。解決沖突時。merge操作遇到?jīng)_突的時候,當前merge不能繼續(xù)進行下去。手動修改沖突內容后,add 修改,commit就可以了。而
rebase操作的話,會中斷rebase,同時會提示去解決沖突。解決沖突后,將修改add后執(zhí)行git rebase –continue繼續(xù)操作,或者git rebase –skip忽略沖突。git pull和git pull --rebase區(qū)別:git pull做了兩個操作分別是”獲取”和”合并”。所以加了rebase就是以rebase的方式進行合并分支,默認為merge。
總結:選擇 merge 還是 rebase?
merge 是一個合并操作,會將兩個分支的修改合并在一起,默認操作的情況下會提交合并中修改的內容
merge 的提交歷史忠實地記錄了實際發(fā)生過什么,關注點在真實的提交歷史上面
rebase 并沒有進行合并操作,只是提取了當前分支的修改,將其復制在了目標分支的最新提交后面
rebase 的提交歷史反映了項目過程中發(fā)生了什么,關注點在開發(fā)過程上面
merge 與 rebase 都是非常強大的分支整合命令,沒有優(yōu)劣之分,使用哪一個應由項目和團隊的開發(fā)需求決定
merge 和 rebase 還有很多強大的選項,可以使用 git help 查看
7. Git stash是什么?它的相關使用方式命令
git stash: 備份當前的工作區(qū)的內容,從最近的一次提交中讀取相關內容,讓工作區(qū)保證和上次提交的內容一致。同時,將當前的工作區(qū)內容保存到Git棧中。
git stash pop: 從Git棧中讀取最近一次保存的內容,恢復工作區(qū)的相關內容。由于可能存在多個Stash的內容,所以用棧來管理,pop會從最近的一個stash中讀取內容并恢復。
git stash pop –index stash@{0}: 恢復編號為0的進度的工作區(qū)和暫存區(qū)。
git stash apply stash@{1} 以將你指定版本號為stash@{1}的工作取出來
git stash drop[] 刪除某一個進度,默認刪除最新進度
git stash list: 顯示Git棧內的所有備份,可以利用這個列表來決定從那個地方恢復。
git stash clear: 清空Git棧。此時使用gitg等圖形化工具會發(fā)現(xiàn),原來stash的哪些節(jié)點都消失了
#?恢復工作進度
git?stash?pop?[--index]?[]
--index?參數(shù):不僅恢復工作區(qū),還恢復暫存區(qū)
?指定恢復某一個具體進度。如果沒有這個參數(shù),默認恢復最新進度
#?這是git?stash保存進度的完整命令形式
git?stash?[save?message]?[-k|--no-keep-index]?[--patch]
-k和--no-keep-index指定保存進度后,是否重置暫存區(qū)
--patch 會顯示工作區(qū)和HEAD的差異,通過編輯差異文件,排除不需要保存的內容。和git add -p命令類似
使用save可以對進度添加備注
#?git?stash?save?"這是保存的進度"
8. Git只從暫存區(qū)刪除,從工作空間刪除的命令分別是什么?
git?rm?--cached
git?rm
git?commit
9. Git標簽的使用
#?列出現(xiàn)有的標簽
git?tag
#?打標簽
git?tag?-a?v1.01?-m?"Relase?version?1.01"
#?查看相應標簽的版本信息
git?show?v1.4
-a 選項,創(chuàng)建一個含附注類型的標簽
-m 選項,指定了對應的標簽說明
9. Git分支的使用
#?查看本地分支
git?branch
#?查看遠程分支
git?branch?-r
#?創(chuàng)建本地分支(注意新分支創(chuàng)建后不會自動切換為當前分支)
git?branch?[name]
#?切換分支
git?checkout?[name]
#?創(chuàng)建新分支并立即切換到新分支
git?checkout?-b?[name]
#?強制刪除一個分支
git?branch?-D?[name]
#?合并分支(將名稱為[name]的分支與當前分支合并)
git?merge?[name]
#?查看各個分支最后提交信息
git?br?-v
#?查看已經(jīng)被合并到當前分支的分支
git?br?--merged
#?查看尚未被合并到當前分支的分支
git?br?--no-merged
10. 介紹Git沖突處理經(jīng)驗,以及merge和rebase中的ours和theirs的差別。
merge和rebase對于ours和theirs的定義是完全相反的。在merge時,ours指代的是當前分支,theirs代表需要被合并的分支。而在rebase過程中,ours指向了修改參考分支,theirs卻是當前分支。因為rebase 隱含了一個git checkout upstream的過程,將HEAD從local分支變成了upstream分支。git會在rebase結束后撤銷這個改變,但它已經(jīng)不可避免地影響了沖突的狀態(tài),使rebase中ours和theirs的定義與merge 截然相反。因此,在使用ours與theirs時請格外小心。
11. Git遠程操作相關
(1). clone
git clone <版本庫的網(wǎng)址>
git clone <版本庫的網(wǎng)址> <本地目錄名>
#?克隆jQuery的版本庫
?git?clone?https://github.com/jquery/jquery.git
?git?clone?-o?jQuery?https://github.com/jquery/jquery.git
(2). remote
#?列出所有遠程主機
git?remote
#?使用-v選項,可以參看遠程主機的網(wǎng)址
git?remote?-v
#?可以查看該主機的詳細信息
git?remote?show?<主機名>
#?添加遠程主機
git?remote?add?<主機名>?<網(wǎng)址>
#?刪除遠程主機
git?remote?rm?<主機名>
#?修改遠程主機名稱
git?remote?rename?<原主機名>?<新主機名>
(3). fetch
#?取回所有分支(branch)的更新到本地
git?fetch?<遠程主機名>
#?取回某的特定分支的更新
git?fetch?<遠程主機名>?<分支名>
#?取回origin主機的master分支的更新
git?fetch?origin?master
#?所取回的更新,在本地主機上要用”遠程主機名/分支名”的形式讀取。比如origin主機的master,就要用origin/master讀取。可以使用git merge命令或者git rebase命令,在本地分支上合并遠程分支
git?merge?origin/master
git?rebase?origin/master
(4). pull
git pull <遠程主機名> <遠程分支名>:<本地分支名>
#?取回origin主機的next分支,與本地的master分支合并
git?pull?origin?next:master
#?如果遠程分支是與當前分支合并,則冒號后面的部分可以省略。
git?pull?origin?next
#?上面的命令實質上等同于先做git fetch,再做git merge。
git?fetch?origin
git?merge?origin/next
#?合并需要采用rebase模式
git?pull?--rebase?<遠程主機名>?<遠程分支名>:<本地分支名>
(5). push
git push <遠程主機名> <本地分支名>:<遠程分支名>
注意:分支推送順序的寫法是”<來源地>:<目的地>”,所以git pull是”<遠程分支>:<本地分支>”,而git push是”<本地分支>:<遠程分支>”。
如果省略遠程分支名,則表示將本地分支推送與之存在”追蹤關系”的遠程分支(通常兩者同名),如果該遠程分支不存在,則會被新建。
如果省略本地分支名,則表示刪除指定的遠程分支,因為這等同于推送一個空的本地分支到遠程分支。
#?將本地的master分支推送到origin主機的master分支。如果后者不存在,則會被新建
git?push?origin?master
#?省略了本地分支,以下等同,刪除origin主機的master分支
git?push?origin?:master
git?push?origin?--delete?master
#?如果當前分支與遠程分支之間存在追蹤關系,則本地分支和遠程分支都可以省略
git?push?origin
#?如果當前分支只有一個追蹤分支,那么主機名都可以省略。
git?push
#?如果當前分支與多個主機存在追蹤關系,則可以使用-u選項指定一個默認主機,這樣后面就可以不加任何參數(shù)使用git?push
git?push?-u?origin?master
#?不管是否存在對應的遠程分支,將本地的所有分支都推送到遠程主機
git?push?--all?origin
#?強制推送
git?push?--force?origin
#?git?push不會推送標簽(tag),除非使用–tags選項
git?push?origin?--tags
12. Git Flow使用簡介
就像代碼需要代碼規(guī)范一樣,代碼管理同樣需要一個清晰的流程和規(guī)范。三種廣泛使用的工作流程:
Git flow
Github flow
Gitlab flow
三種工作流程,有一個共同點:都采用”功能驅動式開發(fā)”(Feature-driven development,簡稱FDD)。它指的是,需求是開發(fā)的起點,先有需求再有功能分支(feature branch)或者補丁分支(hotfix branch)。完成開發(fā)后,該分支就合并到主分支,然后被刪除。最早誕生、并得到廣泛采用的一種工作流程,就是Git flow。
它最主要的特點有兩個。首先,項目存在兩個長期分支,分別是:主分支master、開發(fā)分支develop。其次,項目存在三種短期分支,分別是:功能分支(feature branch)、補丁分支(hotfix branch)、預發(fā)分支(release branch),一旦完成開發(fā),它們就會被合并進develop或master,然后被刪除。
(1). Git Flow流程圖

(2). Git Flow常用的分支
Production分支。也就是我們經(jīng)常使用的Master分支,這個分支最近發(fā)布到生產環(huán)境的代碼,最近發(fā)布的Release, 這個分支只能從其他分支合并,不能在這個分支直接修改。Develop分支。這個分支是我們是我們的主開發(fā)分支,包含所有要發(fā)布到下一個Release的代碼,這個主要合并與其他分支,比如Feature分支。Feature分支。這個分支主要是用來開發(fā)一個新的功能,一旦開發(fā)完成,我們合并回Develop分支進入下一個Release。Release分支。當你需要一個發(fā)布一個新Release的時候,我們基于Develop分支創(chuàng)建一個Release分支,完成Release后,我們合并到Master和Develop分支。Hotfix分支。當我們在Production發(fā)現(xiàn)新的Bug時候,我們需要創(chuàng)建一個Hotfix, 完成Hotfix后,我們合并回Master和Develop分支,所以Hotfix的改動會進入下一個Release。
(3). Git Flow代碼示例
a. 創(chuàng)建develop分支
git?branch?develop
git?push?-u?origin?develop
b. 開始新Feature開發(fā)
git?checkout?-b?some-feature?develop
#?Optionally,?push?branch?to?origin:
git?push?-u?origin?some-feature
#?做一些改動
git?status
git?add?some-file
git?commit
c. 完成Feature
git?pull?origin?develop
git?checkout?develop
git?merge?--no-ff?some-feature
git?push?origin?develop
git?branch?-d?some-feature
#?If?you?pushed?branch?to?origin:
git?push?origin?--delete?some-feature
d. 開始Relase
git?checkout?-b?release-0.1.0?develop
#?Optional:?Bump?version?number,?commit
#?Prepare?release,?commit
e. 完成Release
git?checkout?master
git?merge?--no-ff?release-0.1.0
git?push
git?checkout?develop
git?merge?--no-ff?release-0.1.0
git?push
git?branch?-d?release-0.1.0
#?If?you?pushed?branch?to?origin:
git?push?origin?--delete?release-0.1.0???
git?tag?-a?v0.1.0?master
git?push?--tags
f. 開始Hotfix
git?checkout?-b?hotfix-0.1.1?master
g. 完成Hotfix
git?checkout?master
git?merge?--no-ff?hotfix-0.1.1
git?push
git?checkout?develop
git?merge?--no-ff?hotfix-0.1.1
git?push
git?branch?-d?hotfix-0.1.1
git?tag?-a?v0.1.1?master
git?push?--tags
來源:
https://bigjun2017.github.io/2018/09/24/ruan-jian-gong-ju/git/git-zhi-shi-dian-zheng-li/
推薦閱讀

