文章目錄
- git入門與實踐(3)
- 1. 分支入門操作
- 2. 分支合併
- 2. 1 HEAD查看命令
- 2. 1. 1 git log --decorate
- 2. 1. 2 git log --oneline --decorate
- 2. 1. 3 git log --oneline --decorate --all --graph
- 2. 2 git merge 分支合併
- 2. 3 快速前移
- 3. 分支衝突
- 4. 解決分支衝突
- 5. 刪除分支
- 6. 取消合併
- 7. 撤銷合集
- 8. reset使用
- 8. 1 git reset HEAD
- 8. 1. 1 多條回退
- 8. 1. 2 git reset --hard (儘量避免使用)
- 8. 1. 3 git reset --soft(建議使用)
- 8. 1. 4 git reset --mixed(默認)
- 8. 2 通過哈希找回歷史記錄
- 8. 3 查看歷史提交記錄
- 9. reset與checkout本質
git入門與實踐(3)
1. 分支入門操作
某天完成了項目的一次開發後,準備開始第二次開發,但是如果直接在一次開發的基礎上更改,我們的文件就是1+2,管理起來相當不方便。
1. 1 查看分支: git branch
前面*
代表當前所處的分支
1. 2 創建分支:git branch 分支名稱
創建出來的分支,並不會改變我們當前所在的位置。
git branch branch1
git branch
git是如何判斷我們所處當前哪個分支上呢?
(HEAD -> master, branch1)
git是通過HEAD指向獲取當前分支的。
1. 3 切換分支:git checkout 分支名
將HEAD
指向切換的分支
將工作目錄恢復成當前分支的快照
簡寫命令:git checkout -b 分支名
之後提交一個文件,之後看日誌,發現HEAD
已經指向branch1
了。再往後仔細看標註,就是master
分支的日誌了。
除此之外,如果是branch1
分支,切換過去,只會顯示該分支所有的文件。
切換master
分支,則是它所有的文件。
在branch1
分支下刪除所有文件
git rm * -r
再切回去:
文件都在!因此各個分支是互不影響的!
1. 3. 1 分支流程詳解
首先有一次c1
的提交,在c1
的基礎上還有c2
的提交,這些操作都是在默認的master
分支上進行的,在c2
的提交上又創建新分支branch1
。git如何判斷在當前在哪個分支上,就是通過HEAD
指針。當前HEAD
指向master
。
我們切換分支後,HEAD
就指向branch1
了。
我們再提交c3
,此時branch1
向前移動,並帶着HEAD
一塊移動了。此時branch1
的路線就是c1->c2->c3
。
此時我們想操作master
分支,就需要切換過去了。
之後再進行c4
提交。此時master
的路線就是c1->c2->c4
。
1. 3. 1. 1 流程動態演示
2. 分支合併
假如我們開始開發,基礎功能是c1
提交和c2
提交之間的內容,處理的是第一個版本的內容。
爲了便於後面的開發,我們將其分成兩個分支,一個master
,一個branch1
。
緊接着我們在分支branch1
上開始開發,然後進行功能提升,進行第二個版本開發,提交c3
、c5
。
現在又出現了問題,第一個版本開發的時候,有一些小的bug。這個時候需要提交一些補丁,這可怎麼呢?首先需要回退到c2
上,這上面有第一個版本開發的時候所有的記錄,這個時候我們實際不用回退。直接切換到master
的分支,在這個分支修改bug並提交c4
。這個時候就可以將c1->c2->c4
的代碼進行打包,替換線上的代碼了。
第二個版本開發完成至c5
提交。唯獨缺少了c4
的補丁,你可能會想到再創建一個提交修改bug。明顯是不科學的,這樣重複處理,是非常耽誤時間和工作效率的。因此git就提供了一個很好用的功能,即合併分支。
模擬一下以上操作,新建一個文件夾。
c1
提交
c2
提交
git checkout -b branch1
創建分支並使HEAD指向新分支,-b
就代表 branch
完成c3
提交
切換回master
打補丁,c4
提交
2. 1 HEAD查看命令
2. 1. 1 git log --decorate
--decorate
參數用來顯示一些相關的信息(帶有分支信息),如HEAD
、分支名、tag名等
2. 1. 2 git log --oneline --decorate
--oneline
校驗和(哈希)
查看分支指向+哈希
以上顯示不太明顯,我們可以該命令
切換回branch1
看看
我們繼續提交c5
2. 1. 3 git log --oneline --decorate --all --graph
查看命令的完美組合 —> 包含了所有分支的提交,以樹形圖形形式展現。
--all
所有分支信息
--graph
打印出樹形圖
2. 2 git merge 分支合併
注意:在我們日常開發中最好必須有一個主分支,有一個主分支就利用我們對分支進行管理。比如平時打遊戲,就會有一個主線任務和一個支線任務。然後支線任務也不會影響主線,實際上項目中主線就是項目的版本。默認情形下,大家都把默認分支master
作爲主分支。
git merge 目標分支
將目標分支的內容合併到當前分支
git merge branch1
將branch1
分支合併到主分支master
上來。
此時完成了合併,解決了第二個版本中第一個版本的bug
,我們想讓第二個版本上線,就打包c6
代碼即可。
2. 2. 1 模擬合併小結
其實最終合併關注3個點,一個是必須有共同父節點c2
,其次是master
末尾節點c4
和brach
末尾節點c5
,將c4
、c5
實際整合成了c6
,c6
就完美解決了,第二個開發版本c2->c3->c5
中需要修復第一個開發版本bug的問題了。
2. 3 快速前移
當master
和branch
沒有形成分叉,依舊是處於一條路徑線,當HEAD
落後於所要合併的分支,將會形成快速前移
先初始化目錄
進行兩次提交
創建分支branch1
,並切換過去,做第三次提交
git checkout -b branch1
git log --oneline --decorate --all --graph
切換到master
,並與branch1
合併
git log --oneline --decorate --all --graph
我們發現了奇怪的問題,master
和branch1
都跑到c3
了。爲啥成這樣了, 因爲快速前移,我們仔細觀察上圖,就有提示:Fast-forward
仔細觀察上圖發現合併前並沒形成分叉,branch1
只是在master
的上開了一個分支。
master:c1->c2
branch1:c1->c2->c3
master
上的提交都包括在branch1
裏了,這時執行的合併就和之前不一樣了,不會出現新的提交,而是將master
的指針往前移動了,同樣HEAD
會跟隨master
往前移。我們把這個過程稱爲“快速前移”。
實際快速前移在合併操作裏是不友好的,我們打印log
,它這沒有任何信息(有關合並的信息)可以表示出來。
那如何解決呢?
2. 3. 1 --no-ff
禁止快速前移(可以commit
記錄描述爲合併操作)
我們回退回去!
git merge --no-ff -m '這是一次合併操作' branch1
(要加描述)
2. 3. 2 模擬快速前移
3. 分支衝突
3. 1 分叉衝突
初始化git倉庫
創建並切換一個分支
修改a文件,並提交
切換成master
主線,a.txt
內容爲空,因爲提交也分先後,在master
中只是新建了a.txt
,在branch1
裏才修改了內容。然後切換回master
,會重置工作目錄。我們添加1.txt
的內容。
提交它!
我們把branch1
合併過來,發現衝突報錯了。
我們打開a.txt
<<<<<<< HEAD
master
添加的內容,截止到分隔符
=======
分隔符
>>>>>>> branch1
從分隔符到當前,是branch1
添加的內容
<<<<<<< HEAD
1
2
3
4
5
第二次修改
=======
a
b
c
第1次修改
>>>>>>> branch1
想要解決衝突,打開文本,可將內容合併或刪除後不需要的內容,再提交即可,這裏我們只保留master
添加的內容。
3. 2 快速前移
有的時候修改,不會產生衝突。
我們新建並提交一個b文件
添加內容,並提交
再開一個分支branch2
,對b進行修改!再提交。
切換到master
再合併
提示Fast-forward
(快速前移),並沒有產生衝突!
3. 3 如何判斷是否會引起衝突
3. 3. 1 快速前移不會引起衝突
如上master
第1次提交:新建文件並添加內容
再創建分支,修改文件中的內容
最後切換到master
合併分支,合併之前,git會判斷兩個分支是什麼關係?如果是祖先級關係,master
和branch2
處於同一條commit
路徑上(直接級祖先關係),就進行了快速前移。
✔️ master
和branch2
直接進行合併,不會引起衝突
3. 3. 2 分叉衝突可能會引起衝突
如上上面的操作是,master
第1次提交:新建文件並創建並切換分支,添加文件中的內容
再切換回master
,修改文件中的內容,提交之後最後進行合併。這時候出現了分叉,則不會進行快速平移了,git進行如下的分支判斷:
❌
- 分析
master
和branch1
中的修改是否一致,如果一致合併將會成爲一次空合併(因爲內容完全一致,沒有合併的需要) - 如果不一致,是否修改的同一個文件內容,如果是,產生衝突
4. 解決分支衝突
解決分支衝突:
① 手動解決衝突部分
② 解決完成後再次提交,會以這次提交內容爲準
5. 刪除分支
合併完成後,分支就沒有任何的後期用途了,這時候我們需要手動刪除分支,以防止自己詞窮的時候出現重複命名分支的情況。
git branch -d 分支名稱
-d -> delete
5. 1 無法刪除的分支
注意:HEAD
所指向的分支,無法刪除
還有一種情形也無法刪除:
如果你的分支,從未合併:git branch -D 分支名稱
切換回master
,再刪除分支,都失敗了。提示從來沒合併過的分支,git會提示你是否真的要刪除一個分支。它防止我們刪錯分支,導致分支上的內容丟失。
這個時候就需要強制刪除分支命令了。
git branch -D branch3
6. 取消合併
git merge --abort
修改文件內容
切換回master
,再修改內容,提交合並
合併必然失敗
可以取消合併!
git merge --abort
日誌也不會提示進行過合併操作。
7. 撤銷合集
7. 1 撤銷上一次添加暫存區的內容
7. 1. 1 git rm --cached
我們參考上面提示說明:git rm --cached <file>
將暫存區文件變爲未追蹤狀態(刪除暫存區
或分支
上的文件, 但本地又需要使用),這其實就是一種撤銷
7. 1. 2 將文件內容手動修改回之前的狀態
修改a.txt
的內容
我們再把文件中的內容清空
7. 3 git checkout – 撤銷對文件的修改
從先從緩存區中拉取版本還原,如果沒有再到版本庫中拉取還原。參考廖雪峯老師的官網如下:
修改文件內容。
7. 4 取消暫存
7. 4. 1 git reset HEAD
git reset HEAD <file>
修改a.txt
本想分開提交,但是一不小心全部放到了暫存區
如果提交的話,兩個文件都得提交
那我們嘗試 git rm --cached a.txt
刪除暫存區
或分支
上的文件, 但將本地文件留存
我們發現,也無法提交,這裏git會幫我們重命名了,完全不符合我們的需求。我們需求是僅僅提交b.txt
。
我們還是回到原來的狀態,把a.txt
添加回暫存區
git reset HEAD a.txt
注意:當一個文件第一次進入暫存區實際上無需用reset
命令的,直接remove
就行,因爲暫存區沒有其之前的信息。
假設我們當前提交的記錄寫錯了怎麼整?請看下面的內容。
7. 5 撤銷上一次提交信息
7. 5. 1 git commit --amend
7. 5. 1. 1 修改提交信息
git commit -m '新建一個文件b,a文件待提交' --amend
注意:上次commit
提交錯後,不能再執行任何操作,必須緊接着它執行我們上面的修改提交信息命令纔行。
7. 5. 1. 2 修正緊挨着的一次的提交與本次提交合並
我們再修改b文件
我們本想將a、b文件一起提交,結果只提交了a文件
我們把b文件也加入暫存區,再修正合併上次提交
我們可以補充記錄!
8. reset使用
8. 1 git reset HEAD
撤銷我們提交最新的一次提交
git reset HEAD^
如果撤銷最新的兩次提交
git reset HEAD^^
如果撤銷最新的三次提交
git reset HEAD^^^
git reset HEAD^
可能有的編譯器,會提示More
,是因爲windows將其認爲是換行符了,所有加上"…"即可
解決:
迴歸正題,看下日誌
提交內容
撤銷兩次提交
注意:該提交併未丟失,可以通過哈希找回。
8. 1. 1 多條回退
git reset HEAD~n
n代表最近刪除的條數
8. 1. 2 git reset --hard (儘量避免使用)
重置工作目錄,丟失暫存:
git reset --hard
(儘量避免使用)
修改了a.txt
git reset HEAD^ --hard
並且發現一個問題,對a.txt的修改沒有了。
因此儘量避免使用--hard
,丟失的暫存,是不能找回的。
8. 1. 3 git reset --soft(建議使用)
git reset --soft
保留工作目錄,與原分支差異將放到暫存區
撤銷回去
我們打開a.txt
,也很容易發現,之前裏寫的內容,是不存在的,因爲丟失的內容,是找不回的,因此建議儘量避免使用--hard
。
git reset HEAD^ --soft
並且發現暫存區文件內容還在!因此它不會造成文件的丟失。
8. 1. 4 git reset --mixed(默認)
git reset --mixed(默認)
這是默認的,平時直接reset就是這種命令了。
保留工作目錄,並且清空暫存區
8. 2 通過哈希找回歷史記錄
git reset cc12a6c13af1f5b135f531617b0ce346bb8d46ca
但是如果沒有打印日誌,不知道哈希,如何回退呢?
8. 3 查看歷史提交記錄
git reflog
我們回到三次提交的日誌。
git reset 4180e8e
9. reset與checkout本質
可以用來撤銷commit
,但實質行爲上並不是撤銷操作,而是移動HEAD
並且帶上所指向的分支,重置HEAD
及分支
即在HEAD
之後的提交,因爲當前不在任何分支上,就不會出現在工作目錄中,起到撤銷效果。
9. 1 reset過程分析
假設進行c1
、c2
、c3
次提交,從c3
回退到c2
,實際上就是HEAD
帶上master
一塊移動到c2
,此時c3
就不在任何分支上了。因此打印log
,就看不到c3
了。如果想找回的話,即可通過reset
重置回c3
,即HEAD
帶上master
一塊移動到c3
。
9. 2 checkout過程對比
撤銷除了reset
,checkout
也與它類似,但是兩者也是不一樣的,之前我們學習發現。checkout
一般撤銷的是對文件的修改,它前提是沒有加入暫存區或者沒有提交的內容。
如果我們用checkout
完成上述分析,從c3
回退到c2
,實際HEAD
指向了c2
,而master
沒有變化,打印log
的時候,一切照舊。因此我們才用checkout
切換分支,因爲checkout
不會偏移master
(分支)指針。
所以,簽出指定commit
,只會改變HEAD
指向,並不會影響分支指向。
(後續待補充)