git stash pop時的衝突解決
今天遇到一個問題,本來在主分支上checkout了一條新分支出來工作,可是做一半的時候突然發現後續要做的東西依賴於另一條特性分支裏面的代碼。特性分支其實是已經推送到遠程並且提交合並請求了,但是並沒有及時合入。所以跟老大溝通了一下,先把遠程的特性分支合入主分支,我本地再rebase一下最新的主分支。可是因爲功能才完成一半,並不屬於一個完整的commit,所以我先把代碼用git stash存了起來。本地rebase完執行git stash pop的時候就出現了衝突。因爲以前從來沒有遇到過這種情況,所以一時不知道怎麼處理比較好。網上查了資料,發現上面的做法不是很好,所以自己嘗試着把問題處理了。
幹講命令的話估計不好理解,下面我通過一個例子來演示一下整個衝突出現和解決的過程。由於只是展示怎麼解決衝突,不涉及具體生產時的工作流程,所以就直接在本地進行了。本文爲了儘可能地把問題講清楚,手動復現了衝突,所以冗餘的內容較多,可能對於Git老手來說顯得有點囉嗦,如果想直接看結論,請直接跳轉到第六步。
第一步,我們先做好準備工作,初始化一個版本倉庫,新建一個文件test並且提交,作爲master分支上的根commit:
$ git init
$ touch test
$ git add test
$ git commit -m "init test"
[master (root-commit) c1f4cda] init test
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 test
$ git log
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2 (HEAD -> master)
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第二步,切換到另一條分支上工作,新建另一個文件anothertest並提交commit,代表在新分支上的某個工作階段的成果:
$ git checkout -b another
Switched to a new branch 'another'
$ touch anothertest
$ git add anothertest
$ git commit -m "init anothertest"
[another 66966d5] init anothertest
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 anothertest
$ git log
commit 66966d50a3128771bf70c06ab2b6bd05ef748337 (HEAD -> another)
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:14:56 2017 +0800
init anothertest
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2 (master)
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第三步,在another分支上修改test和anothertest文件的內容,使用git stash進行暫存,代表工作一半的成果,無法作爲一個完整的commit進行提交:
$ vim test
$ vim anothertest
$ git stash
Saved working directory and index state WIP on another: 66966d5 init anothertest
$ git stash list
stash@{0}: WIP on another: 66966d5 init anothertest
第四步,回到master分支,修改test文件並提交commit,模擬master分支出現了another分支需要使用的代碼。這個時候分支樹出現了分叉,master分支和another分支各自往前進行了一個commit:
$ git checkout master
Switched to branch 'master'
$ vim test
$ git add test
$ git commit -m "changes on branch master"
[master 9bc290f] changes on branch master
1 file changed, 1 insertion(+)
$ git log
commit 9bc290f5b6cea5757e01af64ea8c2591c9debdf9 (HEAD -> master)
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:18:11 2017 +0800
changes on branch master
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第五步,再回到another分支,使用git rebase進行變基,模擬another分支取得master分支上的最新代碼,這時分支樹又變成了一條直線:
$ git checkout another
Switched to branch 'another'
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: init anothertest
$ git log
commit 0687e2a2f0d243a725de6093d9f42de5ab02acfd (HEAD -> another)
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:14:56 2017 +0800
init anothertest
commit 9bc290f5b6cea5757e01af64ea8c2591c9debdf9 (master)
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:18:11 2017 +0800
changes on branch master
commit c1f4cdac5e3ede10a995c42b9c1d5b490b0d09a2
Author: ganziqim <[email protected]>
Date: Mon Nov 13 14:14:01 2017 +0800
init test
第六步,事情進展到目前來看,都非常順利,特性分支成功地取得了主分支上需要用到的代碼。但是當我們執行git stash pop想取出之前工作一半的成果之後,卻出現了衝突,其原因是主分支上的最新代碼和stash暫存的代碼對同一個文件都進行了修改。
$ git stash pop
Auto-merging test
CONFLICT (content): Merge conflict in test
$ git status
On branch another
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: anothertest
Unmerged paths:
(use "git reset HEAD <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: test
用git status查看狀態的時候,可以看到Git是有標出衝突的文件的,是不是很熟悉呢?對,這個時候先按照解決普通的pull conflict的方式修改文件,然後執行git add。如果完全接受主分支的修改,那麼再次查看git status的時候這個文件應該不會再出現在狀態裏了,但這裏我們模擬的是衝突兩邊的修改我們都想保留的情況。這時候代表你個人已經接受當前的衝突解決了,Git會把修改完的結果包括其它沒有出現衝突的文件放入暫存區。
$ vim test
$ git add test
$ git status
On branch another
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
modified: anothertest
modified: test
其實事情進行到上面那一步已經算作解決了,可是有時候你並不想把這些文件中的某一個作爲下個commit的內容提交到遠程,所以此時再執行一次git reset HEAD,就恢復git stash pop後該有的狀態了。
$ git reset HEAD
Unstaged changes after reset:
M anothertest
M test
$ git status
On branch another
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: anothertest
modified: test
no changes added to commit (use "git add" and/or "git commit -a")
需要注意的是,衝突解決之後,Git並不會刪除之前的stash記錄,可以使用git stash drop將沒用的記錄刪除掉。
$ git stash list
stash@{0}: WIP on another: 66966d5 init anothertest
$ git stash drop stash@{0}
Dropped stash@{0} (113018d1c2be77ffae51afc15944d8620619ef7d)
$ git stash list
總結
Git屬於越用越順手的東西,並且有很多實用的騷操作技巧,所以建議大家平時多多練習,沒事多搗鼓搗鼓,熟能生巧嘛!而且我是推薦直接使用命令行的,GUI工具雖然方便,但有時候處理問題的速度跟不上思維,而使用命令行更順手,尤其是專注工作,腦子快速運轉的時候。相信你會愛上那種感覺的!
————————————————
版權聲明:本文爲CSDN博主「GanZiQim」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/jy692405180/article/details/78520251
另外的方法參考這篇文章,也是我經常用的方法,比較笨~