iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0
ChatGPT & Codex

2026 年,會用 AI 不等於會帶 AI:用 ChatGPT × Codex 從零開始實現一人 AI 團隊系列 第 17 篇

【Day 17】不會 Git 的 Vibe Coder,連上一版都可能保不住:用 Codex 學會 Commit、Diff、Branch

  • 分享至 

  • xImage
  •  

摘要
Coding Agent 讓修改軟體變得很快。一句 Prompt 送出去,幾個檔案可以一起被改寫,原本需要半天才能看到的另一套設計,幾分鐘後就可能出現在瀏覽器裡。速度提高之後,我開始碰到另一類問題:現在這版如果已經可以用,要怎麼留下來?AI 一次改了幾百行,我該從哪裡開始檢查?如果下一個想法最後失敗,能不能保留眼前這個版本?這篇從一張很普通的線上名片開始,實際走過 Commit、Diff 與 Branch,看看版本控制如何替快速產生的變更建立邊界。

引言

Codex 把一張線上名片從白底單欄改成另一套版型,只需要幾輪提示詞。修改第一次快到讓我開始在意一件以前很少擔心的事:上一個能正常工作的版本,到底去哪裡了? 當一句話就能同時改掉 HTML、CSS 和 JavaScript,「再試一版」幾乎沒有成本;但版本越來越多,我反而更難回答:哪一版可以信、AI 這次究竟碰了什麼、做壞之後又該回到哪裡。

這篇我會用同一張線上名片,把這三個問題實際走一次:先用 Commit 留下能工作的版本,再用 Diff 看清 AI 真正改了哪些地方,最後用 Branch 把還沒有把握的新方向隔離出去。讀完之後,你不需要先學會一整套 Git 指令,但會知道在 Vibe Coding 裡,什麼時候該留下版本、什麼時候該檢查差異,以及什麼時候不該讓 AI 直接改在主線上。

cover_image


當修改變快,我開始在意上一版去了哪裡

我先讓 Codex 做了一張很普通的線上名片。內容只有姓名、職稱、簡介、Email、LinkedIn、GitHub,再加上一顆可以寄信的 Contact me 按鈕;技術上也刻意壓低複雜度,只用 HTML、CSS 和必要的 JavaScript。這個需求幾乎沒有需要討論的地方,Coding Agent 很快建立檔案、補上手機版樣式,再啟動本機預覽。

>實作 Prompt|建立第一版線上名片
請在目前資料夾建立一個簡單的單頁線上名片,不使用 React、Vue 或其他前端框架,只使用 HTML、CSS,以及必要時少量 JavaScript。
名片使用名稱 Heng-Shiou Sheu,職稱為 Forward Deployed Engineer,頁面包含 Bio、Email、LinkedIn、GitHub 與「Contact me」按鈕。先使用乾淨的白底單欄版面,確保桌機與手機都能正常顯示,完成後啟動本機預覽。

第一版沒有太多設計野心。姓名清楚,聯絡方式能點,按鈕真的會開啟 Email,手機畫面也沒有超出版面。當我在瀏覽器裡逐一確認這些功能時,這張看起來還很普通的名片,其實已經跨過一條重要界線:它現在是一個可以工作的版本。

第一版線上名片
〔圖 1:第一版使用簡單的白底單欄設計。後面的所有修改,都從這個可以正常使用的版本開始。〕

接下來我當然還可以繼續叫 Codex 修改。換配色、重排資訊、增加動畫,甚至整張重新設計,都只需要再送出一句提示詞。也正是在這個時間點,我第一次刻意停下來:如果下一版沒有比較好,眼前這個已經可以工作的狀態,要怎麼留下?

這個問題在自己慢慢寫程式時沒有那麼突出。改一個按鈕、調幾行 CSS,修改範圍通常還留在腦中;Coding Agent 把這個速度往前推了一截,一次操作可能同時碰到 HTML、CSS 和 JavaScript。當「繼續改」幾乎沒有摩擦,保存一個可靠狀態反而開始變得重要。

