1. 程式人生 > >git分支間切換注意點和bug分支的處理

git分支間切換注意點和bug分支的處理

[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@