W02 版本控制
所以:素材和場景一個人負責一個,不要兩個人同時改。

動手之前:先 Fetch
Fetch = 去雲端問一下:你那邊現在長怎樣?
- 只是把雲端的最新狀態抓下來,不會動到你的檔案
- 抓完
origin/main這個標籤才會移到正確的位置 - 看得到真正的分叉,才選得出要用哪個方法
沒 fetch 之前,你看到的雲端是舊的。

方法一:不要了(Reset --hard)
你手邊改的東西(已提交)不重要、或本來就想重做:
- 直接丟掉自己的提交與修改
- 把雲端那份原封不動拉下來
- 從乾淨的狀態重新開始
⚠️ 丟掉就回不來了。 只有在「這些改動我不要」時才用。

Reset --hard 在 Fork 裡怎麼按
- 先 Fetch,讓
origin/main是最新的 - 在提交樹上找到
origin/main那一層 - 右鍵 →
Reset 'main' to Here - 模式選 Hard

方法二:Rebase(接枝)
改的東西要留著:
- 像花藝的接枝:把你的提交剪下來,接到雲端最新那一層上面
- 樹會保持一直線,比較好讀
●─●─●─●─● 你的提交接到最新的後面

Rebase 在 Fork 裡怎麼按
- 先 Fetch
- 確認你站在
main(左邊清單粗體的那個) - 在
origin/main上按右鍵 →Rebase 'main' onto origin/main - 有衝突 → Fork 跳出合併工具,解完按 Continue
做完:main 接到 origin/main 上面,樹變成一直線,可以 push 了。

方法三:Merge(合併)
- 把兩根樹枝合在一起,多一個「合併提交」
- 改到不同地方:自動合好
- 改到同一行:Git 標出來問你

改到同一行,Git 會問你
<<<<<<< HEAD
你的版本
=======
組員的版本
>>>>>>>
決定留哪個(或兩個都留)→ 刪掉標記 → commit → push

Merge 在 Fork 裡怎麼按
先站到要保留的那個分支上,再把另一邊的改動合進來。
- 你現在在
main→ 對origin/main按右鍵 → Merge into main - 合進來的是改動,不是整棵樹搬家

方法四:取消重來(Reset,改動留著)
- 用 Reset 撤銷自己的提交,但改動還留在檔案裡
- 先把雲端最新的拉下來
- 重新 commit,再 push
改動不多的時候,這個最簡單。

接下來:討論你們的專案
每組開始討論這學期想做什麼遊戲:
- 寫進
README.md,老師有提供模板 - 每個人用自己的帳號登入
- 試著編輯
README.md的不同段落,各自 commit、push

簽到
今天沒有提交和 push 過的人:
- 在
docs/attendance/w02.md簽名,commit、push

下週停課
🔴 9/28 教師節停課。10/5 再見。 這兩週沒有作業。

分支
前面都在 main 上一起做。分支是「另外開一條路」。
- 想試一個做法,又不想弄壞現在能動的版本
- 兩個人要改同一個東西,先各走各的,之後再合
分支很便宜:開一條、丟掉一條,都只是動一個標籤。

開一條分支(Create Branch)
在 Fork 裡:
- 在提交樹上,找到要從哪一層岔出去(通常是
main的最上面) - 右鍵 →
Create Branch… - 取個名字,例如
try-jump - 勾「Check out after create」=開完直接站過去
開完只是多一個標籤,檔案不會變。

站過去(Checkout)
Checkout = 換一條路站。
- 左邊清單雙擊那個分支名,就站過去了
- 檔案跟著變成那條路上的樣子
- 粗體的那個就是你現在站的分支
⚠️ 站過去之前,手邊的修改先 commit 或 discard,不然會擋著。

丟掉一條分支(Delete Branch)
這條路試完了、或不要了:
- 先站到別條分支(不能站在自己身上刪自己)
- 在要刪的分支上右鍵 →
Delete…
- 刪的是標籤,提交還在,只是沒有名字指著它了
- 雲端那條要另外刪(Fork 會問要不要一起刪遠端)

分支要不要用在這門課
- 今天開始:全組在
main上一起做就好 - 之後專案變大、兩個人要同時改同一個場景,再開分支
- 那時候會一起講 Pull Request 和 review
不要為了用而用。 三個人的小專案,分支常常只是增加麻煩。
shu-dma-mult390.pages.dev 每週的投影片都會公開,課後可以回來看。

- 存檔、同步、紀錄版本
- 這是一個讓我們安心,也讓我們合作的工具