軟體工程很早就在處理這件事。Git 把一個專案的變化記錄成歷史,而這段歷史最基本的節點,就是 Commit。

先替可以運作的版本留下座標

如果沒有版本控制,我也可以複製整個資料夾。profile-card、profile-card-backup、profile-card-backup-2,短期內看起來確實能用;做履歷或報告時,我們甚至很熟悉 final、final-v2、final-really-final 這種命名方式。問題通常要等到幾輪修改後才會出現:哪一份才是目前版本、兩份到底差在哪裡、昨天還能正常工作的那一份又是哪一份。

我沒有替線上名片複製資料夾,而是讓 Codex 在目前位置初始化 Git,檢查需要納入版本控制的檔案,再替這個狀態建立第一個 Commit。

> 實作 Prompt|留下第一個可用版本
目前這張線上名片已經可以正常使用。請檢查目前資料夾是否已經是 Git repository;如果不是,初始化 Git。確認需要納入版本控制的檔案後,將目前狀態建立成第一個 Commit,Commit message 使用 `Create working profile card`。完成後顯示 `git status` 與 `git log --oneline -3`。

終端機最後出現一筆很短的紀錄:

● Create working profile card

這一行看起來沒有瀏覽器裡的名片那麼有存在感,卻改變了接下來所有修改的基準。Git 現在知道有一個時間點叫做 Create working profile card,而我也知道這個節點對應到什麼狀態:聯絡資訊正確、按鈕能用、版面沒有跑掉。

第一個 Commit
〔圖 2:git status 顯示 working tree clean,Git history 裡則第一次出現 Create working profile card。這個節點記錄了目前可以正常工作的狀態。〕

一般的儲存會留下「現在的檔案」,Commit 則替專案歷史增加了一個有意義的座標。之後如果完成手機版,可以再留下一個 Commit;加入作品集之後,又可以再留一個。時間久了,專案不再靠資料夾名稱猜版本,而會長出一條可以閱讀的演進紀錄。

所以我後來比較少把 Commit 想成「存檔」。它更接近一次主動確認:我願意把現在這個狀態當成往後比較的基準。 這個基準一旦存在,下一個問題才有辦法被精確地問出來——從這個版本走到下一個版本,中間究竟改了什麼?

當 AI 一次改掉幾十行,我需要的是差異

我沒有立刻要求 Codex 重做整張名片,而是先做一次幅度很小的修改。社群連結移到底部,Contact me 改成 Let's talk,按鈕增加 hover 效果,再調整幾個文字區塊之間的距離。這些改動在人眼裡很好理解,也很適合觀察 Git 如何記錄一次普通的變更。

> 實作 Prompt|修改畫面,先不要 Commit

請把社群連結移到卡片底部,將「Contact me」改成「Let's talk」,替按鈕增加簡單的 hover 效果,並微調姓名、職稱與簡介之間的垂直間距。保留目前所有 Email、LinkedIn、GitHub 網址與功能。完成後先不要 Commit,顯示 `git diff --stat` 與完整 `git diff`。

這一次 Codex 做完後,我沒有先看完整檔案,而是先看 git diff --stat。它先回答最粗的一層問題:幾個檔案被碰過,各增加多少行、刪掉多少行。再往下展開完整 Diff,才會看見每一個具體變動,刪除的內容和新增的內容被放在一起比較。

其中最容易理解的一段,是按鈕文字:

- <a class="contact-button" href="mailto:hello@example.com">Contact me</a>
+ <a class="contact-button" href="mailto:hello@example.com">Let's talk</a>

這幾行同時告訴我兩件事。按鈕文字確實變成 Let's talk,而原本的 mailto: 仍然留著;也就是說,我要求修改的地方發生了變化,原本應該保留的行為沒有一起被換掉。CSS 裡新增的 hover 樣式與間距,也可以用同樣的方法逐一確認。

