沒想到,Git竟然有3種「後悔藥」!

你知道Git版本控制系統中都有哪些「後悔藥」嗎?

本文經過案例講解git reset 、 git revert 、 git checkout在版本控制中的做用;git

場景

小明同窗做爲新人加入到一個新的項目組中作開發,在項目的迭代開發中,小明勤勤懇懇的寫代碼,直到有一次...fetch

小明:完了,完蛋了
洋仔:怎麼了,一驚一乍的

小明:我把錯誤代碼用git commit後還push到線上代碼庫了! 這可怎麼辦!
洋仔:莫慌,git有「後悔藥」!spa

慌不慌.jpg

洋仔:容我給你慢慢道來。 可是咱們要先知道一些git的基礎知識,你才能更好的理解git命令的做用

預備知識

git將項目的存儲分爲4部分,每部分有本身做用,.net

見下圖:版本控制

20190919160008729.png

  • Workspace:工做區(當前用戶操做修改的區域)
  • Index / Stage:暫存區 (add後的區域)
  • Repository:倉庫區或本地倉庫(commit後的區域)
  • Remote:遠程倉庫(push後的區域)

總體過程能夠簡述爲:code

  • 工做區–>add–>暫存區–>commit–>本地倉庫區–>push–>遠程倉庫區
  • 遠程倉庫區–>fetch–>使用refsremotes下對應分支文件記錄遠程分支末端commit_id 和 本地倉庫區 -->merge–>工做區
  • 遠程倉庫區–>pull–>使用refsremotes下對應分支文件記錄遠程分支末端commit_id and 本地倉庫區 and 工做區

具體的git的組成部分和概念命令,請移步下述兩個博客(超連接):xml

Git技術乾貨!工做中Git的使用實踐和經常使用命令合集!blog

Git - 使用git不知道內部實現機制怎麼行開發

假設項目存在這麼一個提交記錄:rem

$ git log
commit commit_id4 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第三次修改README文件

commit commit_id3 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第二次修改README文件

commit commit_id2
Author: test
Date:   Thu Aug 20 16:28:19 2020 +0800
    第一次修改README文件

commit commit_id1
Author: test
Date:   Thu Aug 20 16:26:59 2020 +080
    初始化項目

提交順序爲:commit_id1 --> commit_id2 --> commit_id3 --> commit_id4

注意:在git中每次的commit都有一個commit id惟一標識當前的提交!

下面,咱們先來解決小明的這個問題,使用git reset便可完美解決~

問題解決

洋仔:小明,你的這個就能夠用 git reset 這個命令來完美的搞定,下面咱們看一下如何解決

一、獲取當前提交的commit id

命令:git log

獲取到當前項目分支下的全部commit記錄;

假設上述小明提交錯誤的commit id爲commit id:commit_id4這一次提交;

他的上一次提交就是commit id:commit_id3 ,咱們要將修改回滾到commit_id3的時刻!

小明:我想要把我剛纔 commit的修改保留下來,我修改的代碼不能給我刪除掉呀!

洋仔:沒問題

二、將某個commit id前的commit清除,並保留修改的代碼

命令:git reset <commit_id> 當前場景下就是:git reset commit_id3

將指定commit_id後的全部提交,都去除,並保留修改的代碼在本地的區域,也就是Workspace

小明:啊哈,這樣的話我就能夠把錯誤代碼修改後再提交了; 可是我已經push到線上倉庫的數據怎麼辦呢?

洋仔:別急,有辦法~

三、修改代碼完成後,將修改好的代碼add到暫存區,並提交到本地倉庫中

命令:git add <file_name> and git commit 當前場景下:git add . and git commit

將最新修改後的代碼commit

則提交後的提交記錄假設以下: 能夠看到,咱們錯誤提交的commit_id4提交記錄消失,取而代之的是咱們更新代碼後提交的記錄commit_id5; 這樣就完成了本地的代碼修改和更新

$ git log
commit commit_id5 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第三次修改README文件-更新錯誤後提交

commit commit_id3 (HEAD -> master)
Author: test
Date:   Thu Aug 20 16:28:45 2020 +0800
    第二次修改README文件

commit commit_id2
Author: test
Date:   Thu Aug 20 16:28:19 2020 +0800
    第一次修改README文件

commit commit_id1
Author: test
Date:   Thu Aug 20 16:26:59 2020 +080
    初始化項目

四、將本地修改同步到遠程倉庫

命令:git push origin HEAD --force

將本地修改強行同步到遠程倉庫,使得遠程倉庫和本地倉庫保持一致!

總體流程以下:

git log
git reset commit_id3
修改代碼
git add .
git commit -m '第三次修改README文件-更新錯誤後提交'
git push origin HEAD --force
洋仔:好了,小明,你的問題完美解決了

小明:哦吼,可是我還有一個問題: 若是我想要不保留回滾commit的修改,直接刪除掉修改!該怎麼處理呢?

