你想做什麼將涉及兩個階段:追溯添加一個新的根與一個合適的.gitignore
和擦洗你的歷史記錄,以刪除不應該添加的文件。 git filter-branch
命令可以同時執行這兩個操作。
設置
考慮一下你的歷史的代表。
$ git lola --name-status
* f1af2bf (HEAD, bar-feature) Add bar
| A .gitignore
| A bar.c
| D main.o
| D module.o
| * 71f711a (master) Add foo
|/
| A foo.c
| A foo.o
* 7f1a361 Commit 2
| A module.c
| A module.o
* eb21590 Commit 1
A main.c
A main.o
爲了清楚起見,*.c
文件代表C源文件和*.o
編譯是應該被忽略的對象文件。
在條形特徵分支上,您添加了一個合適的.gitignore
和刪除的不應該被跟蹤的對象文件,但是您希望在導入中無處不在反映該策略。
請注意,git lola
是一個non-standard但是有用的別名。
git config --global alias.lola \
'log --graph --decorate --pretty=oneline --abbrev-commit --all'
新根提交
創建新的根提交如下。
$ git checkout --orphan new-root
Switched to a new branch 'new-root'
git checkout
文檔記錄了新的孤兒分支可能出現的意料之外的狀態。
如果你想開始一個斷開連接的歷史,記錄一組的路徑是從之一start_point完全不同,那麼你應該通過運行創建孤兒分支後立即清除索引和工作樹git rm -rf .
從工作樹的頂層。然後你就可以準備你的新文件,覆育工作樹,通過從其他地方複製它們,提取壓縮包等
繼續我們的例子:
$ git rm -rf .
rm 'foo.c'
rm 'foo.o'
rm 'main.c'
rm 'main.o'
rm 'module.c'
rm 'module.o'
$ echo '*.o' >.gitignore
$ git add .gitignore
$ git commit -m 'Create .gitignore'
[new-root (root-commit) 00c7780] Create .gitignore
1 file changed, 1 insertion(+)
create mode 100644 .gitignore
現在歷史類似
$ git lola
* 00c7780 (HEAD, new-root) Create .gitignore
* f1af2bf(bar-feature) Add bar
| * 71f711a (master) Add foo
|/
* 7f1a361 Commit 2
* eb21590 Commit 1
這有點誤導,因爲它使得新根看起來像是bar-feature的後代,但它確實沒有父項。
$ git rev-parse HEAD^
HEAD^
fatal: ambiguous argument 'HEAD^': unknown revision or path not in the working tree.
Use '--' to separate paths from revisions, like this:
'git <command> [<revision>...] -- [<file>...]'
記下孤兒的SHA,因爲您以後需要它。在這個例子中,它是
$ git rev-parse HEAD
00c778087723ae890e803043493214fb09706ec7
改寫歷史
我們希望git filter-branch
使三大變化。
- 在新的根提交中拼接。
- 刪除所有的臨時文件。
- 使用新的根中的
.gitignore
,除非已經存在。
在命令行上,即incanted爲
git filter-branch \
--parent-filter '
test $GIT_COMMIT = eb215900cd15ca2cf9ded74f1a0d9d25f65eb2bf && \
echo "-p 00c778087723ae890e803043493214fb09706ec7" \
|| cat' \
--index-filter '
git rm --cached --ignore-unmatch "*.o"; \
git ls-files --cached --error-unmatch .gitignore >/dev/null 2>&1 ||
git update-index --add --cacheinfo \
100644,$(git rev-parse new-root:.gitignore),.gitignore' \
--tag-name-filter cat \
-- --all
說明:在你的新的根
- 的
--parent-filter
選項鉤提交。
eb215...
是舊的根提交的完整SHA,比較。git rev-parse eb215
- 的
--index-filter
選項有兩個部分:
- 運行
git rm
如上刪除任何東西,因爲水珠圖案的報價,由混帳解釋,而不是外殼從整個樹匹配*.o
。
- 檢查現有的
.gitignore
與git ls-files
,如果它不在那裏,則指向新根中的那個。
- 如果您有任何標籤,它們將使用標識操作
cat
進行映射。
- 唯一
--
終止選項,--all
是所有參考的簡寫。
您看到的輸出將與
Rewrite eb215900cd15ca2cf9ded74f1a0d9d25f65eb2bf (1/5)rm 'main.o'
Rewrite 7f1a361ee918f7062f686e26b57788dd65bb5fe1 (2/5)rm 'main.o'
rm 'module.o'
Rewrite 71f711a15fa1fc60542cc71c9ff4c66b4303e603 (3/5)rm 'foo.o'
rm 'main.o'
rm 'module.o'
Rewrite f1af2bf89ed2236fdaf2a1a75a34c911efbd5982 (5/5)
Ref 'refs/heads/bar-feature' was rewritten
Ref 'refs/heads/master' was rewritten
WARNING: Ref 'refs/heads/new-root' is unchanged
原始照片仍然是安全的。例如,主分支現在生活在refs/original/refs/heads/master
之下。查看您新重寫的分支中的更改。當你準備刪除的備份,運行
git update-ref -d refs/original/refs/heads/master
你可以煮了命令,以覆蓋所有備份裁判在一個命令,但是我建議每個人仔細審查。
結論
最後,新的歷史
$ git lola --name-status
* ab8cb1c (bar-feature) Add bar
| M .gitignore
| A bar.c
| * 43e5658 (master) Add foo
|/
| A foo.c
* 6469dab Commit 2
| A module.c
* 47f9f73 Commit 1
| A main.c
* 00c7780 (HEAD, new-root) Create .gitignore
A .gitignore
觀察到所有的目標文件都不見了。 bar-feature中對.gitignore
的修改是因爲我使用了不同的內容來確保它將被保留。爲了完整:
$ git diff new-root:.gitignore bar-feature:.gitignore
diff --git a/new-root:.gitignore b/bar-feature:.gitignore
index 5761abc..c395c62 100644
--- a/new-root:.gitignore
+++ b/bar-feature:.gitignore
@@ -1 +1,2 @@
*.o
+*.obj
新根裁判不再有用,所以用
$ git checkout master
$ git branch -d new-root
你是我的弗利英雄! – Aren
@Aren不客氣!樂意效勞。 –