git分支間切換注意點和bug分支的處理
阿新 • • 發佈:2020-07-17
[toc]
## 備註:
本文參考於廖雪峰老師的部落格[Git教程](https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000)。依照其部落格進行學習和記錄,感謝其無私分享,也歡迎各位檢視原文。
## 知識點
- 當前一個分支上修改檔案或目錄後,在沒有提交前,任何一個分支的狀態(`git status`)都會同步為一樣
- 合併或切換分支工作,一定是在當前分支提交後,或者使用`git stash`將當前暫存區狀態儲存下來之後進行,即當前分支`git status`顯示為乾淨的倉庫再切換
- 同時修改了同一個工作區相同檔案,由於Git管理版本是通過移動`HEAD`指標,工作區的修改對於移動到不同分支的指標是一樣的。此時`master`和`dev`分支`git add`新增到暫存區,`git status`在不同分支狀態是一樣的,如果`master`分支先`commit`,中間所做的修改,會全部算作`master`的修改(由於`dev`沒有提交,僅僅`add`添加了暫存區,中間的修改在切換分支提交後會在`dev`分支丟失,但所有修改都存在於`master`的提交中)。故:**實際開發中一定要提交或者暫存當前暫存區的狀態後,再切換分支進行其他修改,否則在本分支所做修改的狀態會丟失。**
- `git stash`對於`git`沒有管理的檔案狀態不會儲存(新建立或修改沒有新增過的檔案)。
- `git stash list`檢視`stash`的列表
- `git stash pop`恢復`stash`到當前分支,並刪除`stash`
- `git stash apply`,`git stash drop`恢復`stash`和刪除`stash`
- `git stash apply stash@{0}`恢復指定的`stash`到當前分支。
## 記一次分支合併問題狀況
### 從分支點開始,不同分支修改工作區的內容(不新增到暫存區和提交),切換分支,工作區的內容是一樣的。
這一點也證明了,Git修改的是`HEAD`指標,而不是檔案
如下:
- -`git status`檢視`dev`分支上Git的狀態,乾淨工作區
- 切換到mster,檢視Git狀態,乾淨工作區
```s
$ git status
位於分支 dev
無檔案要提交,乾淨的工作區
$ git checkout master
切換到分支 'master'
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
無檔案要提交,乾淨的工作區
```
- master分支下,修改readme檔案,檢視狀態,和切換到dev分支下,檢視狀態。忽略遠端分支的提示。
```s
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
$ git checkout dev
M readme.txt
切換到分支 'dev'
$ git status
位於分支 dev
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
```
### 必須在提交或者暫存當前暫存區的狀態後,再切換或合併分支
工作區的修改對於不同分支是一樣的:
> 同時修改了同一個工作區相同檔案,由於Git管理版本是通過移動`HEAD`指標,工作區的修改對於移動到不同分支的指標是一樣的。此時`master`和`dev`分支`git add`新增到暫存區,`git status`在不同分支狀態是一樣的,如果`master`分支先`commit`,中間所做的修改,會全部算作`master`的修改(由於`dev`沒有提交,僅僅`add`添加了暫存區,中間的修改在切換分支提交後會在`dev`分支丟失,但所有修改都存在於`master`的提交中)。故:**實際開發中一定要提交或者暫存當前暫存區的狀態後,再切換分支進行其他修改,否則在本分支所做修改的狀態會丟失。**
>
> 同理,合併分支也一樣,必須在提交或者暫存當前暫存區狀態後,再進行分支的合併。
如下為修改工作區或新增到暫存區後對git分支切換和提交的整體測試:
- 如下, `master`分支上修改`readme`,檢視狀態,
```s
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
```
- 切換到`dev`檢視狀態,
```s
$ git checkout dev
M readme.txt
切換到分支 'dev'
$ git status
位於分支 dev
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
```
- 在`dev`分支上修改`readme`檔案,切換到`master`分支,檢視內容
```s
$ git checkout master
M readme.txt
切換到分支 'master'
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
$ cat readme.txt
`this is a test that I learning and use git version control system
this is a beginning
wofaidognyixie dognxi
create two new branch
Creating a new branch is quick and simple.
add a new branch
master modify
dev modify
```
- 在`master`分支上將修改新增到暫存區,檢視狀態
```s
$ git add readme.txt
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
要提交的變更:
(使用 "git reset HEAD <檔案>..." 以取消暫存)
修改: readme.txt
```
- 切換到`dev`分支,修改`readme`檔案後,切換回`master`分支,檢視狀態。會出現工作區的修改提示
```s
$ git checkout dev
M readme.txt
切換到分支 'dev'
$ git checkout master
M readme.txt
切換到分支 'master'
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
要提交的變更:
(使用 "git reset HEAD <檔案>..." 以取消暫存)
修改: readme.txt
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: readme.txt
```
- 切換回`dev`分支,`git add`新增在儲存區後,檢視狀態,狀態為暫存(未提交)
```s
$ git checkout dev
M readme.txt
切換到分支 'dev'
$ git add readme.txt
$ git status
位於分支 dev
要提交的變更:
(使用 "git reset HEAD <檔案>..." 以取消暫存)
修改: readme.txt
```
- 切換回`master`分支,`git status`檢視狀態也為暫存(未提交)
```s
$ git checkout master
M readme.txt
切換到分支 'master'
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
liu@liu-virtual-machine:~/gitTest$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
(使用 "git push" 來發布您的本地提交)
要提交的變更:
(使用 "git reset HEAD <檔案>..." 以取消暫存)
修改: readme.txt
```
- 在`master`分支提交,檢視狀態,顯示無檔案要提交,工作區乾淨
```s
$ git commit -m"commit master"
[master 1ba95a4] commit master
1 file changed, 2 insertions(+)
$ git status
位於分支 master
您的分支領先 'origin/master' 共 9 個提交。
(使用 "git push" 來發布您的本地提交)
無檔案要提交,乾淨的工作區
```
- 切換到`dev`分支,工作區狀態為乾淨,暫存區無提交,如下。
```s
$ git checkout dev
切換到分支 'dev'
$ git status
位於分支 dev
無檔案要提交,乾淨的工作區
```
- 此時,分別在`master`和`dev`分支先檢視`readme`檔案內容
**`dev`分支,顯示為所有改動之前的內容**
**`master`分支下的`readme`檔案內容為最新(包含在`dev`分支下修改和新增到暫存區的內容)**
### 超前提交的分支無法合併落後版本的分支(即無法倒退到未提交過的分支狀態)
目前所知,依靠分支之間的合併(merge)無法實現版本倒退(也許有辦法,未進行深入研究),只能通過`git reset --hard commit_id`實現版本回退。
在`master`上新建分支`dev`,然後修改`master`上內容,並新增提交,此時`master`的版本比`dev`版本要高,如果此時想把`dev`(分支的低版本)合併到`master`上會發生什麼呢?
- `master`如果更新後(更新後的上游分支),試圖將未進行更新的`dev`分支合併到當前分支,會提示必須給出一個提交資訊解釋此合併,否則會終止合併提交
![倒退合併master分支到dev分支提示](https://img2020.cnblogs.com/blog/1108935/202007/1108935-20200715204400420-1080590365.png)
輸入合理解釋後,會再一次確認儲存緩衝區的更改
![倒退合併master分支到dev分支再次確認](https://img2020.cnblogs.com/blog/1108935/202007/1108935-20200715204400088-1154070357.png)
![倒退合併master分支到dev分支確認後提示寫入格式](https://img2020.cnblogs.com/blog/1108935/202007/1108935-20200715204359766-1911910661.png)
![倒退合併master分支到dev分支確認提示寫入格式詢問是否新建一個檔案儲存合併資訊](https://img2020.cnblogs.com/blog/1108935/202007/1108935-20200715204359264-758215315.png)
如下為操作完成後的終端狀態
```s
$ git merge dev
Merge made by the 'recursive' strategy.
testOndev.txt | 0
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 testOndev.txt
```
但是檢視檔案內容,並沒有回到原先狀態。
**倒退合併失敗,其實這種情況應該使用版本回退**。
- 即使使用`--no-ff`引數,使用普通模式合併,如下:
```s
$ git merge --no-ff -m"merge backup" dev
Already up-to-date.
```
檔案內容依然保持和master一致,沒有合併到dev分支狀態。
解決:使用版本回退`git reset --hard commit_id`,可以完成實際的修改。
```s
$ git reset --hard a7d3eb7
HEAD 現在位於 a7d3eb7 fixed conflict
```
內容修改。
## bug分支
有了上面切換分支和合並失敗的經歷,就不難理解下面的操作了。
軟體開發中,`bug`總是在你想到和想不到的正常情況和意外情況下出現。修復`bug`,在Git中完全可以通過建立一個臨時分支來修復,修復後合併分支即可。
但是當你正在開發時,對於突然接到一個修復`bug`的任務,由於當前開發(`dev`分支)沒有完成,`dev`上的工作可能還沒有提交。
此時如果想建立一個臨時分支`issue10`修復`master`分支的`bug`。
檢視Git狀態如下:
```s
$ git status
位於分支 dev
要提交的變更:
(使用 "git reset HEAD <檔案>..." 以取消暫存)
新檔案: newFile
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: readme.txt
```
由於沒有開發完,可能暫時無法提交
### 暫存當前暫存區的狀態
- Git提供了一個`stash`功能,可以把當前暫存區工作狀態“儲藏”起來,等以後恢復現場後繼續工作。
```s
$ git stash
Saved working directory and index state WIP on dev: 0df6e43 Merge branch 'dev'
HEAD 現在位於 0df6e43 Merge branch 'dev'
```
- 檢視狀態,顯示無檔案要提交,工作區也是乾淨的。
```s
$ git status
位於分支 dev
無檔案要提交,乾淨的工作區
```
**注:`git stash`對於git沒有管理的檔案狀態不會儲存(新建立沒有新增過的檔案)。**
- 確定從哪個分支上修復`bug`,現在在`master`分支上修復,切換並新建分支`issue10`。
```s
$ git checkout master
切換到分支 'master'
您的分支領先 'origin/master' 共 13 個提交。
(使用 "git push" 來發布您的本地提交)
$ git checkout -b issue10
切換到一個新分支 'issue10'
$ cat readme.txt
`this is a test that I learning and use git version control system
this is a beginning
wofaidognyixie dognxi
create two new branch
Creating a new branch is quick and simple.
add a new branch
master modify
dev modify again commit on master
```
如上為readme內容,將`master modify`改為`modify on master`,提交
```s
$ git add readme.txt
$ git commit -m"fixed a bug"
[issue10 afc33ef] fixed a bug
1 file changed, 1 insertion(+), 1 deletion(-)
```
切換到`master`分支併合並。最後刪除`issue10`分支
```s
$ git checkout master
切換到分支 'master'
您的分支領先 'origin/master' 共 13 個提交。
(使用 "git push" 來發布您的本地提交)
$ git merge --no-ff -m"merged fixed bug" issue10
Merge made by the 'recursive' strategy.
readme.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue10
已刪除分支 issue10(曾為 afc33ef)。
```
`bug`修改完成後,現在回到`dev`分支接著開發,此時`dev`的狀態是乾淨的。
```s
$ git checkout dev
切換到分支 'dev'
$ git status
位於分支 dev
無檔案要提交,乾淨的工作區
```
- 使用`git stash list`檢視暫存的狀態
```s
$ git stash list
stash@{0}: WIP on dev: 0df6e43 Merge branch 'dev'
```
### 恢復暫存起來的狀態
- 用`git stash apply`恢復,但恢復後,`stash`內容並不刪除,需要用`git stash drop`來刪除
- 使用`git stash pop`,恢復的同時會把`stash`內容也刪除。
```s
$ git stash pop
位於分支 dev
要提交的變更:
(使用 "git reset HEAD <檔案>..." 以取消暫存)
新檔案: newFile
尚未暫存以備提交的變更:
(使用 "git add <檔案>..." 更新要提交的內容)
(使用 "git checkout -- <檔案>..." 丟棄工作區的改動)
修改: readme.txt
丟棄了 refs/stash@{0} (90a1bdda8ec2c4d1a2833b45ffa2a0be3f2af670)
```
可以多次`stash`,恢復的時候,先用`git stash list`檢視,然後用`git stash apply`指定恢復到哪個狀態
```s
$ git stash apply stash@