2015-08-19 129 views
7

假設我有一個文件a.txt。有一天,我刪除了它,承諾並推送了它。Git還原已刪除的文件並保留文件歷史記錄

第二天,我想恢復上次提交,將a.txt帶回。我嘗試使用git revert,但是當我做了git blame時,所有行都顯示了恢復提交哈希。原來的責備歷史已經失傳。

我可以恢復文件並保留文件歷史記錄嗎?就好像文件還沒有被刪除過?請注意,我不能在提交被推送時更改歷史記錄。

謝謝!

+0

您的意思是說您無法對上游進行強制推送? – shengy

+2

Git不會跟蹤文件歷史記錄;它只跟蹤整個根目錄的歷史記錄。因此,在請求查看歷史記錄時,重建文件歷史記錄是一個問題,而不是在恢復文件時。 – Nayuki

+0

@shengy不,我不能 – fushar

回答

0

您可以通過使用git reset而不是git revert來完成。 git reset刪除新提交併簽出先前的提交。如果您已經推向上游,則不推薦這樣做。

NAME 
     git-reset - Reset current HEAD to the specified state 

SYNOPSIS 
     git reset [-q] [<tree-ish>] [--] <paths>... 
     git reset (--patch | -p) [<tree-ish>] [--] [<paths>...] 
     git reset [--soft | --mixed | --hard | --merge | --keep] [-q] [<commit>] 

DESCRIPTION 
     In the first and second form, copy entries from <tree-ish> to the index. In the third form, set the 
     current branch head (HEAD) to <commit>, optionally modifying index and working tree to match. The 
     <tree-ish>/<commit> defaults to HEAD in all forms. 

既然你已經沒推:

  • 如果您有拉那一天沒有活動的合作者,利用git reset並強制推git push -f
+0

他已經刪除了文件並推送到上游,此時'git reset'不適用於他。 – shengy

1

-C選項運行git怪指定三次:

git blame -C -C -C 

這將導致git blame查找從文件在以前提交複製的內容。

the documentation for git blame來自:

-C|<num>|

除了-M,檢測線移動或從其它文件複製的 是在相同的修改提交。當您重新組織 並在代碼中移動代碼時,這非常有用。當這個選項是 給出兩次時,該命令另外在創建該文件的提交中查找來自其他 文件的副本。當這個選項被給予 三次時,該命令另外在任何提交中查找來自其他 文件的副本。

<num>是可選的,但它是下界上GIT中必須檢測 文件之間作爲移動/複製爲它與母提交這些線相關聯的字母數字 字符數。 默認值爲40.如果給出的選項不止一個-C,則最後的-C的參數 <num>將生效。

+0

你確定這有效嗎?我試過類似'git init'' echo「test」> a.txt'''git add a.txt''git commit -m「Commit 1」''echo「foobar」>> a.txt''git add a.txt'git commit -m'Commit 2'''git rm a.txt''git commit -m「Commit 3」''git revert HEAD''git blame -C -C -C a.txt' and這兩行顯示恢復提交... – fushar

+0

@fushar我敢肯定,你需要多個單詞讓git註冊你移動了一些東西,文檔中說最少有40個字符,我在我的回答中編輯了引用 – Ajedi32

+0

我只是想表明你的解決方案在最簡單的例子中不起作用,實際上它並不適用於我的真實項目(我刪除的文件內容遠遠大於40)。 - 'git blame -C1 -C1 -C1 a.txt'不幸也不適用於'a.txt'的例子。 – fushar

2

CAN做到這一點!方法如下:

  1. 從您想要撤消的刪除之前的提交開始一個新的分支。
  2. 將違規更改與git merge <sha> -s ours合併。
  3. 如果除了刪除要保持提交了變化:
    1. git diff <sha>^..<sha> | git apply重新應用更改到你的工作副本。
    2. 放棄刪除(許多技術可用; git checkout -p可能適合您)。
  4. 將此分支合併回主分支(例如主)。

這產生了兩個分支的歷史;其中一個文件被刪除,其中一個它從未被刪除。因此,git能夠跟蹤文件歷史,而不訴諸於諸如-C -C -C這樣的英雄。 (事實上​​,即使使用-C -C -C,該文件也不會被「恢復」,因爲git會看到的是,一個新文件被創建爲作爲先前存在文件的副本。使用此技術,您將重新引入相同的文件)。

+0

作品像一種享受,我現在學到了東西,謝謝@Matthew!我的情況相當複雜,我需要閱讀一下'git checkout -p',但即使在部分違規提交中進行了混合更改,此方法也完全按照我需要的方式工作。 – bossi

相關問題