iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
Vibe Coding

從 Vibe Coding 到系統架構:Gemini x Claude Code 雙 AI 協同開發 Godot 2D Roguelike 卡牌遊戲實戰系列 第 11 篇

Day 11:【工程配置】同一專案資料夾,如何切出公私雙 Repo?

  • 分享至 

  • xImage
  •  

這 30 天,我一邊開發遊戲,一邊也在寫開發日誌、學習筆記和文章草稿。
一開始,我直接把這些東西放在遊戲專案裡。
這樣最方便,寫程式和寫筆記都在同一個地方。

但遊戲程式碼準備公開到 GitHub 後,問題就來了:
程式碼想公開,筆記卻不想公開。

未發表的文章、還沒整理好的筆記、寫壞的段落,如果跟著遊戲 repo 一起 push 到 GitHub,之後任何人都可能看到。

所以最後同一個專案裡我把它拆成兩個 repo:

ObsidianTrial
└── 遊戲程式碼 → 公開 repo

doc
└── 開發筆記、文章草稿 → 私有 repo

這樣做之後,我還是可以把筆記放在遊戲專案旁邊寫,只是 Git 的管理分成兩邊。
看起來很簡單,但中間其實碰到了幾個 Git 和 Godot 的問題。


一開始,我把筆記放在遊戲專案裡

當時的專案大概是這樣:

ObsidianTrial/

├── assets/
├── scenes/
├── scripts/
└── doc/
    ├── DEVLOG.md
    └── notes/

這樣做很方便。
但我很快又遇到一個 Godot 的問題。

我的文章一定會有很多截圖。
如果把 .png 放進 doc/,Godot 會把它們當成遊戲素材處理,並在 .godot/imported/ 裡產生對應的匯入資料。

這些圖片是拿來寫文章的,不是遊戲素材。
所以我需要告訴 Godot:

doc/ 是我的筆記,不是遊戲素材。

AI 建議我在 doc/ 裡放一個空白的 .gdignore:

touch doc/.gdignore

這是一個完全空白的檔案。
Godot 看到它之後,就會跳過這個目錄。
用 godot -e 開啟編輯器確認後,可以看到前後差異:

Godot 檔案系統面板的前後對比,左邊看得到 doc 與 doc_ithome_iron 兩個資料夾,右邊加了 .gdignore 之後兩者都消失

左邊還看得到 doc/ 和 doc_ithome_iron/,加上 .gdignore 後,兩個資料夾都不再出現在 Godot 的 FileSystem 面板。

右圖是稍後補拍的,所以多了幾個當時新增的場景和腳本,跟 .gdignore 無關。
這時候我才知道,原來筆記雖然放在遊戲專案裡,還是可以讓 Godot 忽略它。

但接下來的問題是:
如果遊戲 repo 要公開,doc/ 還是會跟著 Git 一起公開。

.gdignore 解決的是 Godot 的問題,沒有解決 Git 的問題。


我有三種選擇

我當時想到三種方式:

做法 結果
繼續放主 repo 最簡單,但筆記會跟著公開
Git submodule 可以分開,但設定比較複雜,而且主 repo 會留下私有 repo 的網址
獨立 repo 程式碼和筆記完全分開,但要分別管理

我最後選了第三種。
因為我其實不需要主 repo 知道筆記的版本。
我只需要兩件事:

遊戲程式碼 → 公開
開發筆記 → 私有

所以讓它們變成兩個獨立 repo,反而比較符合我的需求。


拆之前,我先想保住過去的筆記

這時候又有一個問題。
如果我直接進入 doc/:

git init

新的 repo 當然可以馬上開始使用。
但之前 doc/ 裡已經有 9 個 commit。
直接 git init 的話,這些歷史就不會跟過去的 Git 紀錄一起搬過去。
所以我問 AI:

「有辦法把 doc/ 過去的 commit 歷史一起搬走嗎?」

這個問題讓我找到 git subtree split。


第一步:從主 repo 移除,但不要刪掉檔案

先執行:

git rm -r --cached doc

這裡最重要的是:

--cached

它只會把 doc/ 從 Git 的索引移除,本機檔案還會保留。

如果沒有 --cached:

git rm -r doc

Git 就會真的把檔案刪掉。
所以這裡我特別停下來問了一句:

「--cached 加跟不加差在哪?」

因為那個目錄裡放的是我這幾天累積的筆記。


第二步:告訴主 repo,不要再追蹤 doc/

接著在 .gitignore 加上:

# 開發日誌、學習筆記、文章草稿
# 這些已獨立成私有 repo
doc/

這一步很重要。
因為接下來 doc/ 裡會有自己的 .git。
如果主 repo 還繼續追蹤它,就會變成「Git 裡面又放了一個 Git」。
後面我真的就踩到了這個坑。


第三步:把過去的歷史抽出來

如果只是想把檔案搬到另一個 repo,這時候直接 git init 就可以。
但我想保留原本 9 個 commit。

所以執行:

git subtree split --prefix=doc -b doc-history

這會把 doc/ 這個子目錄的歷史抽出來,建立成一個新的 doc-history 分支。

原本:

doc/DEVLOG.md

抽出來之後會變成:

DEVLOG.md

也就是 doc/ 本身會被拿掉,檔案直接變成新 repo 的根目錄。

接著把這段歷史接到新的 repo:

git -C doc init -b main
git -C doc fetch .. doc-history
git -C doc reset --mixed FETCH_HEAD

