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

備註:

本文參考於廖雪峰老師的部落格Git教程。依照其部落格進行學習和記錄,感謝其無私分享,也歡迎各位查看原文。

知識點

  • 當前一個分支上修改文件或目錄後,在沒有提交前,任何一個分支的狀態(git status)都會同步為一樣

  • 合併或切換分支工作,一定是在當前分支提交後,或者使用git stash將當前暫存區狀態保存下來之後進行,即當前分支git status顯示為乾淨的倉庫再切換

  • 同時修改了同一個工作區相同文件,由於Git管理版本是通過移動HEAD指針,工作區的修改對於移動到不同分支的指針是一樣的。此時masterdev分支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狀態,乾淨工作區

$ git status
位於分支 dev
無文件要提交,乾淨的工作區
$ git checkout master
切換到分支 'master'
您的分支領先 'origin/master' 共 8 個提交。
  (使用 "git push" 來發布您的本地提交)
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
  (使用 "git push" 來發布您的本地提交)
無文件要提交,乾淨的工作區
  • master分支下,修改readme文件,查看狀態,和切換到dev分支下,查看狀態。忽略遠程分支的提示。
$ 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指針,工作區的修改對於移動到不同分支的指針是一樣的。此時masterdev分支git add添加到暫存區,git status在不同分支狀態是一樣的,如果master分支先commit,中間所做的修改,會全部算作master的修改(由於dev沒有提交,僅僅add添加了暫存區,中間的修改在切換分支提交後會在dev分支丟失,但所有修改都存在於master的提交中)。故:實際開發中一定要提交或者暫存當前暫存區的狀態後,再切換分支進行其他修改,否則在本分支所做修改的狀態會丟失。

同理,合併分支也一樣,必須在提交或者暫存當前暫存區狀態後,再進行分支的合併。

如下為修改工作區或添加到暫存區後對git分支切換和提交的整體測試:

  • 如下, master分支上修改readme,查看狀態,
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
  (使用 "git push" 來發布您的本地提交)
尚未暫存以備提交的變更:
  (使用 "git add <文件>..." 更新要提交的內容)
  (使用 "git checkout -- <文件>..." 丟棄工作區的改動)
	修改:     readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
  • 切換到dev查看狀態,
$ git checkout dev
M	readme.txt
切換到分支 'dev'
$ git status
位於分支 dev
尚未暫存以備提交的變更:
  (使用 "git add <文件>..." 更新要提交的內容)
  (使用 "git checkout -- <文件>..." 丟棄工作區的改動)
	修改:     readme.txt
修改尚未加入提交(使用 "git add" 和/或 "git commit -a")
  • dev分支上修改readme文件,切換到master分支,查看內容
$ 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分支上將修改添加到暫存區,查看狀態
$ git add readme.txt
$ git status
位於分支 master
您的分支領先 'origin/master' 共 8 個提交。
  (使用 "git push" 來發布您的本地提交)
要提交的變更:
  (使用 "git reset HEAD <文件>..." 以取消暫存)
	修改:     readme.txt
  • 切換到dev分支,修改readme文件後,切換回master分支,查看狀態。會出現工作區的修改提示
$ 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添加在存儲區後,查看狀態,狀態為暫存(未提交)
$ git checkout dev
M	readme.txt
切換到分支 'dev'
$ git add readme.txt
$ git status
位於分支 dev
要提交的變更:
  (使用 "git reset HEAD <文件>..." 以取消暫存)
	修改:     readme.txt
  • 切換回master分支,git status查看狀態也為暫存(未提交)
$ 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分支提交,查看狀態,顯示無文件要提交,工作區乾淨
$ git commit -m"commit master"
[master 1ba95a4] commit master
 1 file changed, 2 insertions(+)
$ git status
位於分支 master
您的分支領先 'origin/master' 共 9 個提交。
  (使用 "git push" 來發布您的本地提交)
無文件要提交,乾淨的工作區
  • 切換到dev分支,工作區狀態為乾淨,暫存區無提交,如下。
