Git是什麼?版本控制的原理與GitHub的差異

約 11 分鐘 · 更新:2026年10月23日

版本控制是把檔案的變更,連同「何時、誰、改了什麼、為什麼」一起記錄下來,並且可以回到之前狀態的機制。代表性的軟體是Git。它把當時整體的快照(提交)依序串起來,也能分岔(分支)同時進行不同的工作。GitHub不是Git,而是代管Git存放處、協助團隊確認內容的網路服務。

這篇文章可以了解

  • 有了版本控制,會有什麼改變
  • 提交、歷史、分支、合併、衝突的意思
  • 集中式(Subversion)與分散式(Git)的差異,以及Git與GitHub的差異
  • 拉取請求與審查,以及Git分辨內容的方法(雜湊值)
  • 為什麼不能提交密碼或API金鑰

先備知識:不需要。只要曾經在電腦上儲存檔案、把檔案分到資料夾裡,就能讀懂。

生活中的例子

你是否在共用資料夾裡看過這樣的檔案?「企劃書.docx」「企劃書_最終版.docx」「企劃書_最終版_v2.docx」「企劃書_最終版_v2_最新.docx」。哪一個才是真正的最新版?v2改了什麼?光看檔名無從得知。

兩個人各自打開同一個檔案修改,會更麻煩。因為後存檔的人,會把先存檔那個人的修改蓋掉。

在軟體開發中,這種事的規模大上好幾個數量級。有時幾十個人會同時改寫幾千個檔案。這時派上用場的,就是「版本控制」的機制。

版本控制是什麼:留下變更紀錄的機制

Git官方網站公開的說明書《Pro Git》,是這樣說明版本控制的:隨著時間記錄檔案的變更,之後可以叫出特定版本的機制。做這件事的軟體,稱為「版本控制系統」。

把檔案複製到加上日期的資料夾,方法很簡單。但《Pro Git》寫道,這種做法容易出錯,因為很容易覆寫到別的資料夾裡的檔案。用版本控制系統,還能知道哪個變更是誰、在何時加入的,也有助於找出問題的原因。

代表性的軟體是Git。主要的對象是程式,但只要是以文字寫成的檔案,都能用同樣的方式管理。半導體晶片的電路,也常以類似文章的形式寫出來進行設計(「編譯器是什麼?」)。

原理①:提交——附有說明的「當下快照」

在Git中,留下紀錄的單位稱為「提交」(commit)。一個提交,就是當時所有檔案的快照。上面還會附上「誰」「何時」,以及寫明變更理由的簡短文字(提交訊息)。

實際上,沒有變更的檔案只會指向之前存好的那一份,以節省空間。這裡為了讓說明簡單,先當作「會留下整體的快照」。

重要的是,提交和儲存檔案是不同的操作。檔案存檔再多次,也不會自動提交。要在完成一段有意義的工作時,例如「修正了標題」,自己動手提交。

原理②:歷史——查看、還原、比較以前的版本

每個提交都記得前一個提交是哪一個。所以順著提交往回追,從最初到現在的變更就會排成一條流程。這稱為「歷史」。

有了歷史,就能只取出兩個版本之間的不同之處來看。這個不同之處稱為「差異」(diff)。如果在1,000行的檔案裡改了3行,就只會顯示那3行和前後幾行。

也可以回到之前的狀態,只還原一個檔案或還原全部都可以。和團隊共用之後要取消變更,基本做法是新增一個「抵銷之前變更」的提交。因為不刪除歷史,「何時、為什麼還原」也會留在紀錄裡。

最擅長處理的是以文字寫成的檔案。Word文件和圖片也能存放。只是預設的差異只會顯示「內容不同」(《Pro Git》8.2節)。

原理③:分支與合併——分岔出去,再匯合回來

正在開發新功能的檔案,有時還無法運作。把它放進主線,連其他人的工作都會停擺。所以在Git中,會讓歷史分岔,在不影響主線的情況下繼續工作。

這個分岔稱為「分支」(branch)。它的本質是一個有名字的標記,指向某條流程中最新的提交。因為不會整個複製檔案,所以馬上就能建立,也幾乎不占空間。主線的分支常用main或master這樣的名字。

功能完成後,就把分支的變更納入主線。這稱為「合併」(merge)。Git會比較從分岔點開始,兩邊各改了什麼。如果改的是不同的地方,就會自動把兩邊組合起來。

分支從主線的歷史分岔出去,進行別的工作後,透過合併匯入主線 主線(main) 合併 A B C M X Y 分岔 分支(新功能) 時間
每個圓圈代表一次提交。在從B分岔出去的分支上做X和Y的期間,其他人在主線上加了C。透過M的合併,兩邊的變更合而為一。省略的部分:實際的紀錄是由新的提交指向前一個提交的方向串起來;也省略了分支的標記本身。

Git的指令,例如像下面這樣。用畫面上的按鈕做同樣事情的工具,也很常用。

