『現學現忘』Git後悔藥 — 33、revert復原(二)

2022-10-14 12:09:02

提示:接上一篇文章。

4、一次移除某幾次提交

上一篇文章的演示中,只有兩個提交需要 revert,我們可以一個個回退。但如果有幾十個呢?一個個回退肯定效率太低而且容易出錯。

(接上面範例)

我們可以使用以下方法進行批次回退:

(1)git revert移除某幾次提交的修改

命令:git revert <commit6> <commit5> <commit4> …

注意:提交的順序是從最近的提交開始往前寫。

範例:

# 1.檢視版本庫歷史提交記錄
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/revert_test (master)
$ git log --oneline
30f7626 (HEAD -> master) Revert "第6次提交,revert 復原第3次提交"
d0c8e48 Revert "第5次提交,revert 復原第4次提交"
c04b29c 第4次提交,新增內容:revert test v4
fd819dc 第3次提交,新增內容:revert test v3
c71ae3c 第2次提交,新增內容:revert test v2
557f7c3 第1次提交,新增readme.txt檔案

# 2.把第5、6次提交移除
# 先寫提交5ID,在寫提交6ID
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/revert_test (master)
$ git revert d0c8e48 30f7626
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
error: could not revert d0c8e48... Revert "第5次提交,revert 復原第4次提交"
hint: after resolving the conflicts, mark the corrected paths
hint: with 'git add <paths>' or 'git rm <paths>'
hint: and commit the result with 'git commit'

說明:

  • Auto-merging readme.txt:自動合併readme.txt檔案出現問題。
  • CONFLICT (content): Merge conflict in readme.txt:衝突(內容):在readme.txt中合併衝突。
  • error: could not revert d0c8e48... Revert "第5次提交,revert 復原第4次提交":無法還原d0c8e48提交。
  • hint: after resolving the conflicts, mark the corrected paths:解決衝突後,把衝突檔案提交到暫存區。
  • hint: with 'git add <paths>' or 'git rm <paths>':可使用「 git add <路徑>」或「 git rm <路徑>」方法,新增衝突檔案到暫存區,或者刪除檔案。
  • hint: and commit the result with 'git commit':提示:並使用'git commit'提交結果。

我們應該先寫commit-6,在寫commit-5

# 1.復原第5、6次提交
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/revert_test (master)
$ git revert 30f7626 d0c8e48
[master 31341a4] Revert "Revert "第7次提交,revert 復原第5、6次提交""
 1 file changed, 1 insertion(+)
[master 509c208] Revert "Revert "第8次提交,revert 復原第5、6次提交""
 1 file changed, 1 insertion(+)

# 2.檢視版本庫歷史提交記錄
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/revert_test (master)
$ git log --oneline
509c208 (HEAD -> master) Revert "Revert "第8次提交,revert 復原第5、6次提交""
31341a4 Revert "Revert "第7次提交,revert 復原第5、6次提交""
30f7626 Revert "第6次提交,revert 復原第3次提交"
d0c8e48 Revert "第5次提交,revert 復原第4次提交"
c04b29c 第4次提交,新增內容:revert test v4
fd819dc 第3次提交,新增內容:revert test v3
c71ae3c 第2次提交,新增內容:revert test v2
557f7c3 第1次提交,新增readme.txt檔案

# 3.檢視readme.txt檔案內容,又回到V4版本了
L@DESKTOP-T2AI2SU MINGW64 /j/git-repository/revert_test (master)
$ cat readme.txt
revert test v1
revert test v2
revert test v3
revert test v4

我們可以看到,每復原一個commit提交,都會生成一個新的提交。上面復原了兩個commit,就讓你編寫兩次提交說明資訊。

這時,錯誤的提交 commit-5commit-6 依然保留,將來進行甩鍋的時候也有依可循。而且,這樣操作的話 HEAD 指標是往後移動的,可以直接使用 git push 命令推播到遠端倉庫裡,而這種做法,正是企業所鼓勵的

(2)git revert 移除某幾次連續的提交的修改

命令:git revert <commit新>...<commit舊>

(這裡就不做演示了,同上)

注意:

  • 含頭不含尾,也就是復原的提交,包含<commit新>,不包含<commit舊>
  • 提交的順序也是,最新的commit開頭,然後往前到比較遠的commit提交。
  • 移除過程中如果有衝突:
    不知道某次提交的修改內容,可以使用 git show 檢視修改內容。
    Git衝突的時候會提示當前要還原的commit的id是多少,如上error: could not revert d0c8e48... Revert "第5次提交,revert 復原第4次提交"
  • 過程中移除了幾次提交的修改,也會相應的生成幾次revert commit記錄。

5、revert命令常用引數

(1)-n引數

作用:git revert 命令移除某幾次的提交的修改,但是不要使用還原的更改建立任何提交,還原只是修改工作樹和索引。簡寫-n,全稱--no-commit

命令:git revert -n <commit新>...<commit舊>

(2)-m引數

作用:git revert 移除merge(合併)的修改內容。

簡寫:-m parent-number ,全稱:--mainline parent-number

命令:git revert [-m parent-number] <commit>

說明:

如果我們需要還原的提交的是merge的操作,直接使用 git revert <commit> 的方式是不行的,會提示我們:

error: commit ... is a merge but no -m option was given.
fatal: revert failed

因為merge操作有兩個分支,而revert不知道要還原哪個分支的提交,就沒法進行還原\移除那些提交記錄的修改的操作了,所以我們用-m 1來告訴git revert命令哪個是主線,哪個是非主線。(選擇主線就還原非主線,選擇非主線就還原主線)

另外,這個主線是1還是2是從哪裡看出來的呢?

我們可以使用 git show 命令檢視,如果是普通的commit提交,通常會顯示這個commit的id、作者、日期、備註、更改檔案內容等;如果是merge的記錄,則會顯示merge 的commit-id,備註、日期和merge的主線和合並過來的id。

例如:

commit 63374e93eebd2b86882e5a4bb75dcd9d0e334b15
Merge: bc64f61 72032b7
Author: unknown [[email protected]](mailto:[email protected])
Date: Sun Jul 19 11:34:21 2020 +0800

  Merge branch ‘testcopy2’ into testcopy

如上第二行,Merge: bc64f61 72032b7bc64f61 就是主線的id,編號就是1;72032b7就是非主線的id,編號就是2。
此時,我們要把合併過來的分支的修改給還原掉,那麼就可以指定1為主線,還原掉2的提交了。

6、git revertgit reset命令的區別

  1. git revert命令是用一次新的commit來回滾之前的commit,git reset命令是直接回滾到指定的commit。
    即:git reset 命令是把HEAD向歷史版本移動,而git revert命令是把HEAD繼續指向新的commit。
  2. 在回滾這一操作上看,效果差不多。但是在日後繼續merge(合併)以前的老版本時有區別。
    因為git revert命令是用一次逆向的commit「中和」之前的提交,因此日後合併老的branch(分支)時,導致這部分改變不會再次出現。
    但是git reset命令是直接在某個分支上,回退到指定的commit,後邊的提交不會在版本庫的歷史中(只能使用reflog檢視)。因而和老的branch再次merge時,這些被回滾的commit應該還會被引入。

通過以上對比可以發現,git reset 命令與 git revert 命令最大的差別就在於,git reset 命令會失去後面的提交,而 git revert 命令是通過反做的方式重新建立一個新的提交,而保留原有的提交。在企業裡,應儘量使用 git revert 命令,能不用 git reset 命令儘量不用。

參考: