from - git revert教學




如何將Git存儲庫還原為先前的提交 (20)

如何從當前狀態恢復為在某個提交時創建的快照?

如果我做git log ,那麼我得到以下輸出:

$ git log
commit a867b4af366350be2e7c21b8de9cc6504678a61b`
Author: Me <[email protected]>
Date:   Thu Nov 4 18:59:41 2010 -0400

blah blah blah...

commit 25eee4caef46ae64aa08e8ab3f988bc917ee1ce4
Author: Me <[email protected]>
Date:   Thu Nov 4 05:13:39 2010 -0400

more blah blah blah...

commit 0766c053c0ea2035e90f504928f8df3c9363b8bd
Author: Me <[email protected]>
Date:   Thu Nov 4 00:55:06 2010 -0400

And yet more blah blah...

commit 0d1d7fc32e5a947fbd92ee598033d85bfc445a50
Author: Me <[email protected]>
Date:   Wed Nov 3 23:56:08 2010 -0400

Yep, more blah blah.

如何從11月3日恢復提交,即提交0d1d7fc


警告!如果用戶錯誤地提交了錯誤的提交,則此命令可能導致丟失提交歷史記錄。總是有你額外的git備份,以防萬一你犯錯誤,比你更安全一些。 :)

我有類似的問題,並希望恢復到早期的提交。在我的情況下,我沒有完全保持更新的提交因此我使用Hard

這就是我做的方式:

git reset --hard CommitId && git clean -f

這將在本地存儲庫上恢復,此處使用git push -f後將更新遠程存儲庫。

git push -f

Jefromi解決方案的額外替代品

Jefromi的解決方案絕對是最好的,你絕對應該使用它們。 但是,為了完整起見,我還想展示這些其他替代解決方案,這些解決方案也可用於恢復提交(在某種意義上,您創建一個新的提交,撤消先前提交中的更改 ,就像git revert那樣) 。

要清楚,這些替代方案並不是恢復提交的最佳方式 , Jefromi的解決方案是 ,但我只想指出,您也可以使用這些其他方法來實現與git revert相同的功能。

備選方案1:硬重置和軟重置

這是Charles Bailey 在Git中通過SHA哈希恢復提交的解決方案的略微修改版本

# Reset the index to the desired commit
git reset --hard <commit>

# Move the branch pointer back to the previous HEAD
git reset --soft [email protected]{1}

# Commit the changes
git commit -m "Revert to <commit>"

這基本上可以通過使用軟重置將使先前提交的狀態保留在索引/暫存區域中的事實來實現,然後您可以提交該區域。

備選方案2:刪除當前樹並替換為新樹

這個解決方案來自svick對Checkout舊提交的解決方案, 並使其成為新的提交

git rm -r .
git checkout <commit> .
git commit

與備選#1類似,這將再現當前工作副本中<commit>的狀態。 首先需要執行git rm因為git checkout不會刪除自<commit>以來添加的文件。


將工作副本還原為最近的提交

要恢復到先前的提交,請忽略任何更改:

git reset --hard HEAD

其中HEAD是當前分支中的最後一次提交

將工作副本還原為較舊的提交

要恢復到比最近提交更早的提交:

# Resets index to former commit; replace '56e05fced' with your commit code
git reset 56e05fced 

# Moves pointer back to previous HEAD
git reset --soft [email protected]{1}

git commit -m "Revert to 56e05fced"

# Updates working copy to reflect the new commit
git reset --hard

Credits轉到類似的問題, 在Git中恢復為SHA哈希的提交?


好的,回到以前的git提交很容易......

不保留更改的情況下還原:

git reset --hard <commit>

通過保留更改來恢復:

git reset --soft <commit>

解釋:使用git reset,你可以重置為一個特定的狀態,如上所述,它通常使用提交哈希。

但正如你所看到的區別是使用兩個標誌--soft--hard ,默認情況下git reset使用--soft標誌,但這是一個很好的做法總是使用標誌,我解釋每個標誌:

- 柔軟的

所解釋的默認標誌(不需要提供它)不會更改工作樹,而是添加準備提交的所有更改文件,因此您將返回到提交狀態,該更改為文件的未提交狀態。

- 硬

小心這個標誌,它會重置工作樹以及對跟踪文件的所有更改,一切都將消失!

我還創建了下面的圖像,可能發生在使用git的現實生活中:


假設你在一個名為~/commits-to-revert.txt的文本文件中有以下提交(我使用git log --pretty=oneline來獲取它們)

fe60adeba6436ed8f4cc5f5c0b20df7ac9d93219
0c27ecfdab3cbb08a448659aa61764ad80533a1b
f85007f35a23a7f29fa14b3b47c8b2ef3803d542
e9ec660ba9c06317888f901e3a5ad833d4963283
6a80768d44ccc2107ce410c4e28c7147b382cd8f
9cf6c21f5adfac3732c76c1194bbe6a330fb83e3
fff2336bf8690fbfb2b4890a96549dc58bf548a5
1f7082f3f52880cb49bc37c40531fc478823b4f5
e9b317d36a9d1db88bd34831a32de327244df36a
f6ea0e7208cf22fba17952fb162a01afb26de806
137a681351037a2204f088a8d8f0db6e1f9179ca

創建一個Bash shell腳本來還原每個腳本:

#!/bin/bash
cd /path/to/working/copy
for i in `cat ~/commits-to-revert.txt`
do
    git revert $i --no-commit
done

這會將所有內容還原回以前的狀態,包括文件和目錄創建以及刪除,將其提交到您的分支並保留歷史記錄,但是您將其還原為相同的文件結構。 為什麼Git沒有git revert --to <hash>超出我的範圍。


假設您正在談論主人和相應的分支(也就是說,這可能是您關注的任何工作分支):

# Revert local master branch to November 3rd commit ID
git reset --hard 0d1d7fc32e5a947fbd92ee598033d85bfc445a50

# Revert remote master branch to November 3rd commit ID
git push -f origin 0d1d7fc32e5a947fbd92ee598033d85bfc445a50:master

我在博客文章中找到了將遠程Git倉庫刪除到特定提交的答案。


在回答之前,讓我們添加一些背景,解釋這個HEAD是什麼。

First of all what is HEAD?

HEAD只是對當前分支上當前提交(最新)的引用。 在任何給定時間只能有一個HEAD (不包括git worktree )。

HEAD的內容存儲在.git/HEAD ,它包含當前提交的40字節SHA-1。

detached HEAD

如果你沒有進行最新的提交 - 意味著HEAD指向歷史記錄中的先前提交,則稱為detached HEAD

在命令行上它看起來像這樣 - SHA-1而不是分支名稱,因為HEAD沒有指向當前分支的尖端:

關於如何從分離的HEAD中恢復的幾個選項:

git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

這將檢查指向所需提交的新分支。 此命令將簽出到給定的提交。

此時,您可以創建一個分支,並從這一點開始工作:

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

您也可以隨時使用refloggit reflog將顯示更新HEAD任何更改,並且檢出所需的reflog條目會將HEAD設置回此提交。

每次修改HEAD時, reflog都會有一個新條目

git reflog
git checkout HE[email protected]{...}

這將使您回到所需的提交

git reset HEAD --hard <commit_id>

“移動”你的頭回到所需的提交。

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.
  • 注意:( 自Git 2.7起 )您也可以使用git rebase --no-autostash

此架構說明了哪個命令執行的操作。 如您所見, reset && checkout修改HEAD


如果要“取消提交”,擦除最後一次提交消息,並將修改後的文件放回到分段中,則可以使用以下命令:

git reset --soft HEAD~1
  • --soft表示未提交的文件應保留為與--hard相對的工作文件,這將丟棄它們。
  • HEAD~1是最後一次提交。 如果你想回滾3次提交,你可以使用HEAD~3 。 如果要回滾到特定的修訂版號,也可以使用其SHA哈希來執行此操作。

在您提交了錯誤的內容並且想要撤消上次提交的情況下,這是一個非常有用的命令。

資料來源: http://nakkaya.com/2009/09/24/git-delete-last-commit/http://nakkaya.com/2009/09/24/git-delete-last-commit/


對於回滾(或恢復):

  1. git revert --no-commit“commit-code-to-remove”HEAD(例如git revert --no-commit d57a39d HEAD)
  2. git commit
  3. git push

嘗試以上兩個步驟,如果你發現這是你想要的那麼git push。

如果你發現錯誤的話:

git revert --abort


恢復到最近的提交並忽略所有本地更改:

git reset --hard HEAD

您可以通過以下兩個命令執行此操作:

git reset --hard [previous Commit SHA id here]
git push origin [branch Name] -f

它將刪除您之前的Git提交。

如果您想保留更改,還可以使用:

git reset --soft [previous Commit SHA id here]

然後它將保存您的更改。


我和其他人的最佳選擇是Git重置選項:

git reset --hard <commidId> && git clean -f

這對我來說是最好的選擇! 它簡單,快速,有效!

注意: 正如評論中所述,如果您與擁有舊提交副本的其他人共享您的分支,則不會這樣做

同樣來自評論,如果你想要一個較少'ballzy'的方法,你可以使用

git clean -i



有一個命令(不是核心Git的一部分,但它在git-extras包中)專門用於恢復和暫存舊提交:

git back

根據手冊頁 ,它也可以這樣使用:

# Remove the latest three commits
git back 3

要保持從先前提交到HEAD的更改並移至上一次提交,請執行以下操作:

git reset <SHA>

如果從先前提交到HEAD不需要更改並且只丟棄所有更改,請執行以下操作:

git reset --hard <SHA>

這很大程度上取決於“恢復”的含義。

暫時切換到其他提交

如果你想暫時回到它,傻瓜,然後回到你所在的位置,你所要做的就是檢查所需的提交:

# This will detach your HEAD, that is, leave you with no branch checked out:
git checkout 0d1d7fc32

或者,如果你想在那裡做出提交,那麼在你做的時候繼續做一個新的分支:

git checkout -b old-state 0d1d7fc32

要回到原來的位置,只需查看您再次訪問的分支。 (如果你做了更改,就像轉換分支時一樣,你必須在適當的時候處理它們。你可以重置它們扔掉它們;你可以藏匿,結賬,存放pop以帶走它們;你可以提交如果你想要那裡的分支,他們到那裡的一個分支。)

硬刪除未發布的提交

另一方面,如果你想真正擺脫自那時以來所做的一切,那麼有兩種可能性。 一,如果您還沒有發布任何這些提交,只需重置:

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts, if you've modified things which were
# changed since the commit you reset to.

如果你陷入困境,你已經拋棄了你的本地變化,但你至少可以通過重新設置來回到原來的位置。

使用新提交撤消已發布的提交

另一方面,如果您已發布作品,則可能不希望重置分支,因為這有效地重寫了歷史記錄。 在這種情況下,您確實可以還原提交。 使用Git,revert有一個非常具體的含義:使用反向補丁創建一個提交以取消它。 這樣您就不會重寫任何歷史記錄。

# This will create three separate revert commits:
git revert a867b4af 25eee4ca 0766c053

# It also takes ranges. This will revert the last two commits:
git revert HEAD~2..HEAD

#Similarly, you can revert a range of commits using commit hashes:
git revert a867b4af..0766c053 

# Reverting a merge commit
git revert -m 1 <merge_commit_sha>

# To get just one, you could use `rebase -i` to squash them afterwards
# Or, you could do it manually (be sure to do this at top level of the repo)
# get your index and work tree into the desired state, without changing HEAD:
git checkout 0d1d7fc32 .

# Then commit. Be sure and write a good message describing what you just did
git commit

git-revert實際上在其描述中涵蓋了很多內容。 另一個有用的鏈接是這個討論git-revert的git-scm.com部分

如果您決定不想還原,則可以還原還原(如此處所述)或重置為還原之前(請參閱上一節)。

在這種情況下,您可能會發現此答案很有用:
如何將HEAD移回以前的位置? (獨立頭)


這裡有很多複雜而危險的答案,但實際上很簡單:

git revert --no-commit 0766c053..HEAD
git commit

這將從HEAD返回到提交哈希的所有內容,這意味著它將在工作樹中重新創建該提交狀態, 就好像每次提交都已經被回退一樣。 然後,您可以提交當前樹,它將創建一個全新的提交,基本上等同於您“恢復”的提交。

--no-commit標誌允許git立即恢復所有提交 - 否則,系統會提示您為該範圍內的每個提交發送一條消息,並使用不必要的新提交亂丟您的歷史記錄。)

這是回滾到以前狀態安全且簡單的方法 。 沒有歷史被破壞,因此它可以用於已經公開的提交。


選擇所需的提交,然後進行檢查

git show HEAD
git show HEAD~1
git show HEAD~2 

直到你得到所需的提交。 為了使HEAD指向那個,做

git reset --hard HEAD~1

或者git reset --hard HEAD~2或者其他什麼。


如果你想在最後一次提交中糾正一些錯誤,那麼一個好的選擇就是使用git commit --amend命令。如果任何引用都沒有指向最後一次提交,那麼這將起到作用,因為它創建一個與最後一次提交具有相同父級的提交。如果沒有對最後一次提交的引用,它將被簡單地丟棄,並且此提交將是最後一次提交。這是在不恢復提交的情況下糾正提交的好方法。但它有其自身的局限性。


如果情況緊急,你只是想以快速而骯髒的方式做提問者的問題,假設你的項目在“我的項目”目錄下:

  1. 複製整個目錄並將其稱為其他內容,例如“我的項目 - 複製”

  2. 做:

    git reset --hard [first-4-letters&numbers-of-commit's-SHA]
    

然後,您的系統上有兩個版本...您可以檢查或複製或修改先前提交中感興趣的文件或其他任何內容。你可以完全放棄“我的項目 - 複製”下的文件,如果你已經決定新的工作無處可去......

很明顯,如果你想繼續執行項目狀態而不實際丟棄工作,因為這個檢索到的提交是重新命名你的目錄:刪除包含檢索到的提交的項目(或給它一個臨時名稱)並重命名你的“我的項目 - 將“目錄複製回”我的項目“。然後可能很快就會做另一次提交。

Git是一個出色的創作,但你不能只是“隨時拿起它”:試圖解釋它的人也經常假設其他VCS [版本控制系統]的先驗知識,並且過早地鑽研太深,並且犯下其他罪行,比如使用可互換的術語來“退出” - 這種方式有時似乎幾乎可以使初學者感到困惑。

為了節省很多壓力,你必須要讀一本關於Git的書 - 我建議使用Git進行版本控制。如果你能信任我(或者更確切地說,我的傷疤),當我說“有”,它遵循你還不如做NOW。Git的大部分複雜性來自分支然後重新合併。但是從你的問題來看,沒有理由為什麼人們應該用科學讓你眼花繚亂

特別是如果,例如,這是一個絕望的情況,你是Git的新手!

PS:另一個想法:將(現在)將Git存儲庫(“repo”)保存在除工作文件之外的目錄中實際上非常簡單。這意味著你不必使用上面的快速和臟的解決方案來複製整個Git存儲庫。使用--separate-混帳目錄見油炸答案here但是要注意:如果你有一個你沒有復制的“單獨目錄”存儲庫,並且你進行了硬復位,那麼重置提交之後的所有版本將永遠丟失,除非你有絕對應該的,定期備份您的存儲庫,最好是其他地方的雲(例如Google Drive)。







git-revert