如何修復錯誤的合併,並將好的提交重播到固定的合併中?

我無心間將一個不須要的文件(解析合併時的filename.orig )提交到個人存儲庫中,但以前沒有提交,直到如今我尚未注意到。 我想從存儲庫歷史記錄中徹底刪除該文件。 html

是否有可能重寫更改歷史記錄,以使filename.orig從未被添加到存儲庫中? java


#1樓

您還可使用: git

git reset HEAD file/path github


#2樓

重寫Git歷史記錄要求更改全部受影響的提交ID,所以,從事該項目的每一個人都須要刪除其回購的舊副本,並在清理歷史記錄後進行新的克隆。 帶來不便的人越多,您須要作它的理由就越多-多餘的文件並無真正引發問題,可是若是只是在從事該項目,那麼您也能夠清理Git歷史記錄至! shell

爲了使它儘量容易,我建議使用BFG Repo-Cleaner ,這是專門爲從Git歷史記錄中刪除文件而設計的git-filter-branch的更簡單,更快的替代方法。 一種使您的生活更輕鬆的方法是,它實際上默認處理全部引用(全部標記,分支等),但速度也提升了10-50倍bash

您應該仔細按照如下步驟進行操做: http : //rtyley.github.com/bfg-repo-cleaner/#usage-可是核心部分是這樣:下載BFG jar (須要Java 6或更高版本)並運行此命令: 編輯器

$ java -jar bfg.jar --delete-files filename.orig my-repo.git

您的整個存儲庫歷史記錄將被掃描,任何名爲filename.orig (不在您的最新 commit中 )將被刪除。 這比使用git-filter-branch作一樣的事情要容易得多! ide

徹底公開:我是BFG Repo-Cleaner的做者。 工具


#3樓

只是將其添加到Charles Bailey的解決方案中,我只是使用了git rebase -i從較早的提交中刪除不須要的文件,它的工做原理很吸引人。 步驟: 性能

# Pick your commit with 'e'
$ git rebase -i

# Perform as many removes as necessary
$ git rm project/code/file.txt

# amend the commit
$ git commit --amend

# continue with rebase
$ git rebase --continue

#4樓

這是最好的方法:
http://github.com/guides/completely-remove-a-file-from-all-revisions

只要確保首先備份文件的副本便可。

編輯

不幸的是, Neon的編輯在審覈期間被拒絕。
請參閱下面的霓虹燈發佈,其中可能包含有用的信息!


例如,刪除全部意外提交到git存儲庫中的*.gz文件:

$ du -sh .git ==> e.g. 100M
$ git filter-branch --index-filter 'git rm --cached --ignore-unmatch *.gz' HEAD
$ git push origin master --force
$ rm -rf .git/refs/original/
$ git reflog expire --expire=now --all
$ git gc --prune=now
$ git gc --aggressive --prune=now

那對我仍是沒有用? (我目前是git版本1.7.6.1)

$ du -sh .git ==> e.g. 100M

不知道爲何,由於我只有一個master分支。 不管如何,我終於經過推送到一個新的空的和裸露的git倉庫中來真正清理了git倉庫。

$ git init --bare /path/to/newcleanrepo.git
$ git push /path/to/newcleanrepo.git master
$ du -sh /path/to/newcleanrepo.git ==> e.g. 5M

(是!)

而後,將其克隆到一個新目錄,並將其.git文件夾移至該目錄中。 例如

$ mv .git ../large_dot_git
$ git clone /path/to/newcleanrepo.git ../tmpdir
$ mv ../tmpdir/.git .
$ du -sh .git ==> e.g. 5M

(是的!終於收拾了!)

確認一切正常後,您能夠刪除../large_dot_git../tmpdir目錄(也許從如今起幾個星期或一個月,以防萬一...)


#5樓

簡介:您有5種解決方案可用

原始海報指出:

我不當心將不須要的文件提交給存儲庫,幾回提交以前,我想從存儲庫歷史記錄中徹底刪除該文件。

是否有可能重寫更改歷史記錄,以使filename.orig從未被添加到存儲庫中?

有不少不一樣的方法能夠從git中徹底刪除文件的歷史記錄:

  1. 修改提交。
  2. 硬重置(可能須要從新設置基準)。
  3. 非交互式變基。
  4. 交互式基準。
  5. 過濾分支。

對於原始海報,修改提交自己並非一個真正的選擇,由於他隨後進行了幾回其餘提交,可是爲了完整起見,我還將爲任何想要的人解釋如何作修改他們之前的提交。

請注意,全部這些解決方案都以另外一種方式涉及更改/重寫歷史記錄/提交,所以擁有舊提交副本的任何人都必須作額外的工做才能將其歷史記錄與新歷史記錄從新同步。


解決方案1:修改提交

若是您在上一次提交中無心中進行了更改(例如添加文件),而且您不想再存在該更改的歷史記錄,則只需修改上一次提交以從中刪除文件便可:

git rm <file>
git commit --amend --no-edit

解決方案2:硬重置(可能加上一個變基)

像解決方案1同樣,若是您只是想擺脫之前的提交,那麼您還能夠選擇簡單地對其父級進行硬重置:

git reset --hard HEAD^

該命令會將您的分支硬重置爲先前的第一個父提交。

可是 ,若是像原始發佈者同樣,在要撤消更改的提交以後進行了幾回提交,則仍然可使用硬重置來對其進行修改,可是這樣作還涉及使用從新設置基準。 您可使用如下步驟修改歷史記錄中的提交:

