git 0基礎入門—git入門與實踐(3)—詳細圖解git分支操作及超詳細的解決分支衝突及reset和checkout原理深究和詳細操作

git入門與實踐(3)

1. 分支入門操作

  某天完成了項目的一次開發後,準備開始第二次開發,但是如果直接在一次開發的基礎上更改,我們的文件就是1+2,管理起來相當不方便。

1. 1 查看分支: git branch

  前面*代表當前所處的分支

image-20200630115535628

1. 2 創建分支:git branch 分支名稱

  創建出來的分支,並不會改變我們當前所在的位置。

git branch branch1

git branch

image-20200630115714216

  git是如何判斷我們所處當前哪個分支上呢?

  (HEAD -> master, branch1) git是通過HEAD指向獲取當前分支的。

image-20200630115835314

1. 3 切換分支:git checkout 分支名

  將HEAD指向切換的分支

  將工作目錄恢復成當前分支的快照

  簡寫命令:git checkout -b 分支名

image-20200630122154489

  之後提交一個文件,之後看日誌,發現HEAD已經指向branch1了。再往後仔細看標註,就是master分支的日誌了。

image-20200630122707791

  除此之外,如果是branch1分支,切換過去,只會顯示該分支所有的文件。

image-20200630123518902

image-20200630123505313

  切換master分支,則是它所有的文件。

image-20200630123533974

image-20200630124449317

  在branch1分支下刪除所有文件

  git rm * -r

image-20200630124132532

image-20200630124145865

  再切回去:

image-20200630124351654

  文件都在!因此各個分支是互不影響的!

1. 3. 1 分支流程詳解

  首先有一次c1的提交,在c1的基礎上還有c2的提交,這些操作都是在默認的master分支上進行的,在c2的提交上又創建新分支branch1。git如何判斷在當前在哪個分支上,就是通過HEAD指針。當前HEAD指向master

image-20200630125634988

  我們切換分支後,HEAD就指向branch1了。

image-20200630125740429

  我們再提交c3,此時branch1向前移動,並帶着HEAD一塊移動了。此時branch1的路線就是c1->c2->c3

image-20200630130034936

  此時我們想操作master分支,就需要切換過去了。

image-20200630130300992

  之後再進行c4提交。此時master的路線就是c1->c2->c4

image-20200630165248943

image-20200630130540706

1. 3. 1. 1 流程動態演示

2. 分支合併

  假如我們開始開發,基礎功能是c1提交和c2提交之間的內容,處理的是第一個版本的內容。

image-20200630153333597

  爲了便於後面的開發,我們將其分成兩個分支,一個master,一個branch1

image-20200630153356644

image-20200630153405315

  緊接着我們在分支branch1上開始開發,然後進行功能提升,進行第二個版本開發,提交c3c5

image-20200630153421423

  現在又出現了問題,第一個版本開發的時候,有一些小的bug。這個時候需要提交一些補丁,這可怎麼呢?首先需要回退到c2上,這上面有第一個版本開發的時候所有的記錄,這個時候我們實際不用回退。直接切換到master的分支,在這個分支修改bug並提交c4。這個時候就可以將c1->c2->c4的代碼進行打包,替換線上的代碼了。

image-20200630153434584

  第二個版本開發完成至c5提交。唯獨缺少了c4的補丁,你可能會想到再創建一個提交修改bug。明顯是不科學的,這樣重複處理,是非常耽誤時間和工作效率的。因此git就提供了一個很好用的功能,即合併分支。

  模擬一下以上操作,新建一個文件夾。

image-20200630154304428

image-20200630154311763

c1提交

image-20200630154401011

c2提交

image-20200630154346653

git checkout -b branch1 創建分支並使HEAD指向新分支,-b就代表 branch

image-20200630154458131

完成c3提交

image-20200630154716582

切換回master打補丁,c4提交

image-20200630154858983

2. 1 HEAD查看命令

2. 1. 1 git log --decorate

--decorate 參數用來顯示一些相關的信息(帶有分支信息),如HEAD、分支名、tag名等

image-20200630155229540

2. 1. 2 git log --oneline --decorate

