萬盛學電腦網

 萬盛學電腦網 >> Linux教程 >> Linux系統如何在Git裡撤銷操作

Linux系統如何在Git裡撤銷操作

  可以說,所有的操作系統都有撤銷的操作,Linux系統當然也不例外。而且在Linux的 Git中就可以撤銷掉絕大部分的錯誤操作,一起來看一下吧。

  當你進行一次新的提交的時候,Git 會保存你代碼庫在那個特定時間點的快照;之後,你可以利用 Git 返回到你的項目的一個早期版本。

  在本篇博文裡,我會講解某些你需要“撤銷”已做出的修改的常見場景,以及利用 Git 進行這些操作的最佳方法。

Linux系統如何在Git裡撤銷操作

  撤銷一個“已公開”的改變

  場景: 你已經執行了 git push, 把你的修改發送到了 GitHub,現在你意識到這些 commit 的其中一個是有問題的,你需要撤銷那一個 commit.

  方法: git revert 《SHA》

  原理: git revert 會產生一個新的 commit,它和指定 SHA 對應的 commit 是相反的(或者說是反轉的)。如果原先的 commit 是“物質”,新的 commit 就是“反物質” — 任何從原先的 commit 裡刪除的內容會在新的 commit 裡被加回去,任何在原先的 commit 裡加入的內容會在新的 commit 裡被刪除。

  這是 Git 最安全、最基本的撤銷場景,因為它並不會改變歷史 — 所以你現在可以 git push 新的“反轉” commit 來抵消你錯誤提交的 commit。

  修正最後一個 commit 消息

  場景: 你在最後一條 commit 消息裡有個筆誤,已經執行了 git commit -m “Fxies bug #42”,但在 git push 之前你意識到消息應該是 “Fixes bug #42″。

  方法: git commit --amend 或 git commit --amend -m “Fixes bug #42”

  原理: git commit --amend 會用一個新的 commit 更新並替換最近的 commit ,這個新的 commit 會把任何修改內容和上一個 commit 的內容結合起來。如果當前沒有提出任何修改,這個操作就只會把上次的 commit 消息重寫一遍。

  撤銷“本地的”修改

  場景: 一只貓從鍵盤上走過,無意中保存了修改,然後破壞了編輯器。不過,你還沒有 commit 這些修改。你想要恢復被修改文件裡的所有內容 — 就像上次 commit 的時候一模一樣。

  方法: git checkout -- 《bad filename》

  原理: git checkout 會把工作目錄裡的文件修改到 Git 之前記錄的某個狀態。你可以提供一個你想返回的分支名或特定 SHA ,或者在缺省情況下,Git 會認為你希望 checkout 的是 HEAD,當前 checkout 分支的最後一次 commit。

  記住:你用這種方法“撤銷”的任何修改真的會完全消失。因為它們從來沒有被提交過,所以之後 Git 也無法幫助我們恢復它們。你要確保自己了解你在這個操作裡扔掉的東西是什麼!(也許可以先利用 git diff 確認一下)

  重置“本地的”修改

  場景: 你在本地提交了一些東西(還沒有 push),但是所有這些東西都很糟糕,你希望撤銷前面的三次提交 — 就像它們從來沒有發生過一樣。

  方法: git reset 《last good SHA》 或 git reset --hard 《last good SHA》

  原理: git reset 會把你的代碼庫歷史返回到指定的 SHA 狀態。 這樣就像是這些提交從來沒有發生過。缺省情況下, git reset 會保留工作目錄。這樣,提交是沒有了,但是修改內容還在磁盤上。這是一種安全的選擇,但通常我們會希望一步就“撤銷”提交以及修改內容 — 這就是 --hard 選項的功能。

  在撤銷“本地修改”之後再恢復

  場景: 你提交了幾個 commit,然後用 git reset --hard 撤銷了這些修改(見上一段),接著你又意識到:你希望還原這些修改!

  方法: git reflog 和 git reset 或 git checkout

  原理: git reflog 對於恢復項目歷史是一個超棒的資源。你可以恢復幾乎 任何東西 — 任何你 commit 過的東西 — 只要通過 reflog。

  你可能已經熟悉了 git log 命令,它會顯示 commit 的列表。 git reflog 也是類似的,不過它顯示的是一個 HEAD 發生改變的時間列表。 上一頁1234下一頁共4頁

  一些注意事項:

  它涉及的只是 HEAD 的改變。在你切換分支、用 git commit 進行提交、以及用 git reset 撤銷 commit 時,HEAD 會改變,但當你用 git checkout -- 《bad filename》 撤銷時(正如我們在前面講到的情況),HEAD 並不會改變 — 如前所述,這些修改從來沒有被提交過,因此 reflog 也無法幫助我們恢復它們。

  git reflog 不會永遠保持。Git 會定期清理那些 “用不到的” 對象。不要指望幾個月前的提交還一直躺在那裡。

  你的 reflog 就是你的,只是你的。你不能用 git reflog 來恢復另一個開發者沒有 push 過的 commit。