# Create a new branch at the commit you want to amend
git checkout -b temp <commit>

# Amend the commit
git rm <file>
git commit --amend --no-edit

# Rebase your previous branch onto this new commit, starting from the old-commit
git rebase --preserve-merges --onto temp <old-commit> master

# Verify your changes
git diff master@{1}

解決方案3:非交互式Rebase

若是您只想從歷史記錄中徹底刪除提交,這將起做用:

# Create a new branch at the parent-commit of the commit that you want to remove
git branch temp <parent-commit>

# Rebase onto the parent-commit, starting from the commit-to-remove
git rebase --preserve-merges --onto temp <commit-to-remove> master

# Or use `-p` insteda of the longer `--preserve-merges`
git rebase -p --onto temp <commit-to-remove> master

# Verify your changes
git diff master@{1}

解決方案4:交互式基準

經過此解決方案,您能夠完成與解決方案2和#3相同的任務,即,修改或刪除歷史記錄中的提交要比直接提交更早,所以您選擇使用哪一種解決方案取決於您本身。 出於性能方面的考慮,交互式rebase不太適合對數百個提交進行從新計算,所以在這種狀況下,我將使用非交互式rebase或filter分支解決方案(請參閱下文)。

要開始交互式變基,請使用如下命令:

git rebase --interactive <commit-to-amend-or-remove>~

# Or `-i` instead of the longer `--interactive`
git rebase -i <commit-to-amend-or-remove>~

這將致使git將提交歷史回滾到您要修改或刪除的提交的父級。 而後,它將以設置爲git的任何編輯器(以默認方式爲Vim)的反向順序顯示從新提交的列表:

pick 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`
pick 7668f34 Modify Bash config to use Homebrew recommended PATH
pick 475593a Add global .gitignore file for OS X
pick 1b7f496 Add alias for Dr Java to Bash config (OS X)

您要修改或刪除的提交將在此列表的頂部。 要刪除它,只需在列表中刪除它的行便可。 不然,將「選擇」與第1行「編輯」,就像這樣:

edit 00ddaac Add symlinks for executables
pick 03fa071 Set `push.default` to `simple`

接下來,輸入git rebase --continue 。 若是您選擇徹底刪除提交,那麼這就是您須要作的全部事情(除了驗證,請參閱此解決方案的最後一步)。 另外一方面,若是您想修改提交,則git將從新應用提交,而後暫停從新設置基準。

Stopped at 00ddaacab0a85d9989217dd9fe9e1b317ed069ac... Add symlinks
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

此時,您能夠刪除文件並修改提交,而後繼續進行變基:

git rm <file>
git commit --amend --no-edit
git rebase --continue

而已。 做爲最後一步,不管您是修改提交仍是徹底刪除提交,經過將其與從新設置基準以前的狀態進行比較來驗證對分支沒有其餘意外更改始終是一個好主意:

git diff master@{1}

解決方案5:過濾分支

最後,若是您想從歷史記錄中完全清除文件存在的全部痕跡,而且沒有其餘解決方案可以徹底勝任該任務,則此解決方案是最佳選擇。

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>'

從根提交開始,這將從全部提交中刪除<file> 。 相反,若是您只想重寫提交範圍HEAD~5..HEAD ,則能夠HEAD~5..HEAD做爲附加參數傳遞給filter-branch ,如該答案所指出:

git filter-branch --index-filter \
'git rm --cached --ignore-unmatch <file>' HEAD~5..HEAD

一樣,在filter-branch完成以後,一般最好經過將分支與過濾操做以前的先前狀態進行區分來驗證是否沒有其餘意外更改:

git diff master@{1}

分支過濾器:BFG回購清潔器

我據說BFG Repo Cleaner工具的運行速度比git filter-branch快,所以您也能夠選擇將其檢查出來。 過濾器分支文檔中甚至正式提到了可行的替代方法:

git-filter-branch容許您對Git歷史記錄進行復雜的shell腳本重寫,可是若是您只是刪除不須要的數據(例如大文件或密碼),則可能不須要這種靈活性。 對於這些操做,您可能須要考慮使用BFG Repo-Cleaner ,它是git-filter-branch的基於JVM的替代品,對於這些用例,一般至少快10-50倍,而且具備徹底不一樣的特性:

  • 文件的任何特定版本僅清除一次 。 BFG與git-filter-branch不一樣,它沒有給您機會根據文件在歷史記錄中的提交位置或時間對文件進行不一樣的處理。 該約束爲BFG提供了核心性能優點,而且很是適合清理不良數據的任務-您不在意不良數據在哪裏 ,只但願它消失了

  • 默認狀況下,BFG充分利用了多核計算機的優點,能夠並行清除提交文件樹。 git-filter-branch按順序清理提交(即以單線程方式),儘管可能在針對每一個提交執行的腳本中編寫包含其自身並行性的過濾器。

  • 命令選項比git-filter分支的限制要嚴格得多,僅用於刪除不須要的數據的任務,例如:-- --strip-blobs-bigger-than 1M

其餘資源

  1. Pro Git§6.4 Git工具-重寫歷史記錄
  2. git-filter-branch(1)手冊頁
  3. git-commit(1)手冊頁
  4. git-reset(1)手冊頁
  5. git-rebase(1)手冊頁
  6. BFG回購清潔器 (另請參閱建立者本人的回答 )。
相關文章
相關標籤/搜索