$ git checkout dev
切換到分支 'dev'
$ git status
位於分支 dev
無文件要提交,乾淨的工作區
  • 此時,分別在masterdev分支先查看readme文件內容

dev分支,顯示為所有改動之前的內容

master分支下的readme文件內容為最新(包含在dev分支下修改和添加到暫存區的內容)

超前提交的分支無法合併落後版本的分支(即無法倒退到未提交過的分支狀態)

目前所知,依靠分支之間的合併(merge)無法實現版本倒退(也許有辦法,未進行深入研究),只能通過git reset --hard commit_id實現版本回退。

master上新建分支dev,然後修改master上內容,並添加提交,此時master的版本比dev版本要高,如果此時想把dev(分支的低版本)合併到master上會發生什麼呢?

  • master如果更新後(更新後的上游分支),試圖將未進行更新的dev分支合併到當前分支,會提示必須給出一個提交資訊解釋此合併,否則會終止合併提交

倒退合併master分支到dev分支提示

輸入合理解釋後,會再一次確認存儲緩衝區的更改

倒退合併master分支到dev分支再次確認

倒退合併master分支到dev分支確認後提示寫入格式

倒退合併master分支到dev分支確認提示寫入格式詢問是否新建一個文件存儲合併資訊

如下為操作完成後的終端狀態

$ 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參數,使用普通模式合併,如下:
$ git merge --no-ff -m"merge backup" dev
Already up-to-date.

文件內容依然保持和master一致,沒有合併到dev分支狀態。

解決:使用版本回退git reset --hard commit_id,可以完成實際的修改。

$ git reset --hard a7d3eb7
HEAD 現在位於 a7d3eb7 fixed conflict

內容修改。

bug分支

有了上面切換分支和合併失敗的經歷,就不難理解下面的操作了。

軟體開發中,bug總是在你想到和想不到的正常情況和意外情況下出現。修復bug,在Git中完全可以通過建立一個臨時分支來修復,修復後合併分支即可。

但是當你正在開發時,對於突然接到一個修復bug的任務,由於當前開發(dev分支)沒有完成,dev上的工作可能還沒有提交。

此時如果想創建一個臨時分支issue10修復master分支的bug

查看Git狀態如下:

$ git status
位於分支 dev
要提交的變更:
  (使用 "git reset HEAD <文件>..." 以取消暫存)

	新文件:   newFile

尚未暫存以備提交的變更:
  (使用 "git add <文件>..." 更新要提交的內容)
  (使用 "git checkout -- <文件>..." 丟棄工作區的改動)

	修改:     readme.txt

由於沒有開發完,可能暫時無法提交

暫存當前暫存區的狀態

  • Git提供了一個stash功能,可以把當前暫存區工作狀態「儲藏」起來,等以後恢復現場後繼續工作。
$ git stash
Saved working directory and index state WIP on dev: 0df6e43 Merge branch 'dev'
HEAD 現在位於 0df6e43 Merge branch 'dev'
  • 查看狀態,顯示無文件要提交,工作區也是乾淨的。
$ git status
位於分支 dev
無文件要提交,乾淨的工作區

註:git stash對於git沒有管理的文件狀態不會保存(新創建沒有添加過的文件)。

  • 確定從哪個分支上修復bug,現在在master分支上修復,切換並新建分支issue10
$ 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,提交

$ git add readme.txt
$ git commit -m"fixed a bug"
[issue10 afc33ef] fixed a bug
 1 file changed, 1 insertion(+), 1 deletion(-)

切換到master分支併合並。最後刪除issue10分支

$ 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的狀態是乾淨的。

$ git checkout dev
切換到分支 'dev'
$ git status
位於分支 dev
無文件要提交,乾淨的工作區
  • 使用git stash list查看暫存的狀態
$ git stash list
stash@{0}: WIP on dev: 0df6e43 Merge branch 'dev'

恢復暫存起來的狀態

  • git stash apply恢復,但恢復後,stash內容並不刪除,需要用git stash drop來刪除

  • 使用git stash pop,恢復的同時會把stash內容也刪除。

$ 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指定恢復到哪個狀態

$ git stash apply stash@{0}