再次確認:你有分組嗎?
打開 Gitea,你應該看到兩個版本庫:
notes:全班共用- 你們組的版本庫
只看到 notes 的舉手。
版本庫(repository),簡稱 repo:放一個專案所有檔案和歷史的地方。
投影片在哪裡
在本地端編輯檔案
- VS Code
- Obsidian
改完存檔,回到 Fork,會看到哪些檔案變了。

從本地端提交:兩個步驟
- Stage(暫存):挑出這次要提交哪些改動
- Commit(提交):寫說明,存成一個存檔點
改檔案 ⇄ Stage → Commit
↓ Unstage
Discard(這次改壞了,不要了)

用你習慣的編輯器打開專案資料夾:

把專案複製到本地端:Clone
Clone:把雲端的整棵樹複製到本地端。
- 在 Gitea 的 repo 頁複製網址
- Fork → File → Clone,貼上網址
- 選一個放專案的資料夾

HEAD:你現在站在哪裡
- HEAD=你現在所在的位置
- 資料夾裡看到的檔案,就是 HEAD 指著的那個版本

本地端的版本控制軟體:Fork

設定帳號
Fork → File → Preferences → Git:
- User Name=學號
- Email=學號@mail.shu.edu.tw
要跟 Gitea 帳號一樣,貢獻才算得到你頭上。
- 下載:https://git-fork.com/
- 用滑鼠就能看歷史、提交、同步
- 它做的每件事,底下都是 Git 指令

雲端和本地端的關係
- 雲端有一棵樹,本地端也有一棵樹
- 版本控制做的事:讓兩棵樹同步
雲端 ●─●─●
⇅ 同步
本地 ●─●─●

需要軟體來幫忙
- Git 原本是用命令列操作
- 能做的事很多,但有點複雜
- 所以我們用圖形介面軟體來幫忙
實作(一):第一個提交

| 好的 | 壞的 |
|---|---|
新增組員名單 |
❌ update |
修正敵人卡在斜坡的問題 |
❌ 修正bug |
調整第一關的難度 |
❌ asdf |


實作(二):第二個提交
每組第二位同學:
- 在
README.md填上平台(Android/Web) - Stage → Commit
- 一樣做完就停
現在兩個人的電腦裡各有一個新提交,Gitea 上還是舊的。
提交之後發生什麼
提交的注意事項
- 一次提交只做一件事
- 說明不要亂寫:用一句話講這次做了什麼,動詞開頭
老師已經在每組的 repo 放了 README.md。
每組派一位同學:
- 在
README.md寫上組員名單 - Stage → Commit
- 做到這裡就停,其他按鈕先不要碰

- 樹枝往上長一節
- HEAD 跟著移動到最新的提交
- ⚠️ 這時候提交還在你的電腦裡,雲端還沒有

反悔的兩種按法
- Unstage:這個檔案這次不要一起提交,放回去就好,內容不會變
- Discard:把還沒提交的修改丟掉,檔案回到上一個提交的樣子
⚠️ Discard 丟掉就回不來,因為它還沒被記錄過。Unstage 則完全無害。

Push:同步到雲端
Push:把剛剛的提交送到雲端。
- 雲端的樹也往上長一節
- Fork 裡是同一棵樹、兩個標籤:
main= 你本地端的位置origin/main= 雲端的位置
- push 前兩個標籤不在同一層;push 後疊在一起
第一位同學先 push。 到 Gitea 重新整理,看到了嗎?

本地端與雲端的衝突
第二位同學 push → 出現警告。 恭喜,這是第二次衝突(第一次在上週)! 這次撞的不是同一行文字,是你的樹和雲端的樹對不起來。

為什麼會這樣
- 兩位同學改的是不同地方,commit 都成功
- 但第一位已經 push 了,
origin/main這個標籤往前移過了 - 你的提交接在舊的那一層上,接不回現在的
origin/main
看 Fork 的提交樹:main 和 origin/main 不但不在同一層,還岔開成兩邊。

分支長什麼樣

衝突長什麼樣
● ← main(你的提交,只在本地)
/
●─●─●─● ← origin/main(雲端,多了組員的提交)
兩個標籤各自往上長,樹岔開了。要想辦法把它們接回同一條。

解決衝突:先看是什麼檔案
- 文字檔:有機會自動合併;改到同一行就手動決定留哪個
- 二進位檔(圖片、模型、場景):沒辦法合併,只能二選一

雲端與本地端
到這裡為止,我們看的都是 Gitea 上的東西——那是雲端。
●─● feature
/
●─●─●─●─● main
從某一層岔出去往上蓋,就是一條新的分支。

分支其實是一個標籤
- 分支=一個標籤,指著某根樹枝的末端
- 在樹枝之間跳來跳去叫 checkout
- 跳過去,你看到的檔案就會變成那根樹枝上的樣子
在 Gitea 的分支選單裡,打勾的那個就是你現在站的分支。
- 雲端(remote):Gitea 上的那一份,全組共用
- 本地端(local):你電腦裡的那一份
接下來這半堂課,全部都在講本地端。

