Git命令(撤銷更改)

moduzhang發表於2018-08-29

更改最後一個 commit

你已經使用 git commit 命令提交了大量的 commit。現在,藉助 –amend 選項,你可以更改最近的 commit

$ git commit --amend

git commit --amend 使你能夠包含忘記包含的檔案(或檔案更改)。你可以執行新的 commit 並更新檔案,但是這樣就會出現兩個 commit 執行完全相同的任務。相反,你可以執行 git commit --amend更新最近的 commit,而不是建立新的 commit

具體更新步驟:

  • 編輯檔案
  • 儲存檔案
  • 暫存檔案
  • 執行 git commit --amend

還原 commit

git revert 命令用於還原之前建立的 commit:

$ git revert <SHA-of-commit-to-revert>

此命令:

  • 將撤消目標 commit 所做出的更改
  • 建立一個新的 commit 來記錄這一更改

假設 commit A 新增了一個字元,如果 git 還原 commit A,那麼 git 將建立一個新的 commit,並刪掉該字元。如果刪掉了一個字元,那麼還原該 commit 將把該內容新增回來!

git-revert git 文件

重置 commit

初看,重置(reset) 似乎和 還原(revert) 相似,但它們實際上差別很大。還原會建立一個新的 commit,並還原或撤消之前的 commit。但是重置會清除 commit!

一定要謹慎使用 git 的重置功能。這是少數幾個可以從倉庫中清除 commit 的命令。如果某個 commit 不再存在於倉庫中,它所包含的內容也會消失。

為了減輕你的壓力,澄清下,git 會在完全清除任何內容之前,持續跟蹤大約 30 天。要呼叫這些內容,你需要使用 git reflog 命令。請參閱以下連結以瞭解詳情:

相關 commit 引用

有時候可能需要引用相對於另一個 commit 的 commit,我們可以使用特殊的“祖先引用”字元來告訴 git 這些相對引用。這些字元為:

  • ^ – 表示父 commit
  • ~ – 表示第一個父 commit

我們可以通過以下方式引用之前的 commit:

  • 父 commitHEAD^HEAD~HEAD~1
  • 祖父 commitHEAD^^HEAD~2
  • 曾祖父 commitHEAD^^^HEAD~3

^~ 的區別主要體現在通過合併而建立的 commit 中。合併 commit 具有兩個父級。對於合併 commit,^ 引用用來表示第一個父 commit,而 ^2 表示第二個父 commit。第一個父 commit 是當你執行 git merge 時所處的分支,而第二個父 commit 是被合併的分支

我們來看一個示例,這樣更好理解。這是我的 git log 當前的顯示結果:

* 9ec05ca (HEAD -> master) Revert "Set page heading to "Quests & Crusades""
* db7e87a Set page heading to "Quests & Crusades"
*   796ddb0 Merge branch 'heading-update'
|\  
| * 4c9749e (heading-update) Set page heading to "Crusade"
* | 0c5975a Set page heading to "Quest"
|/  
*   1a56a81 Merge branch 'sidebar'
|\  
| * f69811c (sidebar) Update sidebar with favorite movie
| * e6c65a6 Add new sidebar content
* | e014d91 (footer) Add links to social media
* | 209752a Improve site heading for SEO
* | 3772ab1 Set background color for page
|/  
* 5bfe5e7 Add starting HTML structure
* 6fa5f34 Add .gitignore file
* a879849 Add header to blog
* 94de470 Initial commit

我們來看看如何引用一些之前的 commit。因為 HEAD 指向 9ec05ca commit:

  • HEAD^db7e87a commit
  • HEAD~1 同樣是 db7e87a commit
  • HEAD^^796ddb0 commit
  • HEAD~2 同樣是 796ddb0 commit
  • HEAD^^^0c5975a commit
  • HEAD~3 同樣是 0c5975a commit
  • HEAD^^^24c9749e commit(這是曾祖父的 (HEAD^^) 第二個父 commit (^2))

HEAD~4 引用的是當前分支的第四個父 commit,然後 ^2 告訴我們它是合併 commit 的第二個父 commit(被合併的那個 commit !)。

git reset 命令

git reset 命令用來重置(清除)commit

$ git reset <reference-to-commit>

可以用來:

  • 將 HEAD 和當前分支指標移到目標 commit
  • 清除 commit
  • 將 commit 的更改移到暫存區
  • 取消暫存 commit 的更改

git reset 的選項

git 根據所使用選項來判斷是清除暫存之前 commit 的更改,還是取消暫存之前 commit 的更改。這些選項包括:

  • --mixed
  • --soft
  • --hard

理解這些選項的工作方式:

這裡寫圖片描述

這是我們倉庫的三個部分:工作區、暫存區和頂部的版本庫。master 當前指向最近的提交,HEAD 當前指向 master

這裡寫圖片描述

讓我們轉換一下佈局,執行 reset 後,提交內容可能會去三個地方 工作區、暫存區或回收站,去回收站表示它將被刪除。

這裡寫圖片描述

執行 git reset HEAD~1 會將 HEADmaster 移動到前一個提交。這個帶 3 的提交所做的更改可能移動到工作區或暫存區,也可能直接被移到回收站,這完全取決於 reset 命令一起使用的選項。如果不指定任何選項的來執行 git reset,將留存在工作區的檔案中,這是因為 --mixed 是預設值。如果我們暫存檔案並在此提交,將會獲得相同的提交內容。但我們會得到一個不同的提交 SHA,這是因為提交的時間戳與原來的時間戳不同,但提交內容將完全一樣。

這裡寫圖片描述

如果使用 --soft 選項,會將 SHA 為 3 的提交中所作的更改移動到暫存區,這些更改冉冉相同,而且已經暫存好了,我們要做的只是執行 git commit 來重新提交,同樣由於時間戳不同,所以新提交的 SHA 也會不同。

這裡寫圖片描述

--hard 選項,它會刪除 SHA 為 3 的提交中所作的所有更改。

備份分支

在進行任何重置操作之前,我通常會在最近的 commit 上建立一個 backup 分支,因此如果出現錯誤,我可以返回這些 commit:

$ git branch backup

如果你在重置任何內容前建立了 backup 分支,那麼你可以輕鬆地讓 master 分支指向 backup 分支所指向的同一 commit。你只需:

  • 從工作目錄中刪除未 commit 的更改
  • backup 合併到 master(這將導致快進合併並使 master 向上移到和 backup 一樣的點)

Git 文件的 git-reset

相關文章