git-filter-repo 切分子專案小記
環境:
- macOS 26.5.1
- git 2.50.1
有的時候是這樣的, 專案會在測試目錄中發想, 然後慢慢測試, 慢慢就長成可以測試的小專案, 這個時候就會想把它獨立出來, 但是又想要保留當初開發的 git status.
今天要實作的是把 Git repo 裡面的子目錄切出去,變成一個獨立 repo,而且希望 Git history 可以一起帶過去。
我的原本 repo 在這裡:
/Users/max/Downloads/local_lab/lab_temp
要切出來的子目錄是這個:
02_實作中/20260627_chatbot_rag/
工具使用 `git-filter-repo`
Step 1: 先 clone 一份出來
重點是這裡要加 `--no-local`。如果只是從本機路徑直接 clone,`git-filter-repo` 可能會認為這不是乾淨的 fresh clone,然後拒絕改寫 history。
指令如下
cd /Users/max/Downloads/local_lab git clone --no-local ./lab_temp chatbot_rag_split
- 如果沒有加 `--no-local`,會遇到以下錯誤:
this does not look like a fresh clone.
(expected freshly packed repo)
Note: when cloning local repositories, you need to pass --no-local to git clone to avoid this issue.
Step 2: 執行 git-filter-repo
接著只保留目標子目錄,並把它搬到新 repo 的根目錄:
cd chatbot_rag_splitgit-filter-repo \ --path '02_實作中/20260627_chatbot_rag/' \ --path-rename '02_實作中/20260627_chatbot_rag/':
這邊最容易看錯的是最後的冒號。`--path-rename` 的格式是 `OLD_PATH:NEW_PATH`,所以這行的意思是:
- `OLD_PATH` 是 `02_實作中/20260627_chatbot_rag/`
- `NEW_PATH` 是空字串
- 結果就是把該子目錄底下的內容搬到 repo 根目錄
所以不是寫成 `:/`。Git repo 裡的 path 是相對路徑,不是檔案系統的 `/` 根目錄。要搬到 repo root,就是冒號後面留空。
成功輸出
最後成功時輸出長這樣:
NOTICE: Removing 'origin' remote; see 'Why is my origin removed?'
in the manual if you want to push back there.
(was /Users/max/Downloads/local_lab/./lab_temp)
Parsed 36 commits
New history written in 0.14 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
HEAD is now at 54dab99 build: 加入 Cloud Run 入口與資源保護
Enumerating objects: 296, done.
Counting objects: 100% (296/296), done.
Delta compression using up to 8 threads
Compressing objects: 100% (157/157), done.
Writing objects: 100% (296/296), done.
Total 296 (delta 136), reused 276 (delta 136), pack-reused 0 (from 0)
Completely finished after 0.25 seconds.
- 這裡看到 `Removing 'origin' remote` 是正常的。`git-filter-repo` 會移除原本的 `origin`,避免不小心把改寫後的 history 推回原 repo。這個設計滿貼心的,is not really useful :)
檢查結果
跑完後可以先看一下目前內容、commit,以及 remote 狀態:
ls git log --oneline --decorate -n 10 git status git remote -v
- 如果 `git remote -v` 沒有輸出,這次反而是正常狀態,因為 origin 已經被移除了。
Step 3: 接到新的 remote
確認內容沒問題後,再把它接到新的 GitLab 或 GitHub repo。
- 建議新 repo 不要先初始化 README、`.gitignore` 或 license,避免第一推就要處理 unrelated history。
git remote add origin git@github.com:your-org/chatbot_rag.git git push -u origin HEAD:main
- 可用 `HEAD:main`,因為不用先管目前 local branch 叫 `main` 還是 `master`,直接把目前所在的 HEAD 推到遠端 `main`。
這次的完整版本
cd /Users/max/Downloads/local_lab git clone --no-local ./lab_temp chatbot_rag_split cd chatbot_rag_split git-filter-repo \ --path '02_實作中/20260627_chatbot_rag/' \ --path-rename '02_實作中/20260627_chatbot_rag/': git remote add origin git@github.com:your-org/chatbot_rag.git git push -u origin HEAD:main
- 這次的關鍵就是三個:本機 clone 要加 `--no-local`、實際指令用 `git-filter-repo`、`--path-rename` 最後的冒號要留下來。
又前進一步 ~ enjoy it
Reference
- https://github.com/newren/git-filter-repo

沒有留言:
張貼留言