2016-01-31 228 views
0

在git中,如何刪除和重命名文件,從某個分支中的某個提交開始,同時保留每個文件(刪除和重命名)的更改歷史記錄?如何刪除歷史記錄中的刪除和重命名?

我的用例是我帶了一個分支,並從那裏開始一個新的分支,我刪除了一些文件並重新命名了一些其他分支。然後我修改了其餘的(並且經常重命名的)文件(還添加了一些文件)。現在我想恢復到原來的名稱並恢復已刪除的文件(這些文件仍然存在於公共基礎上),同時保留所有內容的歷史記錄。我的最終目標是能夠合併回原始分支(所以without the renames and file deletions that I introduced)。

可以這樣做嗎?我想知道這是多麼容易,尤其是因爲重命名的文件被修改(如此天真地刪除重命名將切斷原始文件和修改之間的歷史鏈接,我反而想保留)...

PS:變化因爲分支分支很廣泛(至少在「清潔」分支上)。

+0

Git不會跟蹤文件名的歷史。這是一個內容跟蹤器;它會在運行時計算來自deltas的文件名更改。 –

+0

「*由於重命名的文件被修改得如此天真,刪除重命名將切斷原始文件和修改之間的歷史鏈接*」這不一定是真的。 Git甚至可以通過文件修改來計算重命名。此外,如果您使用正常提交將文件重命名爲原始名稱,您的分支應該合併正常。 – Schwern

回答

2

您不必重寫歷史記錄即可進行合併工作。您可以恢復重命名並重新引入已刪除的文件,然後進行提交和合並。使用git mv重新命名文件。刪除的文件可以使用git checkout <rev-which-deleted-the-file>^ -- <filename>恢復。 See this answer for details

刪除並重新命名的文件可以使用git-log--diff-filter找到。

Git不存儲重命名,它用一些啓發式方法計算它們以處理小編輯。 git-loggit-diffgit-blame都像-C-M選項來控制的Git如何努力找到複製和重命名(移動)文件。所以歷史的連續性不一定會被分支中的重新命名所遺失。


如果你真的想重寫歷史,第一次發現使用git log --diff-filter=D master..branch其刪除文件的所有更改。然後,您可以使用git rebase -i來更改這些提交併恢復已刪除的文件。

重複寫是有點棘手,因爲你必須撤消重命名,然後重命名該文件在以後的每個承諾。這是git-filter-branch的工作,它可以對一系列提交應用相同的更改。

git filter-branch --tree-filter 'if [ -f new ]; mv new old; fi' master..branch 

--tree-filter運行外殼命令上的每個提交數據並改變了由添加和刪除文件在必要時提交。

和以前一樣,找到你的重命名使用git log --diff-filter=R master..branch

+0

謝謝。我使用了第一種方法(無歷史重寫):'git mv'和'git checkout ...'用於刪除文件。然後我將每個分支合併到另一個分支(並檢查更新)。不知怎的,一個文件的歷史記錄從'git log'中消失了許多。但是,它確實出現在拉取請求中。有沒有辦法獲得這樣的歷史? – EOL

+0

@EOL我不確定你的意思。作爲一個新問題,這會更好。 – Schwern

+0

爲了完整:我從'master'重命名一個文件:'git mv old_name.txt new_name.txt',以便它匹配來自其他分支('production')的名稱。合併'production'後,我在'git log new_name.txt'時沒有看到'new_name.txt'的完整更改歷史記錄。現在我意識到必須執行'git log --follow new_name.txt'才能遵循重命名和列表更改。感謝您的反饋意見。 :) – EOL

0

您可以嘗試在分支點爲違規分支做一個git rebase -i。爲了安全起見,我首先在要破解的分支尖端創建一個新分支,以防萬一(哈!墨菲定律無情)出現問題。

如果變化是非常廣泛的,有辦法自動執行此,但這是更加前途未卜。有關詳細信息,請參閱Pro git book

+0

我相信'git rebase -i'的問題是,如果您在一次提交中撤消重命名,則任何更改了重命名文件的提交都將導致衝突或導致文件副本出現。 – Schwern

+0

@Schwern,「不要刪除文件」是什麼原因導致衝突,如果一些稍後提交重新創建它。你必須決定你想要什麼,沒有辦法, – vonbrand

+0

謝謝。不幸的是,這些變化很... – EOL

相關問題