為什麼要下載到自己電腦
- 網頁只適合改幾行字
- 真正要新增、修改內容,得在自己電腦上做
- 各種素材有各自的專業軟體(Photoshop、Blender、Godot…)

提交會疊成一棵樹
- 每次提交都接在上一次後面
- 目前大家的提交都蓋在主線上,叫主分支(main)

- 日期
- ID(一串亂碼,每個提交獨一無二)
- 作者
- 說明(comment)
上週在網頁上簽到,就是一次線上提交。
●─●─●─● main

分支:多元宇宙
Git 可以開分支。
- 就像多元宇宙:每條分支是一個不同的現實
- 我們一次只能體驗一個現實
- 所以每個宇宙都要有名字,才能在宇宙之間穿越
一次提交=一個存檔點。 每個提交都帶著:
提交(commit)是什麼

上週大家在網頁上簽到時,撞到了 Git 的衝突。
- 兩個人從同一層往上蓋
- 各蓋各的,變成兩棟不一樣的房子
- 要合起來,得先決定:上面那層照誰的做
衝突不是錯誤,是 Git 在問你。
上週的衝突,是正常的

像蓋房子:一層一層往上
- 每做完一件事,就往上蓋一層
- 新的一層蓋在上一層的基礎上,不是憑空出現
- 每一層都有自己的編號(ID),指名道姓找得到
- Git 記的是每一層跟上一層的差異:這層改了什麼
- 所以想看以前的樣子,往下數幾層就回得去
打開 Gitea 看看你們自己蓋的房子。

| 是什麼 | 網址 | |
|---|---|---|
| Git | 版本控制的本體 | git-scm.com |
| GitHub | 放 Git 專案的網站,全世界最多人用 | github.com |
| Gitea | 同樣的東西,自己架的版本,只有修課的人看得到 | anxiously-unrecipient-aurora.ngrok-free.dev |
GitHub 上還有非常多好用的工具和開源專案。 善用工具,不要只局限於老師教的幾種。

- 改壞了想回到昨天的版本 → 回不去
- 兩個人改同一個檔案 → 一個人的工作不見了
- 「這段是誰做的、為什麼這樣做」→ 沒人記得
版本控制解決這三件事。而且它可以當作個人貢獻的評分依據。
Gitea 是什麼?GitHub 是什麼?
為什麼需要版本控制
你一定遇過:

- 儲存空間:一個全組都拿得到的地方
- 記錄變化:誰、什麼時候、改了什麼、為什麼

- 記下我們做過的所有改變
- 隨時都能恢復
- 隨時都能回到某個版本
這就是版本控制
版本控制能幫我們:
在發想和製作的過程中:
還需要:記錄每一次改變

需要即時討論?用通訊軟體就好。
- 一個大家可以一起工作的地方
- 正確性優先
- 不用那麼即時
單一事實來源(Source of Truth)
一個專案資料夾,就是全組唯一的正本。

最後一項最容易消失:「那時候說好的是哪個版本?」
- 程式碼
- 各式各樣的素材(assets):圖、音效、模型、動畫
- 團隊的工作紀錄
- 團隊決定好的事
一個遊戲專案裡有什麼

輸出的檔案最後都要回到同一個專案裡。 工具都很好,但東西會散在各處。
- 畫圖:Photoshop、Krita
- 建模:Blender
- 音效:Audacity
- 程式:VS Code
每種內容有自己的製作軟體,各自輸出檔案:
每種內容,各自的軟體

- 開一個資料夾,然後越開越多
- 資料散在每個人的電腦裡
- 各種好用的網路工具:
- 發想:Canva
- 文字:Google Docs/HackMD
- 資料:Google Sheets
平常我們怎麼做

第三件最常出事:檔案都在,但沒人確定該用哪一個。
- 資料要存得住
- 組員都拿得到檔案
- 大家都知道哪一份才是對的
所以團隊需要三件事

- 很多不同類型的檔案:程式、圖、音效、模型、文件
- 很多決策:為什麼這樣做、後來為什麼改
- 很多人:每個人同時在改不同的地方
- 很多版本:昨天的、上週能動的、要交出去的那一版
一個複雜的專案會包含:
從需求出發:一個專案裡有什麼

卡住了不要自己悶著,勇敢問。
- 及早發現
- 找到原因
- 解決它
重要的是這三件事

- 沒有不會出錯的系統
- 不管是寫程式還是工作流程,很少一次就對
上週大家已經體驗到了一些挫折
心態調整