指令的例子意思
git commit -m "修正標題的錯字"把選好的變更附上說明後提交
git log --oneline以一個提交一行的方式顯示歷史
git switch -c new-feature建立名為new-feature(新功能)的分支並切換過去
git merge new-feature把new-feature的變更合併到目前所在的分支

原理④:衝突——同一個地方被各自修改時

有時候無法自動組合。那就是兩個分支把同一個檔案的同一處,改成了不同內容的情況。例如,A同事把會議時間改成「10點」,B同事則改成「11點」。

哪一個才對,Git無法判斷。所以Git不會擅自選一邊,而是停止合併。檔案的那個部分,會並列出兩邊的內容。分隔處會加上「<<<<<<<」等標記。這種狀態稱為「衝突」(conflict)。

修正是人的工作。兩個人討論後改寫成正確的內容,刪掉標記再提交。衝突不是故障,而是「需要由人決定的分歧」的通知。經常合併,就比較不容易發生。

集中式與分散式:Subversion與Git

版本控制系統大致分為兩種類型。第一種是把歷史全部放在一台伺服器上,每個人從那裡取出最新版本來工作。這稱為「集中式」。代表是Subversion,2000年開始開發。官方網站也自稱是集中式。

集中式因為所有人都看同一個地方,優點是容易管理。另一方面,《Pro Git》也舉出了弱點。伺服器停止的期間,誰都無法留下紀錄。伺服器的硬碟壞掉又沒有備份的話,歷史會全部消失。像這樣一處停止就讓整體停止的地方,稱為單一故障點。

第二種是Git的「分散式」。每個人的電腦裡,不只有最新版本,還複製了完整的歷史。所以提交、查看歷史等大部分操作都在本機完成,沒有網路也能工作。每個人的複本,也都是全部資料的備份。

集中式的完整歷史只在伺服器上,分散式則每個人的本機也有完整的歷史 集中式(Subversion等) 伺服器 完整歷史 本機 工作版本 本機 工作版本 本機 工作版本 分散式(Git) 共用的存放處 完整歷史 本機 完整歷史 本機 完整歷史 本機 完整歷史 只有傳送、取回時才需要連線
集中式每次留下紀錄,都要和伺服器溝通。分散式則在本機提交,想共用時再傳送。省略的部分:集中式的本機也有工作前版本的備份;共用的存放處可以有好幾個。

版本的稱呼方式也不同。Subversion的版本會依序編上1、2、3的流水號。在Git中,每個人各自提交,無法決定編號,所以改用由內容計算出來的值。

Git誕生的經過

Git是為了開發作業系統Linux而誕生的。根據《Pro Git》,1991~2002年,Linux的變更是以差異或壓縮檔的形式交換的。從2002年起,開始免費使用某家公司的分散式產品BitKeeper。

2005年,Linux的開發者們和那家公司的關係惡化,無法再免費使用。於是以創造Linux的林納斯·托瓦茲(Linus Torvalds)為中心,做出了自己的工具。那就是Git。目標包括速度快、能同時處理數千條分支等。

遠端儲存庫與GitHub、GitLab

在Git中,存放檔案和完整歷史的地方稱為「儲存庫」(repository)。自己電腦裡的是本機儲存庫。為了讓團隊共用而放在伺服器上的儲存庫,稱為「遠端儲存庫」。

只在本機提交,其他人是看不到的。要用git push指令送到遠端,其他人再用git pull取回。在送出之前,可以在本機累積任意多次的提交。

代管遠端儲存庫的代表性服務,是GitHub和GitLab。GitHub自稱是「用來存放、分享程式碼,並與他人一起撰寫的雲端平台」。GitLab是在儲存庫管理之外,加上審查和自動測試功能的產品,也可以架設在自家公司的伺服器上使用。

也就是說,Git是在本機運作的軟體,GitHub和GitLab是代管Git儲存庫的服務。Git也可以只在公司內部的伺服器上使用。

拉取請求:合併前先請人看過

在團隊開發中,通常不會擅自把自己的分支合併進主線。在那之前,會先提出「請把這個變更放進主線」的提案。GitHub稱為「拉取請求」(Pull Request),GitLab稱為「合併請求」(Merge Request)。

提案的畫面上會列出變更的差異和說明。其他人閱讀差異,在有疑問的行留言,提出的人修正後再追加提交。這個確認的過程稱為「程式碼審查」,得到同意後就合併。

每次提案都自動執行測試的設定也很常見。把變更經常整合到主線,每次都自動檢查的做法,稱為持續整合(CI)。

Git怎麼分辨內容?

Git會從要存放的檔案內容,計算出固定長度的值。相同的內容一定會得到相同的值,只要差一個字,就會變成完全不同的值。這種計算稱為雜湊函數,得到的值稱為雜湊值。

Git預設使用的雜湊函數是SHA-1,值以0~9和a~f共40個字元表示。下表是對只差一個字的兩個檔案,用和Git相同的方法算出的值的前10個字元。因為雜湊值取決於確切的內容,檔案內容照原文(日文)列出。意思分別是「會議從10點開始」「會議從11點開始」。