--oneline 校驗和(哈希)

  查看分支指向+哈希

  以上顯示不太明顯,我們可以該命令

image-20200630155627931

切換回branch1看看

image-20200630155853565

我們繼續提交c5

image-20200630160016535

image-20200630160051029

2. 1. 3 git log --oneline --decorate --all --graph

  查看命令的完美組合 —> 包含了所有分支的提交,以樹形圖形形式展現。

--all 所有分支信息

--graph 打印出樹形圖

image-20200630160143289

2. 2 git merge 分支合併

注意:在我們日常開發中最好必須有一個主分支,有一個主分支就利用我們對分支進行管理。比如平時打遊戲,就會有一個主線任務和一個支線任務。然後支線任務也不會影響主線,實際上項目中主線就是項目的版本。默認情形下,大家都把默認分支master作爲主分支。

git merge 目標分支

  將目標分支的內容合併到當前分支

image-20200630160943907

git merge branch1branch1分支合併到主分支master上來。

image-20200630161010099

image-20200630161135347

  此時完成了合併,解決了第二個版本中第一個版本的bug,我們想讓第二個版本上線,就打包c6代碼即可。

image-20200630161317364

2. 2. 1 模擬合併小結

  其實最終合併關注3個點,一個是必須有共同父節點c2,其次是master末尾節點c4brach末尾節點c5,將c4c5實際整合成了c6c6就完美解決了,第二個開發版本c2->c3->c5中需要修復第一個開發版本bug的問題了。

2. 3 快速前移

  當masterbranch沒有形成分叉,依舊是處於一條路徑線,當HEAD落後於所要合併的分支,將會形成快速前移

  先初始化目錄

image-20200630165623735

  進行兩次提交

image-20200630165809901

  創建分支branch1,並切換過去,做第三次提交

  git checkout -b branch1

image-20200630170029685

git log --oneline --decorate --all --graph

image-20200630170215832

image-20200630171144789

切換到master,並與branch1合併

image-20200630171240557

image-20200630170412680

git log --oneline --decorate --all --graph

  我們發現了奇怪的問題,masterbranch1都跑到c3了。爲啥成這樣了, 因爲快速前移,我們仔細觀察上圖,就有提示:Fast-forward

image-20200630170457597

  仔細觀察上圖發現合併前並沒形成分叉,branch1只是在master的上開了一個分支。

master:c1->c2

branch1:c1->c2->c3

  master上的提交都包括在branch1裏了,這時執行的合併就和之前不一樣了,不會出現新的提交,而是將master的指針往前移動了,同樣HEAD會跟隨master往前移。我們把這個過程稱爲“快速前移”。

image-20200630171357291

  實際快速前移在合併操作裏是不友好的,我們打印log,它這沒有任何信息(有關合並的信息)可以表示出來。

image-20200630182842189  那如何解決呢?

2. 3. 1 --no-ff

  禁止快速前移(可以commit記錄描述爲合併操作)

  我們回退回去!

image-20200630183659778

image-20200630183638221

git merge --no-ff -m '這是一次合併操作' branch1 (要加描述)

image-20200630184018334

image-20200630184035268

image-20200630184109198

2. 3. 2 模擬快速前移

3. 分支衝突

3. 1 分叉衝突

  初始化git倉庫

image-20200630194716040

  創建並切換一個分支

image-20200630194837077

  修改a文件,並提交

image-20200630195055584

image-20200630195030727

  切換成master主線,a.txt內容爲空,因爲提交也分先後,在master中只是新建了a.txt,在branch1裏才修改了內容。然後切換回master,會重置工作目錄。我們添加1.txt的內容。

image-20200630200757949

image-20200630200740943

提交它!

image-20200630200909375

我們把branch1合併過來,發現衝突報錯了。

image-20200630201019500

我們打開a.txt

image-20200630201105508

<<<<<<< HEAD master添加的內容,截止到分隔符

======= 分隔符

>>>>>>> branch1 從分隔符到當前,是branch1添加的內容

<<<<<<< HEAD
1
2
3
4
5
第二次修改
=======
a
b
c
第1次修改
>>>>>>> branch1

  想要解決衝突,打開文本,可將內容合併或刪除後不需要的內容,再提交即可,這裏我們只保留master添加的內容。