Linux系統如何在Git裡撤銷操作

  那麼…你怎麼利用 reflog 來“恢復”之前“撤銷”的 commit 呢?它取決於你想做到的到底是什麼:

  如果你希望准確地恢復項目的歷史到某個時間點,用 git reset --hard 《SHA》

  如果你希望重建工作目錄裡的一個或多個文件,讓它們恢復到某個時間點的狀態,用 git checkout 《SHA》 -- 《filename》

  如果你希望把這些 commit 裡的某一個重新提交到你的代碼庫裡,用 git cherry-pick 《SHA》

  利用分支的另一種做法

  場景: 你進行了一些提交,然後意識到你開始 check out 的是 master 分支。你希望這些提交進到另一個特性(feature)分支裡。

  方法: git branch feature, git reset --hard origin/master, and git checkout feature

  原理: 你可能習慣了用 git checkout -b 《name》 創建新的分支 — 這是創建新分支並馬上 check out 的流行捷徑 — 但是你不希望馬上切換分支。這裡, git branch feature 創建一個叫做 feature 的新分支並指向你最近的 commit,但還是讓你 check out 在 master 分支上。

  下一步,在提交任何新的 commit 之前,用 git reset --hard 把 master 分支倒回 origin/master。不過別擔心,那些 commit 還在 feature 分支裡。

  最後,用 git checkout 切換到新的 feature 分支,並且讓你最近所有的工作成果都完好無損。

  及時分支,省去繁瑣

  場景: 你在 master 分支的基礎上創建了 feature 分支,但 master 分支已經滯後於 origin/master 很多。現在 master 分支已經和 origin/master 同步,你希望在 feature 上的提交是從現在開始,而不是也從滯後很多的地方開始。

  方法: git checkout feature 和 git rebase master

  原理: 要達到這個效果,你本來可以通過 git reset (不加 --hard, 這樣可以在磁盤上保留修改) 和 git checkout -b 《new branch name》 然後再重新提交修改,不過這樣做的話,你就會失去提交歷史。我們有更好的辦法。

  git rebase master 會做如下的事情:

  首先它會找到你當前 check out 的分支和 master 分支的共同祖先。

  然後它 reset 當前 check out 的分支到那個共同祖先,在一個臨時保存區存放所有之前的提交。

  然後它把當前 check out 的分支提到 master 的末尾部分,並從臨時保存區重新把存放的 commit 提交到 master 分支的最後一個 commit 之後。 上一頁12 34下一頁共4頁

  大量的撤銷/恢復

  場景: 你向某個方向開始實現一個特性,但是半路你意識到另一個方案更好。你已經進行了十幾次提交,但你現在只需要其中的一部分。你希望其他不需要的提交統統消失。

  方法: git rebase -i 《earlier SHA》

  原理: -i 參數讓 rebase 進入“交互模式”。它開始類似於前面討論的 rebase,但在重新進行任何提交之前,它會暫停下來並允許你詳細地修改每個提交。

  rebase -i 會打開你的缺省文本編輯器,裡面列出候選的提交。如下所示:

Linux系統如何在Git裡撤銷操作
copyright © 萬盛學電腦網 all rights reserved