截圖 3|第一次查看 Diff
〔圖 3:紅色代表原本內容,綠色代表這次新增或取代的內容。原本需要重新閱讀整份檔案的修改,被縮小成這一次真正發生變化的範圍。〕

這個畫面讓我重新理解 Coding Agent 裡的 Review。假設一句 Prompt 最後造成 12 files changed、增加六百多行、刪除三百多行,我很難重新讀完 repository 再判斷結果;Diff 直接把問題縮到「這次碰了哪些地方」。如果需求只有調整按鈕樣式,Diff 卻出現付款、登入或資料處理邏輯的大量修改,光是修改範圍就已經值得停下來檢查。

這對不熟悉程式的人也有意義。我要判斷的第一件事,不一定是某一行 JavaScript 寫得夠不夠漂亮,而可以先從需求邊界開始:我只請它改 A,為什麼 B 也被碰到了?原本要求保留的連結還在嗎?這些問題不要求我從空白頁寫出同一段程式,卻能讓我開始參與變更的判斷。

Commit 在這裡提供了「前一個可靠狀態」,Diff 則把從那裡走到現在的變化攤開。兩個概念接起來後,AI 回覆裡的 Done 不再是工作結束的唯一證據;我開始擁有一個可以查看、追問,再決定要不要接受的中間層。

確認這次修改符合預期後,我才把它做成第二個 Commit:

● Refine card layout and CTA
│
● Create working profile card

專案到這裡仍然沿著同一條路前進。下一次修改卻不一樣,我準備把整張名片重新設計,而我並不知道新方向最後會不會比較好。

讓新的方向先在另一條路上長大

我把需求拉大很多。原本的單欄名片要變成 editorial portfolio:桌機版左右分欄,姓名和 Product Designer 身分放大,Bio 與聯絡方式重新安排,字級、留白與整體 HTML 結構都可以重做。這次已經不是調幾個 CSS 數值;如果結果不喜歡,我會希望現在這張能用的名片完整留在原處。

過去我可能會在修改前複製一份資料夾。Git 提供另一個做法:從目前的版本分出一條新的開發路線,也就是 Branch。我讓 Codex 從現在的 main 建立 redesign-editorial,所有重新設計都在這條 Branch 上完成。

> 實作 Prompt|在新的 Branch 重做名片

> 目前 `main` 上的線上名片已經可以正常使用。請先確認 working tree 是乾淨的,從目前版本建立 `redesign-editorial` branch,並切換到該 branch。接著把名片重新設計成 editorial portfolio 風格:桌機版使用左右分欄、更明顯的字級層次與留白,手機版維持自然的單欄閱讀;保留所有原始文字與聯絡網址。完成後建立 Commit `Redesign profile card with editorial layout`,最後顯示目前 branch 與完整 Git graph,不要 merge 回 `main`。

完成之後,Git history 第一次出現岔路。兩條路共享前面的 Commit,走到 Refine card layout and CTA 之後,redesign-editorial 才開始產生自己的新版本。這個結構讓「目前穩定版本」和「新的設計實驗」同時存在,也讓我暫時不用決定誰一定要取代誰。

截圖 4|Branch 出現
〔圖 4:Git graph 同時顯示 main 與 redesign-editorial。兩個版本共享前面的歷史,重新設計則沿著新的 Branch 繼續往前。〕

真正讓 Branch 變得具體的,是接下來那次切換。我先請 Codex 回到 main,重新整理瀏覽器,原本那張比較保守、已經確認能工作的名片又出現在畫面上;接著再切回 redesign-editorial,同一個本機網址換成完全不同的 editorial 版本。沒有搬資料夾,也沒有手動把檔案覆蓋回去,差異來自我現在站在哪一條開發路線。

截圖 5A|同一個專案的兩個版本

截圖 5A|同一個專案的兩個版本
〔圖 5:上圖側為 main,下圖為 redesign-editorial。兩張截圖使用相同 viewport,讓版型差異直接呈現在同一組比較裡。〕

