<kbd id="9plqc"><label id="9plqc"></label></kbd>

        <th id="9plqc"></th>
        1. <center id="9plqc"><video id="9plqc"></video></center>
          <sub id="9plqc"><form id="9plqc"><pre id="9plqc"></pre></form></sub>
          <nav id="9plqc"><form id="9plqc"><legend id="9plqc"></legend></form></nav>
          Git版本回退的三種方式與stash 您所在的位置:網(wǎng)站首頁 屬馬的找對象找什么屬相的好 Git版本回退的三種方式與stash

          Git版本回退的三種方式與stash

          2024-03-19 17:28| 來源: 網(wǎng)絡(luò)整理| 查看: 265

          前言

          git作為一款版本控制工具,其最核心的功能就是版本回退,沒有之一。熟悉git版本回退的作能夠讓你真真正正地放開手腳去開發(fā),不用小心翼翼,怕一不小心刪除了不該刪除的文件。本節(jié)除了介紹版本回退的內(nèi)容之外,還會介紹stash的使用。

          一、版本回退

          在git中永遠有后悔藥可吃,總是可以回到版本庫的某一個時刻,這就叫做版本回退;

          image-20200406144058526

          如上圖所示:當前master分支指針指向D,通過版本回退可以使master指向C、B或A。進行版本回退的命令大體上有三種:reset、revert和checkout。下面就來一一講解:

          Ⅰ.git reset 1.參數(shù)

          reset命令可以添加很多參數(shù),常用的有--mixed、--soft和--hard三種。下圖為一次完整提交的四個階段:

          image-20200412192613526

          三個參數(shù)大體上的區(qū)別為:

          --mixed:為默認值,等同于git reset。作用為:將文件回退到工作區(qū),此時會保留工作區(qū)中的文件,但會丟棄暫存區(qū)中的文件; --soft:作用為:將文件回退到暫存區(qū),此時會保留工作區(qū)和暫存區(qū)中的文件; --hard:作用為:將文件回退到修改前,此時會丟棄工作區(qū)和暫存區(qū)中的文件;

          下面就來詳細地講解它們的使用方法:

          首先在master分支進行四次提交,每次提交在test.txt中添加一行文本信息:

          image-20200406164503683

          --mixed

          該參數(shù)為默認值,作用為:將文件回退到工作區(qū)中:如下圖所示,將test.txt文件回退一次提交:

          image-20200412194811197

          可以看到第四次提交對test.txt的修改作被回退到了工作區(qū)當中,并且保留了工作區(qū)中第四次提交對test.txt所做的修改,所以工作區(qū)中的test.txt文件內(nèi)容與回退前一致。

          --soft

          該參數(shù)的作用為:將文件回退到暫存區(qū)中:如下圖所示,將test.txt文件回退一次提交:

          image-20200412195321082

          可以看到第四次提交對test.txt的修改作被回退到了暫存區(qū)當中,并且保留了工作區(qū)和暫存區(qū)中第四次提交對test.txt所做的修改,所以,工作區(qū)中的文件內(nèi)容與回退前一致。

          --hard

          該參數(shù)的作用為:將文件回退到修改前:如下圖所示,將test.txt文件回退一次提交:

          image-20200412205112201

          可以看到test.txt直接回到了進行第四次提交前,此時刪除了工作區(qū)和暫存區(qū)中第四次提交對test.txt所做的修改。所以,工作區(qū)變得干凈了,test.txt文件內(nèi)容回退到剛完成第三次提交時。

          2.寫法

          為了方便演示reset的各種使用方法,下面的指令都采用--hard參數(shù)。

          git reset --hard HEAD^

          該命令的作用為回退一次提交:

          image-20200406164628192

          回退后的狀態(tài)為:

          image-20200406164713774

          可以看到,該方法會同時改變了HEAD和master指針的指向;

          git reset --hard HEAD^^

          該命令的作用為回退兩次提交:

          image-20200406170323254

          回退后的狀態(tài)為:

          image-20200406170352024

          同樣,使用--hard參數(shù)回退,工作區(qū)是干凈的;可以看到,該方法也會同時改變HEAD和master指針的指向;

          git reset --hard HEAD~n

          該命令的作用為回退n次提交:

          image-20200406203027868

          可以看到使用了--hard參數(shù),回退結(jié)果符合預期,并且該方法也會同步修改HEAD和分支master指針的指向。

          注意:該方式只能向前回退,不能向后回退。

          上述命令中的HEAD可以更換為分支名,比如master:

          git reset --hard master~n

          該命令表示將master分支回退n次提交。由于HEAD始終指向當前分支,所以使用分支名和使用HEAD效果是一樣的。

          git reset --hard commit_id

          **該指令的作用為回退到指定的commit id的提交版本;由于commit id是不會重復的,一般只需要寫前幾(6)位就可以識別出來。通過commit id的回退方式既可以向前回退,也可以向后回退。**如下所示,從1st commit往后回退到4th commit,其中4th commit的commit id = bdb373...。

          為了熟悉該指令,我們分兩種方式進行回退:使用--hard參數(shù)與使用默認參數(shù)。

          使用--hard參數(shù)

          image-20200406193422130

          從圖中可以看出:通過第四次提交的commit_id: bdb373順利地從第一次提交向后回退到了第四次提交,并且工作區(qū)干凈。該方法也同時修改了HEAD和分支master的指向,具體過程為:

          image-20200414171228274

          使用默認參數(shù)

          image-20200406193005200

          可以看到切換回了4th commit,但是工作區(qū)的test.txt文件并沒有變化;這是因為,在4th -> 1st的過程中,需要在工作區(qū)中刪除test.txt文件中的2nd line、3rd line、4th line。通過默認參數(shù)--mixed,將4th commit對文件的修改回退到了工作區(qū)當中,如下圖所示:

          image-20200406202451310

          這個過程丟棄了暫存區(qū)中對文件的刪除作,但是保留了工作區(qū)中對文件的刪除作。所以,工作區(qū)中的test.txt文件仍然處于刪除了三行內(nèi)容的狀態(tài)。

          此時只需要將修改作從階段1移動到修改前的階段0,即可將文件恢復到修改前的狀態(tài),并清空工作區(qū)。可以采用git restore test.txt實現(xiàn):

          image-20200406202716247

          Ⅱ.git revert

          revert是回滾,重做的意思。不同于reset直接通過改變分支指向來進行版本回退,并且不產(chǎn)生新的提交;revert是通過額外創(chuàng)建一次提交,來取消分支上指定的某次提交的方式,來實現(xiàn)版本回退的。如下圖所示,假如想要重做提交B,重做前與重做后的狀態(tài)為:

          image-20200413234440432

          所謂重做提交B,指的是在新建的提交B'中取消提交B中所做的一切作。也就是說revert的思想為:通過創(chuàng)建一個新提交來取消不要的提交。所以,提交數(shù)會增加。

          1.參數(shù)

          git同樣為revert提供了許多參數(shù),常用的有以下三種。為了演示它們的作用,首先需要設(shè)置對應(yīng)的測試環(huán)境:在dev分支上進行四次提交,每次提交都為test.txt添加一行內(nèi)容:

          image-20200414000404304

          -e

          -e參數(shù)是--edit的縮寫,為revert指令的默認參數(shù),即git revert -e等同于git revert。該參數(shù)的作用為在重做過程中,新建一次提交的同時編輯提交信息。比如通過以下命令重做上述的dev2提交:

          git revert f4a95

          執(zhí)行該指令后會創(chuàng)建一次新的提交來取消提交dev2所做的一切作,并且會進入vim編輯器,編輯新提交的提交注釋: image-20200414115052089

          如下圖所示,提交dev2為文件test.txt添加的dev2文本被取消了,并且dev分支上多了一次提交:

          image-20200414114945783

          --no-edit

          該參數(shù)的作用為不編輯由于revert重做,所新增提交的注釋信息。如下圖所示,通過:

          git revert --no-edit f4a95b

          重做提交dev2的過程中,并不會進入vim編輯器編輯新增提交的注釋信息,而是采用默認的注釋信息:Revert "dev2":

          image-20200414114748865

          -n

          -n參數(shù)是--no-commit的簡寫形式,作用為對revert重做某次提交時所產(chǎn)生的修改,不進行提交,也就是不會新增一次提交;

          如下圖所示,這是revert指令通過新建提交B'來取消提交B的過程,分為0~4個階段。不添加-n參數(shù)時,revert指令會產(chǎn)生一次額外提交B',此時處于下圖中的第3階段。而使用-n參數(shù)時,雖然revert指令也會通過新建提交B'來重做提交B。但是,此時還處于生成提交B'的過程,還沒有完全生成提交B',也就是處于下圖中的第2階段。

          image-20200414002942670

          這種做法的好處是,允許我們干涉revert重做過程,手動進行提交。如下圖所示,通過:

          git revert -n f4a95

          重做提交dev2的過程中,手動暫停了重做過程。雖然提交dev2對test.txt所做的修改已被撤銷,但是這一重做作還未進行提交:

          image-20200414120436217

          這樣我們既可以修改重做過程中不滿意的地方,也可以隨意添加注釋。修改完后,通過手動提交的方式,完成重做(REVERTING)作:

          image-20200414121147251

          2.寫法

          revert指令也有多種寫法,下面介紹主要的幾種。為了方便演示,下列指令都采用默認參數(shù)-e手動編輯每次新增提交的注釋信息。

          git revert commit_id

          這是最常用的寫法,通過commit_id精準地選擇想要重做的提交。分兩種情況:

          **情況一:**重做最新一次提交,不會發(fā)生沖突。

          例如:通過以下指令,重做dev分支上最新的一次提交dev2:

          git revert f4a95b

          首先進入vim編輯器編輯新增提交的注釋信息:

          image-20200414135326937

          隨后完成重做作,如下圖所示;可見提交dev2給test.txt添加的dev2內(nèi)容被刪除了,并且多出一次提交,說明重做成功:

          image-20200414140040443

          **情況二:**重做非最新一次提交,會發(fā)生沖突。

          例如:通過以下指令,重做dev分支上的第三次提交dev1:

          git revert dbde45

          會出現(xiàn)合并沖突:

          image-20200414140502098

          使用git mergetool指令,通過vim編輯器的工具vimdiff顯示沖突文件test.txt:

          image-20200414140645448

          回車進入vim編輯器界面,解決沖突:

          image-20200414141354304

          解決沖突之后,手動進行一次提交,完成revert過程:

          image-20200414142323103

          為什么會出現(xiàn)沖突?

          通過上面的例子不難看出,revert作生成的新提交其實是通過兩次提交合并而成的。如下圖所示:

          image-20200414143430837

          首先,將被重做的提交dev1的前一次提交2nd復制一份,即圖中的2nd'; 然后,將它與當前分支的最新提交dev2進行合并,由此生成revert作新增的提交;

          知道了revert作新增的提交的由來后,就不難解釋為什么會出現(xiàn)合并沖突了,如下圖所示:

          image-20200414144109389

          合并的兩次提交中,文件test.txt的內(nèi)容不一樣。git不知道以哪個版本為準,自然會導致自動合并失敗,需要手動合并。

          git revert HEAD

          該指令的作用為重做所在分支的最新一次提交,并且不會發(fā)生沖突:

          image-20200414150640086

          git revert HEAD^

          該指令的作用為重做所在分支的倒數(shù)第二次提交,會發(fā)生沖突,需要手動合并,完成重做作:

          image-20200414151002143

          git revert HEAD^^

          該指令的作用為重做所在分支的倒數(shù)第三次提交,會發(fā)生沖突,需要手動合并,完成重做作:

          image-20200414180953703

          git revert HEAD~n

          該指令的作用為重做所在分支的倒數(shù)第n+1次提交,會發(fā)生沖突,需要手動合并,完成重做作。過程與上述一致,這里就不再贅述了。

          **總結(jié):**常用git revert commit_id這種方式。

          3.撤銷revert作

          思路很簡單,再次通過revert作取消上一次的revert作(即所謂"負負得正")。

          作前,dev分支上的提交記錄和test.txt文件內(nèi)容如下:

          image-20200414153206034

          通過:git revert --no-edit f4a95重做提交dev2(--no-edit表示不修改新增提交的注釋):

          image-20200414153456451

          重做后,多了一次提交,并且test.txt文件中刪除了dev2這一行內(nèi)容。此時,可以通過:

          git revert --no-edit 582d127

          重做上一次重做作,以此達到取消上一次重做作的目的:

          image-20200414153724455

          如上圖所示,雖然多出了一次提交,但是test.txt文件中被刪除的dev2內(nèi)容被恢復了,這樣就撤銷了revert作。

          Ⅲ.git checkout 1.git checkout commit_id

          使用checkout可以進行版本回退,如直接使用:

          git checkout cb214

          回退到提交3rd,此時會出現(xiàn)如下提示:

          image-20200311111540863

          注意到,切換后HEAD指向的不再是master分支,而是cb214...即第三次提交,查看歷史提交記錄:

          image-20200311111719389

          可看到只有3次提交,什么意思呢?如下圖所示:

          image-20200412001646768

          image-20200311112656834

          通過git checkout讓HEAD指針指向了第3次提交,可以將它想象為一個新的分支。但是卻沒有實際創(chuàng)建分支,即此時head指向的由提交1~3組成的commit對象鏈條處于游離狀態(tài);

          接著,在HEAD還指向游離的提交節(jié)點3的基礎(chǔ)上對文件做出新的修改:

          image-20200311113237150

          此時如果我們切換回master分支,會出現(xiàn)下列錯誤

          image-20200311113209483

          提示顯示:如果沒有保存就從游離的提交上切換到master分支,這一修改就會被checkout命令覆蓋。我們可以在切換前進行一次提交作:

          image-20200311113625297

          此時的狀態(tài)為:

          image-20200412002213790

          在游離的Commit對象鏈中進行了一次提交之后,再次通過:git checkout master切換到master分支:

          image-20200311114055018

          提示大意為:如果沒有任何分支指向剛才在游離的Commit對象鏈中進行的提交,那么該提交就會被忽略。此時的狀態(tài)如下圖所示:

          image-20200412002655921

          如果想要創(chuàng)建一個分支保存(指向)這條游離的Commit對象鏈,現(xiàn)在就是很好的時機。根據(jù)上述提示的命令:

          git branch mycommit c4d5cc3

          創(chuàng)建指向commit_id為c4d5cc3的提交(即上述的提交節(jié)點5)的分支mycommit:

          image-20200311115117279

          由此游離的commit對象鏈得以被新分支所指向,并得到了保存,此時的狀態(tài)如下圖所示:

          image-20200412004042471

          總結(jié):

          通過checkout進行版本回退會造成游離的提交對象鏈,需要額外創(chuàng)建一個分支進行保存; 因此,使用checkout進行版本回退的思路為,先切換到想要回退的提交版本,再刪除進行版本回退的分支dev。最后,創(chuàng)建一個新的dev分支指向游離的提交對象鏈,完成分支dev的版本回退,簡稱"偷天換日"; 只要有分支指向,提交就不會被丟棄。 Ⅳ.revert與reset的選擇

          由于checkout會造成游離的提交對象鏈,所以,一般不使用checkout而是使用reset和revert進行版本回退:

          revert通過創(chuàng)建一個新提交的方式來撤銷某次作,該作之前和之后的提交記錄都會被保留,并且會將該撤銷作作為最新的提交; reset是通過改變HEAD和分支指針指向的方式,進行版本回退,該作之后的提交記錄不會被保留,并且不會創(chuàng)建新的提交;

          在個人開發(fā)上,建議使用reset;但是在團隊開發(fā)中建議使用revert,特別是公共的分支(比如master),這樣能夠完整保留提交歷史,方便回溯。

          Ⅴ.回退方法匯總

          版本回退主要有三大方式:reset、revert和checkout,各方式的比較如下:

          方法效果向前回退向后回退同步修改HEAD與分支指向git reset --hard HEAD^往前回退1次提交能否是git reset --hard HEAD^^往前回退2次提交能否是git reset --hard HEAD~n往前回退n次提交能否是git reset --hard 回退到指定commit id的提交能能是git revert HEAD重做最新一次提交能否是git revert HEAD^重做倒數(shù)第二次提交能否是git revert HEAD^^重做倒數(shù)第三次提交能否是git revert HEAD~n重做倒數(shù)第n+1次提交能否是git revert commit_id重做指定commit_id的提交能能是git checkout commit_id回退到指定commit id的提交能能否

          從上表可知,只有下列三種方式可以自由地向前向后回退:

          git reset --hard commit_id git revert commit_id git checkout commit_id

          但是,使用checkout進行回退會出現(xiàn)游離的提交,需要創(chuàng)建一個新分支進行保存,所以不常用。

          二、git stash 1.git stash的作用

          git stash指令的作用為:對沒有提交到版本庫的,位于工作區(qū)或暫存區(qū)中游離的修改進行保存,在需要時可進行恢復。具體應(yīng)用場景如下:

          在master分支進行兩次提交:1st和2nd,隨后創(chuàng)建并切換到dev分支。在dev分支上進行一次提交(dev1),此時兩分支的狀態(tài)為:

          image-20200412235844426

          隨后在dev分支上給文件test.txt添加一行dev2,但是不提交到暫存區(qū),直接切換到master分支,會出現(xiàn)如下錯誤:

          image-20200413001632846

          圖中顯示的錯誤大意為:在dev分支上的修改會被checkout作覆蓋。下面我們來看看,將dev分支上的這一修改作添加到暫存區(qū)后,再切換分支,是否還會出現(xiàn)同樣的問題:

          image-20200413001752227

          可見還是會出現(xiàn)該錯誤,這初步驗證了位于工作區(qū)和暫存區(qū)中的修改都會被checkout作覆蓋的結(jié)論。原因如下圖所示:

          image-20200413001917190

          雖然在dev分支上修改了文件,但是沒有將這一修改作進行提交。這樣就不會產(chǎn)生提交節(jié)點,就如上圖所示,修改dev2是游離的,在切換分支的時候會被丟棄。

          這種情況在日常開發(fā)中很常見,當在develop分支上開發(fā)新功能的時候,master分支出現(xiàn)緊急情況需要切換回去進行修復。但是,當前分支的新功能還沒開發(fā)完全,貿(mào)然切換分支,原來開發(fā)的內(nèi)容就會因被覆蓋而丟失,怎么辦呢?

          有人可能會說進行一次commit不就可以了嗎?確實可以。但是,這樣不符合提交的代碼就是正確代碼的原則。更好的解決方法為使用git stash,如下圖所示:

          image-20200413002115302

          可見git stash可以將當前dev分支上,位于在工作區(qū)或暫存區(qū)中的修改,在未提交的情況下進行了保存;并且將分支回退到修改前的狀態(tài),保存過后,就可以很順暢地切換回master分支了。

          圖中的WIP(working in progress)表示的是正在進行的工作;

          當我們在master分支上完成了工作,再次切換回dev分支時,查看test.txt文件:

          image-20200413002256321

          發(fā)現(xiàn)切換分支前所做的修改dev2消失了,這是為什么呢?

          其實,上面通過git stash將dev分支上工作區(qū)或暫存區(qū)中的修改,提交到了stash區(qū)域進行保存,并將dev分支回退到修改前的狀態(tài)。如下圖所示:

          image-20200413003349365

          切換到master分支時test分支上的修改依舊會被覆蓋。所以,再次回到dev分支時需要從stash區(qū)域中恢復切換分支前保存的修改;

          怎樣恢復通過git stash保存到stash中的修改呢?可以通過:

          git stash list

          查看該分支上被stash保存的修改:

          image-20200413224408623

          繼續(xù)給test.txt文件添加內(nèi)容:dev3,并通過以下指令保存修改的同時添加注釋:

          git stash save '注釋'

          image-20200413225024618

          首先,通過上述命令可以修改stash中存儲修改的備注信息; 其次,雖然在test分支上進行了兩次修改,但是使用git stash保存修改后,文件test.txt并沒有實際被修改; 2.恢復stash存儲的修改

          方法有很多,主要有以下三種:

          git stash pop

          image-20200413225140030

          如圖所示,通過上述命令將stash中存儲的最新一次修改恢復了。相信你已經(jīng)發(fā)現(xiàn)了,stash與棧非常類似:先保存的修改,排在最后,序號最大;后保存的修改,排在最前,序號最小;

          恢復了最新一次修改后,再次查看stash:

          image-20200413225221071

          可以看到存儲的修改只剩下一條了,由此可推斷出git stash pop作用為:

          **第一:**恢復stash中存儲的最新一次修改; **第二:**將該修改從stash中刪除; git stash apply

          image-20200413225457480

          如上圖所示,使用該指令時發(fā)生了合并沖突。這是因為,stash中保存的每一次修改代表的都是一個版本。

          image-20200413231349820

          如上圖所示,在test分支上,進行第一次修改后,通過git stash將該修改作為修改0保存到stash中,此時分支中的文件并沒有發(fā)生改變; 進行第二次修改后,通過git stash將修改作為修改1保存到stash中,分支中的文件依舊沒有發(fā)生改變;此時的stash中相當于保存著同一分支上兩個修改后的版本; 此時通過**git stash pop取出修改0,與test分支進行合并;再通過git stash pop**取出修改1,再次與test分支進行合并,兩個版本合并自然會產(chǎn)生沖突。

          手動解決沖突后,要進行一次提交才算完成了手動合并;隨后查看stash:

          image-20200413230750201

          修改0仍然存在,說明**git stash apply**的作用為取出stash中最新(前面)的修改并與分支進行合并。但是,stash中存儲的該修改并不會被刪除;

          git stash apply stash@{n}

          這是最常用的方法,作用為從stash中恢復特定的修改,并且不刪除stash中的該修改。

          將test.txt的兩次修改通過git stash存儲到stash中,如下圖所示:

          image-20200413232024080

          通過git stash apply stash@{1}恢復stash中存儲的修改1:

          image-20200413232309330

          如上圖所示,成功地恢復了stash中的修改1,并且stash中的修改1并沒有被刪除;

          總結(jié):

          git stash pop:恢復并刪除stash中存儲的最新修改; git stash apply:恢復但不刪除stash中存儲的最新修改; git stash apply stash@{0}:恢復但不刪除stash中存儲的特定提交;


          【本文地址】

          公司簡介

          聯(lián)系我們

          今日新聞

          推薦新聞

          專題文章
            CopyRight 2018-2019 實驗室設(shè)備網(wǎng) 版權(quán)所有
            黄色免费网站在线看,韩国精品在线观看,韩国美女一区二区,99国产热 开封市| 临汾市| 彭泽县| 南昌市| 抚顺县| 清水河县| 钟祥市| 屏东县| 扶沟县| 乐业县| 旬阳县| 喀喇| 玉龙| 梅河口市| 邯郸县| 手机| 阿克陶县| 乐安县| 永康市| 勐海县| 清远市| 扶风县| 周口市| 宾川县| 西吉县| 确山县| 法库县| 邓州市| 施秉县| 秦皇岛市| 盈江县| 冷水江市| 墨竹工卡县| 陵水| 木兰县| 简阳市| 亳州市| 洪泽县| 江阴市| 含山县| 福鼎市| http://444 http://444 http://444 http://444 http://444 http://444