image-20200630201836938

image-20200630200740943

3. 2 快速前移

  有的時候修改,不會產生衝突。

  我們新建並提交一個b文件

image-20200630202532916

  添加內容,並提交

image-20200630202616546

image-20200630202744771

  再開一個分支branch2,對b進行修改!再提交。

image-20200630203218956

image-20200630203305572

  切換到master再合併

  提示Fast-forward(快速前移),並沒有產生衝突!

image-20200630203518373

image-20200630203218956

3. 3 如何判斷是否會引起衝突

3. 3. 1 快速前移不會引起衝突

  如上master第1次提交:新建文件並添加內容

  再創建分支,修改文件中的內容

  最後切換到master合併分支,合併之前,git會判斷兩個分支是什麼關係?如果是祖先級關係,masterbranch2處於同一條commit路徑上(直接級祖先關係),就進行了快速前移。

✔️ masterbranch2直接進行合併,不會引起衝突

image-20200630204554374

3. 3. 2 分叉衝突可能會引起衝突

  如上上面的操作是,master第1次提交:新建文件並創建並切換分支,添加文件中的內容

  再切換回master,修改文件中的內容,提交之後最後進行合併。這時候出現了分叉,則不會進行快速平移了,git進行如下的分支判斷:

image-20200630204956306

  1. 分析masterbranch1中的修改是否一致,如果一致合併將會成爲一次空合併(因爲內容完全一致,沒有合併的需要)
  2. 如果不一致,是否修改的同一個文件內容,如果是,產生衝突

4. 解決分支衝突

解決分支衝突:

​ ① 手動解決衝突部分

​ ② 解決完成後再次提交,會以這次提交內容爲準

5. 刪除分支

  合併完成後,分支就沒有任何的後期用途了,這時候我們需要手動刪除分支,以防止自己詞窮的時候出現重複命名分支的情況。

git branch -d 分支名稱 -d -> delete

image-20200630210133151

5. 1 無法刪除的分支

注意:HEAD所指向的分支,無法刪除

image-20200630210258162

還有一種情形也無法刪除:

如果你的分支,從未合併:git branch -D 分支名稱

image-20200630210533515

  切換回master,再刪除分支,都失敗了。提示從來沒合併過的分支,git會提示你是否真的要刪除一個分支。它防止我們刪錯分支,導致分支上的內容丟失。

image-20200630210720645

  這個時候就需要強制刪除分支命令了。

git branch -D branch3

image-20200630211050875

6. 取消合併

git merge --abort

image-20200630212032265

修改文件內容

image-20200630212054369

image-20200630212234574

切換回master,再修改內容,提交合並

image-20200630212357015

合併必然失敗

image-20200630212617697

image-20200630212655152

可以取消合併!

git merge --abort

image-20200630212805558

image-20200630212357015

  日誌也不會提示進行過合併操作。

image-20200630213037438

7. 撤銷合集

7. 1 撤銷上一次添加暫存區的內容

7. 1. 1 git rm --cached

image-20200630224042977

  我們參考上面提示說明:git rm --cached <file> 將暫存區文件變爲未追蹤狀態(刪除暫存區分支上的文件, 但本地又需要使用),這其實就是一種撤銷

image-20200630224433659

7. 1. 2 將文件內容手動修改回之前的狀態

image-20200630225137836

修改a.txt的內容

image-20200630225217946

image-20200630225330107

我們再把文件中的內容清空

image-20200630225405180

image-20200630230751919

7. 3 git checkout – 撤銷對文件的修改

  從先從緩存區中拉取版本還原,如果沒有再到版本庫中拉取還原。參考廖雪峯老師的官網如下:

修改文件內容。

image-20200630231118806

image-20200630231203805

image-20200630233205018

image-20200630225405180

7. 4 取消暫存

7. 4. 1 git reset HEAD

git reset HEAD <file>

image-20200630234308145

修改a.txt

image-20200630234349059

  本想分開提交,但是一不小心全部放到了暫存區

image-20200630234522281

  如果提交的話,兩個文件都得提交

  那我們嘗試 git rm --cached a.txt 刪除暫存區分支上的文件, 但將本地文件留存