這也是我覺得 Branch 最容易被低估的地方。它的價值不只在「做壞了可以回去」,而是容許多個方向先存在,再把決策往後延。對 Coding Agent 而言,這件事變得更有用,因為產生第二種、第三種方案的成本正在快速下降;當嘗試大量增加,我需要一個地方讓它們彼此隔離。

到了這裡,Commit、Diff、Branch 終於不再像三個需要背的 Git 名詞。它們處理的是三種不同的不確定性:Commit 留下我已經確認過的狀態,Diff 把這次修改縮到可以檢查的範圍,Branch 則替還沒有答案的實驗保留空間。

Git 概念 我遇到的問題 它提供的控制點
Commit 這個版本已經可以用,我不想失去它 留下可靠的歷史節點
Diff AI 做完了,但我不知道這次碰了什麼 看清兩個狀態之間的實際變更
Branch 我想大幅嘗試,但還不確定結果 把實驗與目前版本隔離

如果一定要再把三者縮短,我會這樣記:Commit 讓我知道哪裡回得去,Diff 讓我看懂途中發生了什麼,Branch 讓我在還沒有答案時先去試。 它們一起構成的,其實是一套試錯結構。

當產生變更變便宜,管理變更就開始重要

我以前看到 Git,首先想到的是 GitHub、Terminal 和一串工程師每天在打的指令。做完這張線上名片之後,它在我腦中留下的畫面反而很具體:一個可以工作的版本被 Commit 留下來,一次修改被 Diff 攤開,一個還不知道好不好的設計則被放到另一條 Branch 上。

這些方法都早於 Coding Agent 很久。軟體本來就會反覆修改,工程團隊也一直需要追蹤歷史、檢查變更與隔離實驗;AI 改變的是變更出現的速度。當我可以在幾分鐘內要求另一套版型、再試第三個方向,原本屬於工程流程裡的版本控制問題,也更早出現在 Vibe Coder 面前。

這也改變了我下 Prompt 的方式。遇到幅度比較大的需求時,我不會只交代「幫我重新設計」,還會一起說明變更應該怎麼被管理:

先確認目前版本已經 Commit。這次修改建立新的 Branch,完成後先讓我 Review Diff,不要直接 Merge 回 main。

實際輸入 Git 指令的人仍然可以是 Codex。我需要掌握的是這些動作分別保護什麼:目前哪個狀態可信、AI 這次改了哪些地方、新方向是否還和穩定版本保持距離。當這三個問題都有答案,我就不必靠「希望這次不要改壞」來承擔每一次生成。

Vibe Coding 把製造變更的成本壓得很低,也因此讓試錯發生得更頻繁。版本控制替這些試錯建立了歷史、差異與邊界。等我真的理解這件事之後,Git 才從一套工程師工具,變成我敢繼續把專案交給 AI 修改的理由之一。

補充:卡片連結
這次示範用的名片收入於此處:https://heng-shiou-editorial-profile.workspace-717020.chatgpt.site

結論

做到最後,我已經不太在意 Git 指令本身。真正留下來的是三個問題:現在有沒有一個我確定可以工作的版本?AI 這次到底改了什麼?如果新的方向失敗,我能不能讓它留在實驗裡,而不是直接覆蓋現在的成果? Commit、Diff 和 Branch,分別替這三個問題提供了一個可以操作的答案。

Coding Agent 讓「再改一版」變得很便宜。也因為如此,我反而更需要知道什麼值得留下、什麼正在改變,以及哪些嘗試還不該進入主線。從這個角度看,Git 管理的其實不只是程式碼版本,而是試錯的邊界。當下一次我再把專案交給 Codex,我不必期待它每次都一次做對;我只需要確保每一次修改,都還看得懂、退得回去,也有地方可以放心地試。


上一篇
【Day 16】文件正在變成 AI 時代的新原始碼:讓 Codex 讀懂專案怎麼工作
系列文
2026 年,會用 AI 不等於會帶 AI:用 ChatGPT × Codex 從零開始實現一人 AI 團隊 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言