Git 知識點整理
作者:Pursue
原文:https://bigjun2017.github.io/2018/09/24/ruan-jian-gong-ju/git/git-zhi-shi-dian-zheng-li/
1. Git 基本概念
-
repository
-
config
-
init
-
clone
-
fetch
-
pull
-
commit
-
push
-
branch
-
head
-
tag
-
merge
-
conflict
-
diff
-
log
-
show
-
status
2. Git 工作空間和文件狀態
(1). 工作空間
左側爲工作區,右側爲版本庫。
-
工作區(
Working Directory
) 就是在電腦裏能看到的目錄,比如 learngit 文件夾就是一個工作區。 -
版本庫(
Repository
)工作區有一個隱藏目錄.git
,是 Git 的版本庫。
在版本庫中標記爲index
的區域爲暫存區,標記爲master
的是 Git 爲我們自動創建的第一個分支,代表的是目錄樹。此時HEAD
實際是指向master
分支的一個 “遊標”,所以圖示的命令中出現 HEAD 的地方可以用master
來替換。圖中的 objects 標識的區域爲 git 的對象庫,實際位於.git/objects
目錄下。
-
當對工作區修改(或新增)的文件執行
git add
命令時,暫存區的目錄樹會被更新,同時工作區修改(或新增)的文件內容會被寫入到對象庫中的一個新的對象中,而該對象的 id 被記錄在暫存區的文件索引中。 -
當執行提交操作
git commit
時,暫存區的目錄樹會寫到版本庫(對象庫)中,master 分支會做相應的更新,即 master 最新指向的目錄樹就是提交時原暫存區的目錄樹。 -
當執行
git reset HEAD
命令時,暫存區的目錄樹會被重寫,會被 master 分支指向的目錄樹所替換,但是工作區不受影響。 -
當執行
git rm --cached
命令時,會直接從暫存區刪除文件,工作區則不做出改變。 -
當執行
git checkout .
或git checkout --
命令時,會用暫存區全部的文件或指定的文件替換工作區的文件。這個操作很危險,會清楚工作區中未添加到暫存區的改動。 -
當執行
git checkout HEAD .
或git checkout HEAD
命令時,會用 HEAD 指向的 master 分支中的全部或部分文件替換暫存區和工作區中的文件。這個命令也是極度危險的。因爲不但會清楚工作區中未提交的改動,也會清楚暫存區中未提交的改動。
(1). 文件狀態
Git 有三種狀態,你的文件可能處於其中之一:已提交 (committed
)、已修改 (modified
) 和已暫存 (staged
)。
3. Git 配置系統級、全局、當前倉庫用戶名、郵箱的命令
系統級、全局、當前倉庫選項分別是: 倉庫 - system、-global、-local(或默認不填)
git config --global user.name "Jerry Mouse"
git config --global user.email "jerry@yiibai.com"
列出 Git 設置
git config --list
git config -l
4. Git fetch 和 pull 的區別
-
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。 -
在回滾這一操作上看,效果差不多。但是在日後繼續 merge 以前的老版本時有區別。因爲
git revert
是用一次逆向的 commit“中和” 之前的提交,因此日後合併老的 branch 時,導致這部分改變不會再次出現,但是git reset
是之間把某些 commit 在某個 branch 上刪除,因而和老的 branch 再次 merge 時,這些被回滾的 commit 應該還會被引入。 -
git reset
是把 HEAD 向後移動了一下,而git revert
是 HEAD 繼續前進,只是新的 commit 的內容和要 revert 的內容正好相反,能夠抵消要被 revert 的內容。 -
git revert 與 git reset 最大的不同是,git revert 僅僅是撤銷某次提交。
另外,說一下git revert
, git reset –hard
和 –soft
的區別
-
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
操作會生成一個新的節點,之前的提交分開顯示。而rebase
操作不會生成新的節點,是將兩個分支融合成一個線性的提交。 -
解決衝突時。merge 操作遇到衝突的時候,當前 merge 不能繼續進行下去。手動修改衝突內容後,add 修改,commit 就可以了。而
rebase
操作的話,會中斷 rebase, 同時會提示去解決衝突。解決衝突後, 將修改 add 後執行git rebase –continue
繼續操作,或者git rebase –skip
忽略衝突。 -
git pull
和git pull --rebase
區別:git pull
做了兩個操作分別是” 獲取” 和” 合併”。所以加了 rebase 就是以 rebase 的方式進行合併分支,默認爲 merge。
總結:選擇 merge 還是 rebase?
-
merge 是一個合併操作,會將兩個分支的修改合併在一起,默認操作的情況下會提交合並中修改的內容
-
merge 的提交歷史忠實地記錄了實際發生過什麼,關注點在真實的提交歷史上面
-
rebase 並沒有進行合併操作,只是提取了當前分支的修改,將其複製在了目標分支的最新提交後面
-
rebase 的提交歷史反映了項目過程中發生了什麼,關注點在開發過程上面
-
merge 與 rebase 都是非常強大的分支整合命令,沒有優劣之分,使用哪一個應由項目和團隊的開發需求決定
-
merge 和 rebase 還有很多強大的選項,可以使用 git help 查看
7. Git stash 是什麼?它的相關使用方式命令
-
git stash: 備份當前的工作區的內容,從最近的一次提交中讀取相關內容,讓工作區保證和上次提交的內容一致。同時,將當前的工作區內容保存到 Git 棧中。
-
git stash pop: 從 Git 棧中讀取最近一次保存的內容,恢復工作區的相關內容。由於可能存在多個 Stash 的內容,所以用棧來管理,pop 會從最近的一個 stash 中讀取內容並恢復。
-
git stash pop –index stash@{0}: 恢復編號爲 0 的進度的工作區和暫存區。
-
git stash apply stash@{1} 以將你指定版本號爲 stash@{1} 的工作取出來
-
git stash drop[] 刪除某一個進度,默認刪除最新進度
-
git stash list: 顯示 Git 棧內的所有備份,可以利用這個列表來決定從那個地方恢復。
-
git stash clear: 清空 Git 棧。此時使用 gitg 等圖形化工具會發現,原來 stash 的哪些節點都消失了
# 恢復工作進度
git stash pop [--index] [<stash>]
--index 參數:不僅恢復工作區,還恢復暫存區
<stash> 指定恢復某一個具體進度。如果沒有這個參數,默認恢復最新進度
# 這是git stash保存進度的完整命令形式
git stash [save message] [-k|--no-keep-index] [--patch]
-k和--no-keep-index指定保存進度後,是否重置暫存區
--patch 會顯示工作區和HEAD的差異,通過編輯差異文件,排除不需要保存的內容。和git add -p命令類似
使用save可以對進度添加備註
# git stash save "這是保存的進度"
8. Git 只從暫存區刪除,從工作空間刪除的命令分別是什麼?
git rm --cached
git rm
git commit
9. Git 標籤的使用
# 列出現有的標籤
git tag
# 打標籤
git tag -a v1.01 -m "Relase version 1.01"
# 查看相應標籤的版本信息
git show v1.4
-
-a 選項, 創建一個含附註類型的標籤
-
-m 選項, 指定了對應的標籤說明
9. Git 分支的使用
# 查看本地分支
git branch
# 查看遠程分支
git branch -r
# 創建本地分支(注意新分支創建後不會自動切換爲當前分支)
git branch [name]
# 切換分支
git checkout [name]
# 創建新分支並立即切換到新分支
git checkout -b [name]
# 強制刪除一個分支
git branch -D [name]
# 合併分支(將名稱爲[name]的分支與當前分支合併)
git merge [name]
# 查看各個分支最後提交信息
git br -v
# 查看已經被合併到當前分支的分支
git br --merged
# 查看尚未被合併到當前分支的分支
git br --no-merged
10. 介紹 Git 衝突處理經驗,以及 merge 和 rebase 中的 ours 和 theirs 的差別。
merge 和 rebase 對於 ours 和 theirs 的定義是完全相反的。在 merge 時,ours 指代的是當前分支,theirs 代表需要被合併的分支。而在 rebase 過程中,ours 指向了修改參考分支,theirs 卻是當前分支。因爲 rebase 隱含了一個git checkout upstream
的過程,將HEAD
從 local 分支變成了 upstream 分支。git 會在 rebase 結束後撤銷這個改變,但它已經不可避免地影響了衝突的狀態,使 rebase 中 ours 和 theirs 的定義與 merge 截然相反。因此,在使用 ours 與 theirs 時請格外小心。
11. Git 遠程操作相關
(1). clone
git clone <版本庫的網址>
git clone <版本庫的網址> < 本地目錄名 >
# 克隆jQuery的版本庫
git clone https://github.com/jquery/jquery.git
git clone -o jQuery https://github.com/jquery/jquery.git
(2). remote
# 列出所有遠程主機
git remote
# 使用-v選項,可以參看遠程主機的網址
git remote -v
# 可以查看該主機的詳細信息
git remote show <主機名>
# 添加遠程主機
git remote add <主機名> <網址>
# 刪除遠程主機
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選項指定一個默認主機,這樣後面就可以不加任何參數使用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 使用簡介
就像代碼需要代碼規範一樣,代碼管理同樣需要一個清晰的流程和規範。三種廣泛使用的工作流程:
-
Git flow
-
Github flow
-
Gitlab flow
三種工作流程,有一個共同點:都採用” 功能驅動式開發”(Feature-driven development,簡稱 FDD)。它指的是,需求是開發的起點,先有需求再有功能分支(feature branch)或者補丁分支(hotfix branch)。完成開發後,該分支就合併到主分支,然後被刪除。最早誕生、並得到廣泛採用的一種工作流程,就是 Git flow。微信搜索公衆號:Linux 技術迷,回覆:linux 領取資料 。
它最主要的特點有兩個。首先,項目存在兩個長期分支,分別是:主分支 master、開發分支 develop。其次,項目存在三種短期分支,分別是:功能分支(feature branch)、補丁分支(hotfix branch)、預發分支(release branch),一旦完成開發,它們就會被合併進 develop 或 master,然後被刪除。
(1). Git Flow 流程圖
(2). Git Flow 常用的分支
-
Production分支
。也就是我們經常使用的 Master 分支,這個分支最近發佈到生產環境的代碼,最近發佈的 Release, 這個分支只能從其他分支合併,不能在這個分支直接修改。 -
Develop分支
。這個分支是我們是我們的主開發分支,包含所有要發佈到下一個 Release 的代碼,這個主要合併與其他分支,比如 Feature 分支。 -
Feature分支
。這個分支主要是用來開發一個新的功能,一旦開發完成,我們合併回 Develop 分支進入下一個 Release。 -
Release分支
。當你需要一個發佈一個新 Release 的時候,我們基於 Develop 分支創建一個 Release 分支,完成 Release 後,我們合併到 Master 和 Develop 分支。 -
Hotfix分支
。當我們在 Production 發現新的 Bug 時候,我們需要創建一個 Hotfix, 完成 Hotfix 後,我們合併回 Master 和 Develop 分支,所以 Hotfix 的改動會進入下一個 Release。
(3). Git Flow 代碼示例
a. 創建 develop 分支
git branch develop
git push -u origin develop
b. 開始新 Feature 開發
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
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/IVHljngAJ-NdF9KuviC8KQ