image-20200630235035102

  我們發現,也無法提交,這裏git會幫我們重命名了,完全不符合我們的需求。我們需求是僅僅提交b.txt

  我們還是回到原來的狀態,把a.txt添加回暫存區

image-20200630235329759

git reset HEAD a.txt

image-20200630235809457

注意:當一個文件第一次進入暫存區實際上無需用reset命令的,直接remove就行,因爲暫存區沒有其之前的信息。

  假設我們當前提交的記錄寫錯了怎麼整?請看下面的內容。

image-20200701000308170

7. 5 撤銷上一次提交信息

7. 5. 1 git commit --amend

7. 5. 1. 1 修改提交信息

git commit -m '新建一個文件b,a文件待提交' --amend

注意:上次commit提交錯後,不能再執行任何操作,必須緊接着它執行我們上面的修改提交信息命令纔行。

image-20200701000308170

image-20200701001403170

7. 5. 1. 2 修正緊挨着的一次的提交與本次提交合並

image-20200701001141727

我們再修改b文件

image-20200701001446854

image-20200701001507257

我們本想將a、b文件一起提交,結果只提交了a文件

image-20200701001637991

我們把b文件也加入暫存區,再修正合併上次提交

image-20200701001950061

image-20200701002032968

我們可以補充記錄!

image-20200701002115263

image-20200701002153566

8. reset使用

8. 1 git reset HEAD

  撤銷我們提交最新的一次提交

git reset HEAD^

如果撤銷最新的兩次提交

git reset HEAD^^

如果撤銷最新的三次提交

git reset HEAD^^^

git reset HEAD^

image-20200701010208748

可能有的編譯器,會提示More ,是因爲windows將其認爲是換行符了,所有加上"…"即可

image-20200701010538724

解決:

image-20200701010605874

迴歸正題,看下日誌

image-20200701010709212

image-20200701010808598

提交內容

image-20200701093539835

撤銷兩次提交

image-20200701093629170

注意:該提交併未丟失,可以通過哈希找回。

8. 1. 1 多條回退

git reset HEAD~n n代表最近刪除的條數

image-20200701095229406

image-20200701095248358

8. 1. 2 git reset --hard (儘量避免使用)

重置工作目錄,丟失暫存:
git reset --hard (儘量避免使用)

修改了a.txt

image-20200701102747341

image-20200701102941378

git reset HEAD^ --hard

image-20200701103042287

並且發現一個問題,對a.txt的修改沒有了。

image-20200701103126737

image-20200701103205444

因此儘量避免使用--hard,丟失的暫存,是不能找回的。

8. 1. 3 git reset --soft(建議使用)

git reset --soft

  保留工作目錄,與原分支差異將放到暫存區


  撤銷回去

image-20200701103546623

  我們打開a.txt,也很容易發現,之前裏寫的內容,是不存在的,因爲丟失的內容,是找不回的,因此建議儘量避免使用--hard

image-20200701103813135

git reset HEAD^ --soft

並且發現暫存區文件內容還在!因此它不會造成文件的丟失。

image-20200701103929008

image-20200701103813135

8. 1. 4 git reset --mixed(默認)

git reset --mixed(默認) 這是默認的,平時直接reset就是這種命令了。

保留工作目錄,並且清空暫存區

8. 2 通過哈希找回歷史記錄

image-20200701094104112

git reset cc12a6c13af1f5b135f531617b0ce346bb8d46ca

image-20200701094123142

但是如果沒有打印日誌,不知道哈希,如何回退呢?

8. 3 查看歷史提交記錄

git reflog

image-20200701095407256

我們回到三次提交的日誌。

git reset 4180e8e

image-20200701095657346

9. reset與checkout本質

  可以用來撤銷commit,但實質行爲上並不是撤銷操作,而是移動HEAD並且帶上所指向的分支,重置HEAD及分支

  即在HEAD之後的提交,因爲當前不在任何分支上,就不會出現在工作目錄中,起到撤銷效果。

9. 1 reset過程分析

  假設進行c1c2c3次提交,從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指向,並不會影響分支指向。



(後續待補充)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章