今天恰巧遇到了須要回退分支的問題,我以前一直在用的都是git reset
,自認爲清楚明瞭,也就沒去看還有其餘的回退方法。今天突然被問到,特地查了查。git
develop ----1 3-----
\ /
branch a a
複製代碼
develop將a分支合併後,想要不留痕跡的撤回合併。這個時候用git reset
就是很好的選擇了。github
具體的操做步驟以下:緩存
例如個人日誌是這樣的:bash
commit 3
Merge 1 2
Author: admin <admin@163.com>
Date: Wed May 30 15:00:00 2018 +0800
Merge branch 'feature/a' into 'develop'
close a
See merge request !20
commit 2
Author: admin <admin@163.com>
Date: Wed May 30 14:00:00 2018 +0800
close a
commit 1
Author: admin <admin@163.com>
Date: Wed May 30 13:00:00 2018 +0800
init project
複製代碼
我要將develop回退到合併以前的狀態,那就是退到 commit 1這了,將commit號複製下來。退出編輯界面。服務器
--soft 回退後a分支修改的代碼被保留並標記爲add的狀態(git status 是綠色的狀態)
--mixed 重置索引,但不重置工做樹,更改後的文件標記爲未提交(add)的狀態。默認操做。
--hard 重置索引和工做樹,而且a分支修改的全部文件和中間的提交,沒提交的代碼都被丟棄了。
--merge 和--hard相似,只不過若是在執行reset命令以前你有改動一些文件而且未提交,merge會保留你的這些修改,hard則不會。【注:若是你的這些修改add過或commit過,merge和hard都將刪除你的提交】
--keep 和--hard相似,執行reset以前改動文件若是是a分支修改了的,會提示你修改了相同的文件,不能合併。若是不是a分支修改的文件,會移除緩存區。git status仍是能夠看到保持了這些修改。
複製代碼
a分支的代碼我不須要了,之後應該也不須要了。所以:測試
git reset 1(粘貼過來的commit號) --hard
spa
a分支代碼我仍是想要的,只是這個提交我不想要了: git reset 1
日誌
git log
查看一下:commit 1
Author: admin <admin@163.com>
Date: Wed May 30 13:00:00 2018 +0800
init project
複製代碼
是我想要的沒錯了,能夠push到遠端去了。(這一步很危險,必定要確認好reset的結果確實是你想要的結果,不然,丟失了代碼就不要怨我了)code
git push origin develop
索引
![rejected] develop -> develop (non-fast-forward)
error: 沒法推送一些引用到 'git@github.cn:...'
提示:更新被拒絕,由於您當前分支的最新提交落後於其對應的遠程分支。
。。。
複製代碼
好吧,個人分支確實落後於遠程的develop分支。我須要--force
。
git push origin develop --force
Total 0 (delta 0), reused 0 (delta 0)
To git@...
+ 83***...23***** develop -> develop (forced update)
複製代碼
能夠了,回到github查看network。嗯,就是想要這樣的。
仍是這個例子
develop ----1 3-----
\ /
branch a a
複製代碼
仍是以前的需求,不想要合併a,只想要沒合併a時的樣子。
操做步驟:
git checkout develop
git log
,仍是上面的日誌:commit 3
Merge 1 2
Author: admin <admin@163.com>
Date: Wed May 30 15:00:00 2018 +0800
Merge branch 'feature/a' into 'develop'
close a
See merge request !20
commit 2
Author: admin <admin@163.com>
Date: Wed May 30 14:00:00 2018 +0800
close a
commit 1
Author: admin <admin@163.com>
Date: Wed May 30 13:00:00 2018 +0800
init project
複製代碼
此次和git reset
不一樣的是我不能複製 commit 1
這個commit號了,我須要複製的是commit 2
的commit號。由於revert後面跟的是具體須要哪一個已經合併了的分支,而並非須要會退到哪的commit號。
git revert 2
Revert "close a"
This reverts commit 2
#.......
複製代碼
這是至關於又新增了一個commit,把a分支上的全部修改又改了回去。
git log
查看一下是否是我想的那樣
commit 4
Author: admin <admin@163.com>
Date: Wed May 30 17:00:00 2018 +0800
Revert "close a"
This reverts commit 2
commit 3
Merge 1 2
Author: admin <admin@163.com>
Date: Wed May 30 15:00:00 2018 +0800
Merge branch 'feature/a' into 'develop'
close a
See merge request !20
commit 2
....
複製代碼
確實是新增長了一個commit,查看代碼發現a分支的修改都不存在了,也達到了我想要的效果。
git push origin develop
查看network,是這樣的:
develop ----1 3-----revert a------
\ /
branch a a
複製代碼
如此看來,git reset
和git revert
都能實現我如今的需求,那這兩個到底有什麼區別呢,在網上查了這個問題,我以爲說的有些抽象,看的不是很明白,因而本身實踐了以後才明白。
git revert是用一次新的commit來回滾以前的commit,git reset是直接刪除指定的commit。
這個很好理解,在剛纔的操做中咱們看日誌已經能夠看到這個現象。
git reset
操做以後,咱們查看上面例子的network已經能夠看到network中只有commit 1
,分支a
和合併分支後的commit 3
都消失了;
git revert
操做以後,network中仍是能夠看到a分支和合並a分支的操做,只不過在其基礎上又增長了一個revert的commit而已。
git reset 是把HEAD向後移動了一下,而git revert是HEAD繼續前進,只是新的commit的內容和要revert的內容正好相反,可以抵消要被revert的內容。
這個也是能夠清晰明瞭的看到,我就不作過多的解釋了
在回滾這一操做上看,效果差很少。可是在往後繼續merge之前的老版本時有區別。由於git revert是用一次逆向的commit「中和」以前的提交,所以往後合併老的branch時,致使這部分改變不會再次出現,可是git reset是之間把某些commit在某個branch上刪除,於是和老的branch再次merge時,這些被回滾的commit應該還會被引入。
如今的需求是我以前已經把a分支revert了,可是我如今又須要a分支的代碼了,我以前都寫過一遍總不能再從新寫一遍了。我首先想到的方法,把a分支再merge到develop不就行了。
git merge a
複製代碼
結果
Already up-to-date
複製代碼
啥?由於咱們以前提交合並的a分支的代碼還在,所以咱們並不能在從新合併a分支。
解決辦法:使用revert以前revert的commit號。在上面的例子中就是git revert 4
。因而又新增了一個commit,把以前revert的代碼又從新revert回來了。具體參考
依舊是上面的需求。
develop -----1-----4-------5------6
\ / \ / \ /
feature b c d
複製代碼
如今我將develop reset到commit 4這裏,繼續提交我之後的代碼
develop -----1-----4-------7------8
\ / \\ /
feature b \ e
\------5----d
\-c-/
複製代碼
我如今想從新合併d分支的代碼
develop -----1-----4-------7------8------9
\ / \\ / /
feature b \ e /
\------5----d/
\-c-/
複製代碼
合併過來大概是這個樣子的。也就是說d分支以前已經合併過c分支,所以若是還想要合併d分支的話,c分支的代碼就會同步的帶過來。
講到這裏大部分經常使用的應用場景也就應該是比較清晰的了。
git revert
就再好不過了; 若是分支我就是提錯了沒用了還不想讓別人發現我錯的代碼,那就git reset
吧git revert b分支commit號
,這樣c和d的代碼依然還在。我能想到的大概就是這些了,固然在具體項目上咱們會遇到不少沒遇到過的情形。個人建議是不要盲目的查找相似問題後就去修改,由於他的問題並不必定就等同於你的問題。我建議去建立測試的分支,等真正整明白了,再去整線上的分支也不遲。
第一次寫了這麼詳細的一篇文章,主要也是由於網上查到的知識,對git知識體系通常的人來講,看的比較費解。