是最早的一批單機版版本控制工具。它最主要的功用就是讓你在同一台電腦上,對單一檔案進行版本控制。
優點:
簡單輕巧:它的設計非常單純,只專注於單一檔案的歷史管理,學習曲線很低。
節省空間:它只儲存檔案的「差異」,而不是整個檔案的完整備份,因此非常省磁碟空間。
缺點:
無法協作:RCS 是為個人設計的,無法讓多個開發者同時在同一個專案上協作。
單一檔案:它只能管理單一檔案。
功能有限:除了儲存歷史,幾乎沒有其他進階功能,例如分支(branching)或合併(merging)。
CVCSs 是一種 主從式(Client-Server)的版本控制架構,所有的版本歷史都集中儲存在一台中央伺服器上
# Subversion (SVN) 就是這類系統中最具代表性的一個,當開發者想提交修改時,必須連線到中央伺服器。要更新檔案時,也必須從伺服器拉取最新的版本。
優點:
集中管理:因為所有版本歷史都在中央伺服器上,所以管理員可以輕鬆地集中控制權限、備份資料,非常方便。
易於理解:它的概念很直觀,就像是團隊共用一個雲端資料夾,每個人都從那裡同步更新。
缺點:
單點故障:這是 CVCSs 最大的風險!如果中央伺服器故障或損壞,所有人的工作都會停擺,甚至可能丟失資料。
必須連線:開發者在進行任何版本操作(提交、更新)時,都必須連上網路,如果沒有網路,就無法進行任何版本管理。
單線程:因為所有人都共用一個中央伺服器,所以在分支和合併操作上相對複雜且不靈活。
DVCSs 是一種點對點(Peer-to-Peer)的架構。每個開發者的電腦上都存有一份完整的版本歷史,而不僅僅是當前檔案。
# Git 是這類系統中最知名的代表,也是目前業界最廣泛使用的工具。
優點:
不怕故障:因為每個開發者都有一個完整的備份,即使中央伺服器掛了,你也可以用任何一個人的本地備份來恢復,大大提高了安全性。
離線工作:你可以在沒有網路的情況下,自由地進行提交、分支、合併等操作,等到有網路時再同步到遠端。
分支和合併極度靈活:DVCSs 擅長處理複雜的分支,這使得團隊可以更自由地開發新功能或修復 Bug,不會互相干擾。
缺點:
空間佔用:因為每個本地儲存庫都包含了完整的歷史紀錄,所以會比 CVCSs 的本地工作目錄佔用更多一些的磁碟空間。
Git 基本語法
git –version # 驗證版本
git config –global user.email “信箱” # 輸入驗證信箱
git config –global user.name “名稱” # 輸入驗證名稱
git init# 建立tutorial目錄,套件庫需要的資訊會放在.git資料夾裡
git status # 確認tutorial目錄的狀態
檔案狀態的生命週期
untracked (未追蹤):當在專案資料夾裡建立一個新檔案,Git 知道它的存在,但不會對它的變動做任何追蹤。
unmodified (未修改):檔案已經被追蹤了,而且內容和上次提交時的狀態完全一樣。
modified (已修改):對被追蹤的檔案進行了修改,但還沒把這些修改「打包」起來,這時候檔案內容和上次提交時的內容不同。
staged (待提交):已經用 git add 打包好了,準備提交(commit)。這個狀態下的檔案,已經被標記為「準備好進入下一個版本」了。
流程步驟 (建立、修改、還原、提交、檢視、回朔) & 分支管理
流程 (untracked -> unmodified):這個流程只發生在第一次將一個全新的檔案納入 Git 管理時。
你用 git add 把一個 untracked 的新檔案加進來,它就變成 unmodified 狀態,因為此時它的內容還沒有任何修改。
流程 (unmodified <-> modified <-> staged):這個流程是日常開發中不斷重複的循環。
當一個檔案被 Git 追蹤後,你修改它(unmodified -> modified),然後用 git add 準備提交(modified -> staged),最後用 git commit 正式提交(staged -> unmodified)。這個循環會一直重複下去。
第一步:建立並提交新檔案
– 建立檔案:
先建立一個檔案,此時檔案處於 untracked 狀態。
– 追蹤檔案:
git add ‘檔案名稱’ 將檔案加入索引,。若要指向多個檔案,可用空白鍵將檔案們分開
# 檔案從 untracked 變成 staged
– 提交變更:
git commit -m “first commit” # 提交命令
# 檔案從 staged 變成 unmodified。此時,first commit 這個版本就正式被儲存到 Git 的歷史紀錄裡了。
第二步:修改、還原、提交
– 修改檔案:
當修改檔案內的內容後,檔案從 unmodified 變成 modified。
– 還原修改:
git restore ‘檔案名稱’ 把當前已修改 (modified) 的檔案,還原成上一次提交 (unmodified) 後的樣子。
# 這就像是你寫了一段程式碼,發現寫壞了,想回到最初的狀態,這個指令就是你的後悔藥!
– 重新修改並提交:
在次修改還原的內容,檔案會從 unmodified 變成 modified。
– 添加到待提交區: (git add ‘檔案名稱’ )
檔案從 modified 變成 staged。
– 正式提交: (git commit -m “要提交的訊息” )
檔案從 staged 變成 unmodified。
第三步:版本檢視與回溯版本
git log:顯示的是你目前分支的提交(commit)歷史,會根據提交的先後順序,把提交紀錄、作者、日期和訊息條列出來,但不會記錄任何沒有提交的行為,例如回溯版本、刪除分支。
git reflog:這是一個版本紀錄器,它會顯示你所有的 Git 操作歷史(包括提交、切換分支、合併、回溯版本)。
# 5c0b893 (HEAD -> main) HEAD@{0}: commit: second commit
# 1b2e67a HEAD@{1}: commit: first commit
git reset:這是一個返回功能,用來移動版本歷史。
git reset –soft [版本號碼]:移動 HEAD,但保留你當前的所有修改在待提交區 (staged)。
# 重新組織提交:你可能提交了太多次微小變動,想把它們合併成一個單一、有意義的提交
# 修改提交訊息:你提交了一個版本,但發現提交訊息寫錯了,或者描述不夠清楚。
情境:你發現 B 和 C 兩次提交太零碎了,想把它們合併成一個提交。
# 將 HEAD 回到 B 提交之前的版本
# ^ 代表上一個版本,所以 HEAD^ 會是 B
# HEAD^^ 則會是 A
# Git 會把你的 HEAD 指標移到提交 B。
# 但提交 C 的修改內容(file2.txt)不會消失,而是被放到暫存區。
# 現在你的工作區和暫存區同時有 file1.txt 和 file2.txt 的內容。
# 你可以用 git commit -m “Add files 1 & 2”,將這兩次提交合併成一個。
git reset –mixed [版本號碼]:移動 HEAD,並將修改退回到已修改 (modified) 狀態。這是 git reset 的預設模式。
git reset –hard [版本號碼]:移動 HEAD,並徹底刪除所有修改,讓你的工作目錄和待提交區都回到指定版本!
情境:你發現最近的兩個提交(B 和 C)都是錯誤的,你想完全捨棄它們,回到乾淨的初始提交 A。
git reset –hard HEAD^^
# Git 會將你的 HEAD 指標強制移到提交 A。
# 所有提交 B 和 C 的修改(file1.txt 和 file2.txt)都會被永久刪除!你的工作區會變回只有提交 A 的狀態。
建立分支:git branch 與 git checkout
git branch [分支名稱]:這個指令單純地建立一個新分支,但你仍然停留在當前分支上。
git checkout [分支名稱]:這個指令是切換到指定的分支。
git checkout -b [分支名稱]:它會先建立一個新分支,然後立刻切換過去。
# 從 master 分支出去,建立並切換到名為 ‘分支名稱‘ 的新分支
在切換之前,要注意以下幾點:
提交或暫存你的變更:
如果你當前工作目錄有未提交的變更,Git 會拒絕你切換分支,以防止你的變更在切換過程中遺失或被覆蓋。
必須先用 git add 和 git commit 將變更提交,或者使用 git stash 將變更暫存起來。
# git stash 是一個非常實用的指令,它可以將你目前的變更儲存起來,讓工作區變回乾淨狀態,待你切換回來後再恢復。
確定當前分支:
在切換之前,最好先用 git branch 或 git status 確認你目前在哪個分支。
否則你可能會切換到錯誤的分支,把你的變更提交到錯誤的地方。
合併分支:git merge
當在分支上完成開發並測試無誤後,就要把你的成果合併回主線了。
git merge [來源分支]:這個指令會將「來源分支」的變更,合併到「你當前所在的分支」上。
# 1. 先切換回 master 分支
git checkout master
# 2. 將 分支名稱 的變更合併過來
git merge 分支名稱
在合併之前,要注意以下幾點:
合併前先拉取最新程式碼:在合併之前,務必先執行 git pull origin main,確保你當前所在的分支(例如 main)是最新的,避免潛在的衝突。
處理合併衝突:如果你的程式碼與要合併進來的分支有衝突(兩邊都修改了同一行程式碼),Git 會暫停合併,並在檔案中標註衝突區域,你必須手動解決這些衝突,然後用 git add 和 git commit 來完成合併提交。
依序合併:將每個分支逐一合併到主分支。這會讓提交歷史看起來像一條直線,每個合併都是一個獨立的提交。
同時合併:將多個分支合併到一個新的分支,然後再將這個新分支合併到主分支。這會讓提交歷史看起來更整潔,特別適用於大型功能開發。
刪除分支:
git branch -d [分支名稱]:刪除一個已經被合併到當前分支的本地分支。
git branch -D [分支名稱]:強制刪除一個本地分支,即使它還沒有被合併。這是一個有風險的操作,請謹慎使用。
git push origin –delete [分支名稱]:刪除遠端的 Git 服務器上的分支。
Git 專案從無到有的完整流程
第一步:在 GitHub 上建立專案(遠端儲存庫)
登入 GitHub,點擊右上角的 + 號,選擇 New repository。
輸入專案名稱 test-project。
選擇 Public 或 Private,看專案是否需要公開。
勾選 Add a README file,這樣專案一開始就不會是空的,可以避免一些推送問題。
點擊 Create repository,成功建立遠端專案了!
# 初次建立可以先把專案中的分支先建立好,保留一個最後整合的主支
第二步:在本機建立專案(本地儲存庫)
複製專案連結:在 GitHub 專案頁面上,點擊綠色的 Code 按鈕,然後複製 HTTPS 連結。
開啟命令列工具,並切換到想要存放專案的資料夾。
使用 git clone 指令:git clone [剛剛複製的連結]
# Git 會自動建立一個名為 test-project 的資料夾,並把遠端專案的檔案下載下來,同時也自動設定好了遠端的連結。
第三步:在新裝置上工作並提交變更
假設現在換了一台電腦,要從頭開始開發。
重複第二步的 git clone:在新電腦上執行 git clone,將專案複製下來。
更新檔案:在本地專案資料夾裡,開始新增或修改程式碼。例如,修改了 READ.md,並新增了一個 index.html 檔案。
檢查狀態:git status
# 會告訴你 README.md 處於 modified 狀態,而 index.html 處於 untracked 狀態。
加入待提交區:git add .
# . 代表將所有變動(包含修改和新增的檔案)都加入待提交區。
提交到本地版本庫:git commit -m “feat: Add initial HTML structure”
# 變更已經保存在本地的電腦裡了。
推送到 GitHub:將本地的變更同步到遠端。
git push origin main
# origin 是遠端專案的名稱,main 是分支名稱。如果你的本地分支是 master,記得要先用 git branch -M main 重新命名。
第四步:下載其他人的新程式碼
拉取最新版本:git pull origin main
# Git 會自動從遠端(origin)的 main 分支下載所有新的變更,並與你本地的程式碼自動合併。
# 本地專案就是最新的版本了,你可以繼續你的開發。
常見的突發狀況
1. 首次推送失敗:src refspec main does not match any
原因:你的本地專案沒有任何提交,或者主分支名稱不對(例如是 master 而不是 main)。
解決方案:
務必先執行 git commit:你的本地專案必須至少有一個提交,才能被推送到遠端。
重新命名分支:如果本地分支是 master,在第一次推送前,先執行 git branch -M main。
2. 推送被拒絕:! [rejected] main -> main (fetch first)
原因:在你 git push 之前,你的夥伴已經先一步提交了新的程式碼。你的本地版本已經不是最新的了。
解決衝突的通用流程
(1.)拉取最新程式碼:當你遇到 ! [rejected] 錯誤時,第一步永遠是 git pull,這會將遠端的變更拉到你的本地,並觸發合併。
(2.)識別衝突:Git 會在衝突的檔案中加入特殊的標記,例如 <<<<<<< HEAD 和 >>>>>>>,來告訴你衝突在哪裡。
(3.)解決衝突方式:
– 選擇工具:用 git mergetool 或 GUI 工具來處理。
– 手動修改:根據需求,選擇保留你或對方的程式碼,然後移除那些標記。
(4.)提交變更:當所有衝突都解決後,再次 git add 和 git commit,完成這次的合併提交。
(5.)推送到遠端:最後,git push 將你成功解決衝突的版本上傳。
3. 分支管理
業界常規:一般來說,不會直接在 main 分支上工作。
正確流程:
從 main 分支建立一個新的分支來開發你的新功能或修復 Bug。
git checkout -b feature/my-new-feature
# 在這個新分支上進行 git add 和 git commit。
當功能完成後,將新分支推送到 GitHub,然後發起一個 Pull Request。
團隊成員會審查你的程式碼,通過後才會合併到 main 分支。
# 這麼做的好處是,即使你寫錯了程式碼,也不會影響到主分支的穩定性,可以確保專案永遠處於可運行的狀態。