檔案內容(結尾有1個換行)雜湊值(前10個字元)
会議は10時からd7a6150543…
会議は11時から3eec220ecf…

Git把這個值當作檔案和提交的名稱。內容相同,名稱也相同,所以同樣的東西不必存兩次。存放的內容就算損壞,重新計算的值也會和名稱對不上,因此能夠察覺。

提交的名稱也用同樣的方法決定。提交裡也寫入了前一個提交的名稱。所以只要偷偷改寫過去的任何一個提交,在它之後所有提交的名稱都會改變。平常會縮短成前7個字元左右來顯示。

密碼學用的雜湊函數,設計成實際上無法做出得到相同值的另一筆資料。這是和找出傳輸錯誤的CRC最大的不同。

不過,SHA-1在2017年被實際展示了做出兩筆相同值資料的攻擊。Git加入了識破這種攻擊的機制,並選擇SHA-256作為後繼。在2026年10月時的Git說明文件中,預設仍是SHA-1。預計在下一個大版本Git 3.0,把新儲存庫的預設改為SHA-256,但時間還沒有決定。

密碼和API金鑰不要提交

版本控制的強項是「不會消失」。但這有時會帶來反效果。那就是不小心把密碼,或是使用服務用的祕密鑰匙(API金鑰)寫進檔案並提交的情況。

就算發現後從檔案刪掉、再提交一次,之前的提交裡還是留著。能看到儲存庫的人,只要順著歷史就能取出。GitHub的說明文件也提醒,即使改寫歷史,也可能留在其他人的複本等地方。

因此,只要曾經送到共用的地方,就要把那個祕密當作已經外洩。基本做法是到發行的一方讓那把金鑰失效,換成新的。原本就不要把祕密寫在程式的檔案裡,而是放在別的地方。金鑰的保護方法,在「API是什麼?」中有說明。把不想放進去的檔案名稱寫進「.gitignore」,還沒納入Git管理的檔案就會被忽略。

常見的誤解

誤解:Git和GitHub是同一個東西

實際上,Git是在自己電腦上運作的版本控制軟體。GitHub是代管Git儲存庫,再加上拉取請求等協作功能的網路服務。沒有GitHub也能使用Git。因為名字相似,又常常一起使用,所以容易混淆。

誤解:只要提交,變更就會傳給團隊的所有人

實際上,提交是記錄在本機儲存庫裡。要傳給其他人,必須用git push送到遠端儲存庫。反過來說,其他人的變更,在取回之前也不會進到你的電腦。集中式的Subversion留下紀錄的操作會直接送到伺服器,所以同一個詞容易造成誤解。

誤解:版本控制是只有程式設計師才用的工具

實際上,幾乎任何檔案都能管理。《Pro Git》也推薦給想保留圖片和版面配置各個版本的設計師。不過,Word文件等檔案的差異比較難看出來。

從數字來看

項目數字/時間備註
Linux的變更以差異或壓縮檔交換1991~2002年《Pro Git》
Subversion開始開發2000年集中式的代表
Git誕生2005年林納斯·托瓦茲等人
SHA-1雜湊值的長度40個字元(160位元)以0~9和a~f表示
縮短顯示的長度從7個字元起無法分辨時會加長
偶然出現相同值的機率達到一半所需的數量約2的80次方(約1.2×10的24次方)個《Pro Git》的估算
發表以SHA-1做出相同值的攻擊2017年2月SHAttered
Git選擇SHA-256作為後繼2018年下半年預設仍是SHA-1。預計在Git 3.0成為新儲存庫的預設(時間未定,2026年10月時)

2的80次方,大約是1兆的1兆倍。偶然出現相同值幾乎不必擔心,要擔心的是刻意做出相同值的攻擊。這就是改用SHA-256的理由。

進一步學習

系列「電腦的原理」的文章

  1. 電腦怎麼用0和1計算?二進位與加法電路
  2. CPU是什麼?它在電腦和手機裡做些什麼
  3. AI為什麼要用GPU?同時處理大量乘法的原理
  4. 作業系統(OS)是什麼?它在電腦和手機裡做些什麼
  5. CPU快取記憶體是什麼?讓CPU不必苦等記憶體的原理
  6. NPU是什麼?手機和電腦裡的AI專用電路原理
  7. FPGA是什麼?做好之後還能改寫電路的晶片原理
  8. ASIC是什麼?特定應用積體電路與CPU、FPGA的差異
  9. 編譯器是什麼?程式變成機器碼的過程
  10. 邏輯閘是什麼?用AND、OR、NOT計算的原理
  11. RISC-V是什麼?人人都能使用的開放指令集
  12. 演算法是什麼?靠步驟的巧思讓計算變快的原理
  13. 資料庫是什麼?表格、SQL與索引的運作原理
  14. Git是什麼?版本控制的原理與GitHub的差異

這個領域的題目: Linux與命令列基礎

參考資料

入門解說一覽