洋仔:簡單~ 咱們總體看一下 git reset 命令

後悔藥-git reset

在進行下面的講解是,仍是先假設有這麼一個提交鏈:

commit_id1 --> commit_id2 --> commit_id3 --> commit_id4

git reset <param> commit_id2:

reset是將HEAD從新定位到commit_id2上,對於commit_id3 和 commit_id4 和本地當前的修改,對於不一樣的參數param,會有不一樣的處理;

reset命令有三種處理模式:

  • --soft:保留commit修改,將修改存儲到index中;也就是說git add後的區域
  • --mixed:保留commit修改,將修改存儲到本地工做區域中;也就是說git add前的區域
  • --hard:刪除commit修改,慎用!

git reset --soft

回滾commit_id前的全部提交,不刪除修改:

git reset --soft commit_id

重設head,不動index,因此效果是commit_id以後的commit修改所有在index中
將id3 和 id4的修改放到index區(暫存區),也就是add後文件存放的區域,本地當前的修改保留

git reset --mixed

回滾commit_id前的全部提交,不刪除修改:
git reset commit_id 等同於 git reset --mixed commit_id

與 下述的 git reset --hard commit_id效果不一樣

重設head 和 index,不重設work tree,效果就是commit_id以前的修改,所有在work tree中,爲還未add的狀態
將id3 和 id4 的全部修改放到本地工做區中,本地當前的修改保留

git reset --hard

回滾commit_id前的全部提交,將修改所有刪除:
git reset --hard commit_id

重設head、index、work tree,也就是說將當前項目的狀態恢復到commit_id的狀態,其他的所有刪除(包含commit_id後的提交和本地還未提交的修改)
慎用!!

後悔藥-git revert

小明:原來git reset這麼強大呀! 可是我這還有個問題:

若是想要只操做修改中間的一個commit,不對其餘的commit產生影響; 也就是相似於咱們只修改commit_id2,而對commit_id3 和 commit_id4無影響,該怎麼處理呢?

洋仔:(這麼多問題,幸好我懂,要不此次就丟大了。。) 簡單! git revert 命令!

適用場景: 在項目開發中,忽然發如今前幾回的提交中,有一次提交中包含一個bug; 固然咱們能夠進行一個新的修改,而後再提交一次; 可是,不優雅哈哈; 咱們能夠直接重作有bug的commit~

爲何不直接去再添加一個commit呢? git revert是用於「反作」某一個版本,以達到撤銷該版本的修改的目的。

好比,咱們commit了三個版本(版本1、版本2、 版本三),忽然發現版本二不行(如:有bug),想要撤銷版本二,但又不想影響撤銷版本三的提交,就能夠用 git revert 命令來反作版本二,生成新的版本四,這個版本四里會保留版本三的東西,但撤銷了版本二的東西;

在revert命令中經常使用的就兩個:

  • git revert -e <commit_id>:重作指定commit的提交信息
  • git revert -n <commit_id>:重作執行commit的代碼修改

git revert -e

重作commit_id的提交信息,生成爲一個新的new_commit_id
git revert -e commit_id

git revert -n

重作commit_id的提交
git revert -n commit_id
將commit_id中修改,放到index區,咱們能夠對他從新作修改並從新提交

revert vs reset

  • git revert是用一次新的commit來回滾以前的commit,這次提交以前的commit都會被保留不動;
  • git reset是回到某次提交,提交及以前的commit都會被保留,可是此commit id以後的修改都會被刪除或放回工做區等待下一次提交;
小明:還有這種操做,能夠直接單獨操做提交過程當中的某一個commit! 太棒了!

後悔藥-git checkout

小明:還有最後一個問題:

若是我在一次開發中,發現某個文件修改錯誤了,想要將文件恢復到剛pull代碼時的狀態怎麼辦呢?

洋仔:簡單! 看git checkout解決這個問題!

咱們知道使用git checkout能夠

  • git checkout <branch_name>切換分支
  • git checkout -b <branch_bame>建立分支等操做

它還有回滾指定文件的修改的功能

命令:git checkout -- <file_name>

上述語句的做用,就是將file_name的本地工做區的修改所有撤銷,有兩種狀況:

  • 若是file_name在commit後沒有add過這個文件,則撤銷到版本庫中的狀態
  • 若是file_name在commit後add過這個文件,則撤銷到暫存區的狀態,也就是add後的狀態

總之,就是讓指定的文件回滾到最近的一次git add 或者 git commit時的狀態!

小明:太棒了,之後不再怕提錯代碼了!

總結

上述,咱們介紹了git reset git revert git checkout 在版本回滾、重作、撤銷修改方面的做用;

能夠應用到工做中對 誤操做、不知足要求、不知足意願的commit記錄的重作和修改;

不用慌錯誤的commit了,撒花~
相關文章
相關標籤/搜索