我需要重寫分支,放棄對特定子文件夾(例如,其路徑爲path/to/folder
)所做的所有更改及其內容在從指定的start
修訂版開始的修訂範圍之間並在HEAD
結束。接受start
修訂版之前的更改。如何重寫分支,丟棄對子文件夾的更改
我考慮過使用git-filter-branch
來做到這一點,但不知道使用哪個過濾器。我認爲對每個提交使用'git-reset'到子文件夾可能會有效,但是這個post讓我質疑這種方法是否可行。
問題:如何重寫上面第一段中指定的分支?
我需要重寫分支,放棄對特定子文件夾(例如,其路徑爲path/to/folder
)所做的所有更改及其內容在從指定的start
修訂版開始的修訂範圍之間並在HEAD
結束。接受start
修訂版之前的更改。如何重寫分支,丟棄對子文件夾的更改
我考慮過使用git-filter-branch
來做到這一點,但不知道使用哪個過濾器。我認爲對每個提交使用'git-reset'到子文件夾可能會有效,但是這個post讓我質疑這種方法是否可行。
問題:如何重寫上面第一段中指定的分支?
什麼最終工作是使用git-filter-branch
與git rm
的組合來刪除提交中添加的新文件和'git checkout'來恢復狀態。
git filter-branch -f --prune-empty --index-filter 'git rm -rfq -- path/to/subdir && git checkout -f <the-good-state-sha1> -- path/to/subdir' -- start..HEAD
這裏start
是起始提交和<the-good-state-sha1>
是start
的父的提交的哈希值。 注意:path/to/subdir
需要指定兩次,如圖所示,一次在rm
命令中,一次在checkout
命令中。
使用git-filter-branch與--tree-filter
,可能與--prune-empty
。整個命令序列可以是這樣的:
GOOD_STATE=<some-revision>
DIR_TO_PRESERVE="relative/path/to/directory"
BRANCH_TO_REWRITE=<branch-to-rewrite>
export GOOD_STATE DIR_TO_PRESERVE BRANCH_TO_REWRITE
git filter-branch --tree-filter \
'rm -rf "${DIR_TO_PRESERVE}" && git checkout -f ${GOOD_STATE} -- "${DIR_TO_PRESERVE}"' \
--prune-empty ${BRANCH_TO_REWRITE} --not ${GOOD_STATE}
其更快的替代方案--index-filter
都可以使用。但作爲一個命令,你不應該使用git rm...
,因爲這會完全刪除路徑。相反,你應該使用git reset
重置給定文件夾的索引:
git filter-branch --index-filter \
'git reset -q ${GOOD_STATE} -- "${DIR_TO_PRESERVE}"'' \
--prune-empty ${BRANCH_TO_REWRITE} --not ${GOOD_STATE}
要加快一件事可能會暫時將存儲庫複製到更快的文件系統(我在Linux上使用tmpfs
是什麼,以及使用9007次的提交已被重寫 - 在14分37秒內過濾索引)。
嗯 - 我試圖使用--index-filter使用相同的命令在一個簡單的測試回購,它似乎工作。然而,在數千次提交的實際回購中,卻沒有。你能否提供一個完整的命令行來使用--index-filter?此外,對發生的事情的一些解釋會很好。我不太明白它是如何做到的。 – bright
更新了答案 – user3159253
請舉個例子嗎? – hjpotter92
據我瞭解的[文檔](https://www.kernel.org/pub/software/scm/git/docs/git-filter-branch.html)你應該很好'git filter-branch --index -filter'git rm --cached --ignore-unmatch path/to/folder'commit..HEAD' – Vogel612
這將完全刪除路徑/到/文件夾 – user3159253