最後刪掉暫時建立的分支:

git branch -D doc-history

這樣原本 doc/ 裡的 9 個 commit,就完整搬到新的 repo。


三個坑

拆完之後,我又遇到三個實際問題。

坑 1:Git 給警告,但指令還是成功

如果沒有把 doc/ 放進 .gitignore,主 repo 會看到裡面還有另一個 Git repo。

執行 git add 時,Git 會出現:

warning: adding embedded git repository: inner

hint: You've added another git repository inside your current repository.

hint: Clones of the outer repository will not contain the contents of
the embedded repository and will not know how to obtain it.

後面 Git 甚至還會告訴你,如果真的要使用 submodule,應該怎麼做;如果是不小心加進去的,也會告訴你怎麼移除。

Git 其實已經把問題講得很清楚。
但我差點忽略它。
因為這是:

warning

不是:

error

所以指令還是會成功。

接著看 git status:

A  file.txt
A  inner

整個巢狀 repo 只剩下一行:

inner

裡面到底有哪些檔案,完全看不出來。
原因是外層 Git 記錄的不是裡面的檔案內容,而是一個 commit。

如果別人 clone 外層 repo,也不會自動拿到裡面 repo 的完整內容。
所以 .gitignore 在這裡就很重要:

主 repo
    ↓
看到 doc/
    ↓
.gitignore
    ↓
「這個目錄不要由我追蹤」

坑 2:VS Code 看不到第二個 repo

拆完之後,我又發現:
VS Code 的「原始檔控制」面板只看到主 repo。
我修改了筆記,卻沒有看到任何 Git 變更。

原因是 doc/ 已經被 .gitignore 排除,VS Code 預設掃描 repo 時,也把它跳過了。
所以我在 .vscode/settings.json 加上:

{
  "git.scanRepositories": ["doc"]
}

重新載入視窗之後,兩個 repo 就都出現了:

VSCode 原始檔控制面板同時列出 ObsidianTrial 與 doc 兩個存放庫,doc 那列標示 main 加星號代表有未提交的變更

這裡可以看到:

ObsidianTrial    main
doc              main*

* 代表 doc 有尚未 commit 的變更。
兩個 repo 的狀態完全獨立。

所以之後 commit 前,我還多了一個要注意的地方:
先確認現在選的是哪一個 repo。


坑 3:兩邊要分別 push

最後一個沒有什麼技術難度,卻最容易忘記。

程式碼:

git push

筆記:

git -C doc push

git -C <目錄> 可以理解成:

在指定的目錄裡執行 Git 指令。

所以不用先 cd doc。

這個操作之後會變成雙 repo 日常工作的一部分。
我也把這件事情寫進 CLAUDE.md,讓新的 Claude Code 對話一開始就知道:

主 repo → 遊戲程式碼
doc repo → 開發筆記
兩個 repo 要分開 commit / push

不然 AI 如果只在主 repo 執行:

git status

看到主 repo 沒有變更,就可能直接回報:

工作區是乾淨的。

但其實我的筆記 repo 可能早就有修改了。


最後,我的專案變成這樣

現在的結構可以簡單理解成:

ObsidianTrial
└── 公開的遊戲程式碼

doc
└── 私有的開發筆記、文章草稿

但在我的電腦裡,doc/ 依然放在遊戲專案裡:

ObsidianTrial/

├── assets/
├── scenes/
├── scripts/
├── README.md
├── CLAUDE.md
└── doc/
    ├── DEVLOG.md
    └── notes/

只是 Git 的管理已經分開。

所以我現在可以:

寫遊戲
  ↓
公開到 GitHub

寫文章
  ↓
留在私有 repo

兩邊都可以繼續在同一個 VS Code 裡工作。


這次我攔下來看的地方

Day 01 說過這個系列的心法:

攔截 → 追問 → 親手重做

這次最直接的攔截點,就是:

git rm -r --cached doc

提問:「--cached 加跟不加差在哪?」
提問:「有辦法保住 doc/ 過去的 commit 歷史嗎?」

第一個問題,讓我知道檔案不會被刪掉。
第二個問題,讓我找到 git subtree split,把原本 9 個 commit 一起搬走。

拆完之後,我自己確認:

ls doc/

確認檔案還在。

git -C doc log --oneline

確認新的 repo 有原本的歷史。
再回到主 repo:

git status

確認主 repo 已經不再追蹤 doc/。
三個都確認過,我才繼續 push。


所以 Day 11 最後留下來的結構,其實很簡單:

遊戲 repo
→ 公開

筆記 repo
→ 私有

只是為了做到這件事,我中間才碰到了 .gdignore、git rm --cached、git subtree split,以及兩個 repo 在 Git 和 VS Code 裡的管理問題。

程式碼公開,筆記私有。

這就是這次拆 repo 最後得到的結果。

明天 Day 12 開始進入遊戲的核心機制。
我很好奇一件事:
AI 為什麼把玩家的血量、牌組這些資料,都放進一個叫 Global.gd 的檔案?
這次就要開始拆 Godot 裡的資料到底怎麼流動。


上一篇
Day 10:【自動化驗證】讓 AI 自己跑完一場 Smoke Test
下一篇
Day 12:【程式碼驗證】程式能跑,真的就沒問題嗎?
系列文
從 Vibe Coding 到系統架構:Gemini x Claude Code 雙 AI 協同開發 Godot 2D Roguelike 卡牌遊戲實戰 共 15 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言