Git輕松入門1:本地倉庫篇


什么是Git

版本控制系統

首先我們要明白,什么是版本控制系統(version control systems)?

版本控制系統,顧名思義,就是能控制文件處於哪個版本的系統。

e.g. 你在博客園里編輯的文章,你可以控制文章是處於某個時間點的版本。

而Git就是一款版本控制系統,而且是分布式的。

與分布式相對應的是集中式版本控制系統,它的版本庫是存儲在中央服務器的。工作的時候你需要先從中央服務器取得最新的版本,等工作完了,再把自己的工作推送回中央服務器。但這有個問題:萬一哪天中央服務器崩潰了甚至數據丟失了,那所有人不就都無法工作了?

於是分布式版本控制系統(Distributed Version Control System,簡稱 DVCS)就應運而生了。它沒有“中央服務器”,每個人的電腦上都有一份完整的版本庫,如果某個人的電腦壞了導致版本庫丟失了,直接從別人那復制一個版本庫過來即可。

Git的基本工作原理

有一類版本控制系統是基於差異(delta-based)來進行版本控制的。

這類版本控制系統存儲的是新文件和舊文件間的區別(delta)。這里的delta和高中物理里的delta一樣,\(Δv = v_2 - v_1\),都指的是變化量。

而Git和上述這類版本控制系統的工作原理不同:每當你對提交新項目或者對項目進行修改,它會把項目的所有文件都壓縮保存起來,這個壓縮文件在Git中被稱為快照(snapshot)。每次有更新就會每次把所有文件都壓縮起來存儲一遍,形成一系列快照。

當我們需要處於某個時間點版本的文件時,直接根據索引,找到那個時間點的快照即可。

操作指令

在開始介紹Git相關的指令前,我們先創建三個文件。

創建版本庫

所謂“版本庫(repository)”就是一個用來存儲文件歷史版本的倉庫。所以要想對文件進行版本控制,我們需要先初始化一個版本庫來存儲文件的各個歷史版本。

$ git init 命令能把當前所在目錄變為由Git管理的倉庫(或是對該位置已有倉庫進行初始化),使得該目錄下的文件可被Git進行版本控制。

當執行完該命令后,可以看到該目錄下生成了一個 .git 的文件夾。

把文件添加到版本庫

創建完版本庫后,我們還需要把文件放進去才能對其進行版本控制。

而把文件添加到版本庫需要兩個步驟:

第一步,用 $ git add 命令把需要跟蹤版本的文件添加到暫存區。

第二步,用 $ git commit 命令告訴倉庫:我確定要對暫存區里的文件進行版本控制,請把暫存區里的文件正式放入倉庫管理。

-m "xxx" 是對本次提交的備注說明;2 files changed 指有兩個文件變動:即我們新添加的 README.mddemo1.txt1 insertion 指插入1行內容:即我們在 README.md 文件中插入的“Git is a version control system.”。

在每次提交變動(commit)后,都會產生對應的快照。快照,我們在Git的工作原理那章提到過,它就是被放入版本庫中的所有文件的壓縮版本。我們可以把快照理解成是游戲的存檔。在玩游戲時,我們每通過一關就會保存游戲。如果進行到某一關死了,那就可以通過讀取存檔來回到前面的某一關。Git也一樣,每次commit就是在給文件存檔,要是哪一天文件誤刪了或出錯了,那我們就可以讀取存檔,讓文件恢復到存檔時的狀態。

通過 $ git log 命令,可以查看當前共有幾個存檔。

同步修改到版本庫

當我們在工作區(工作區就是當你打開“我的電腦”看到的目錄就叫工作區)里對文件進行修改后,如何把更新同步到版本庫中,讓版本庫也擁有文件最新的版本呢?

我們先添加一行話到 README.md 文件中,使其內容變為如下:

Git is a version control system.
Git is distributed. 

現在,運行 $ git status 命令查看版本庫當前狀態:

從狀態中我們可以得到2個信息:

  1. README.md 文件進行了修改,並且這次修改還沒有被添加到暫存區。
  2. learn_git 目錄下,demo2.txt 文件沒被添加到倉庫中以進行版本追蹤。

如果我們想要進一步得知對 README.md 文件進行了哪些修改,可以用 $ git diff 命令(這步並不是必須的)。

可以看到,新增加的改動是“Git is distributed”這行話。

確定了作出哪些修改后,再把它提交到倉庫自然就放心多了。提交修改和之前提交新文件需要同樣的兩個步驟:$ git add$ git commit

我們先運行 $ git add,然后看看版本庫狀態。

可以看到,當我們用 $ git add 命令把文件添加到暫存區后,版本庫狀態就不會再提示我們“尚未暫存已備提交的變更”,而是提示“要提交的變更”,即提示我們要用 $ git commit 命令提交這次變更。

那我們就再運行一下 $ git commit 命令,再來看看版本庫狀態。

再用git log查看一下當前共有幾個存檔(快照)。

從以上兩張截圖可以看出現在已經沒有需要提交的修改了,只剩下未跟蹤的文件 demo2.txt 了,剛才的那次變動已經被版本庫存檔了。

把文件從版本庫中刪除

刪除文件也算是對文件的一種修改。同樣也需要兩步:

  1. $ git rm <file> 把該文件從工作區刪除。
  2. commit這次變動,把刪除同步到版本庫。

注:在執行 $ git rm <file> 指令時,Git會默認執行 $ git add 命令來把這次修改提交到暫存區。

回退到某個版本

我們已知目前共有2個存檔:第一個存檔的ID是b1a6863...,存檔備注是“added README and demo1”;第二個存檔的ID是245fcc1...,存檔備注是“modified README”。

在Git中,HEAD 是一個指針,它會指向當前所在分支的最新存檔,分支的概念我們后邊在介紹,但反正目前我們沒有創建別的分支。你讓 HEAD 指向哪個版本號,Git就把當前版本定位在哪。所以此時 HEAD 代表的就是ID為245fcc...的存檔,那么在它前一個的存檔就是 HEAD^,前N個的存檔就是 HEAD~N

有一天你可能會覺得第二個版本很糟糕,不如第一個版本,於是想坐時光機回到過去,讓一切復原到第一個版本時的樣子。這時我們可以用 $ git reset 命令來幫助我們穿越時空。

我們再來看一下 README.md 里的內容,后面新添加的那行就不見了,內容回到了最初的時候:

Git is a version control system.

再運行一下 $ git log

一切真的都回到了過去!連存檔都變成和當時一樣,只有b1a6863...這一個了!

為什么回退的速度這么快呢?

因為我們每個版本的文件都被保存在了快照里,Git僅僅只需要把 HEAD 指針從一個快照指向到另一個快照,再把目錄里的文件替換成那個快照里的文件即可。

所以建議:無論是大的變動還是小的變動,都存一下檔(即commit)。只有把這個版本存檔了,保存進快照里了,日后才能通過讀檔來返回到該版本。

可萬一你又后悔了,覺得一切還是像第二個版本時的那樣好,怎么辦?通過 $ git log 命令已經找不到第二個版本的存檔了,是不是回不去了?

並不是的。在Git中,你的每次操作就會留下記錄,我們可以用 $ git reflog 來查看所有的操作。

從中我們可以看到,備注為“modified README”的那次commit的ID是245fcc1。有了commit ID后,我們就又能通過 $ git reset 命令回到未來了!

再運行一下 $ git log 和打開 README.md 文件,可以確認真的回到了未來!

撤銷修改

撤銷修改有三種情況:

  1. 修改還沒添加到暫存區。
  2. 修改已經添加到暫存區,但還沒commit。
  3. 修改已經commit。

修改還沒添加到暫存區

我們先談第一種情況。

假設你往 README.md 文件里添加了一行“My boss is stupid. ”,而這最新修改還沒有被你添加到暫存區。所以當你運行$ git status 命令時,你看到Git提示你有尚未暫存已備提交的修改。

你覺得這句話可能會讓你被炒魷魚,盡管你說的是事實。於是你最終還是決定把這句話刪掉。

有兩種刪除方式:

  1. 手動打開 README.md 文件,然后把這句話刪掉,讓文件回到添加這行話前的樣子。
  2. 按照Git提示的,用 $ git restore <file> 命令,來直接撤銷改文件在工作區的變動。

你覺得第二種方式看起來顯得逼格更高點,於是你輸入如下命令。

$ git restore README.md

然后當你再打開README.md文件,發現那句話果然消失了;再運行 $ git status 命令,發現Git也沒有任何提示了。

修改已經添加到暫存區但還沒commit

再來談談第二種情況:你不僅寫了那句話,還提交到了暫存區!所以當你運行 $ git status 命令時,你看到Git提示你有要提交的變更。

有了上次撤銷的經驗,你就放心地按照Git的提示輸入如下命令:

$ git restore --staged README.md

再運行 $ git status,你發現現在它提示的和第一種情況一樣了,而打開工作區里 README.md 文件,那句話還在。原來這個命令只是幫你撤銷一小步,僅僅是從暫存區移除,而不是幫你一夜回到解放前。

當然了,如果你很不幸的已經commit這次提交了,那就只能用 $ git reset 來版本回退了。

總結

Git中文件的所有狀態以及狀態間的轉換可以被概括為下面這張圖。

最后,總結一下今天出現過的幾個Git命令:

# 創建版本庫
$ git init

# 把文件添加到暫存區
$ git add <file>

# 把暫存區里的變動提交到版本庫
$ git commit

# 查看當前所有快照
$ git log

# 查看版本庫當前狀態
$ git status

# 查看某文件的變動
$ git diff

# 刪除文件,並把這次變動提交到暫存區
$ git rm <file>

# 版本間的前進和回退
$ git reset

# 撤銷修改
$ git restore

參考

  1. https://sp18.datastructur.es/materials/guides/using-git.html
  2. https://www.liaoxuefeng.com/wiki/896043488029600
  3. http://git-scm.com/book/en/v2/Getting-Started-What-is-Git%3F
  4. https://stackoverflow.com/questions/4964099/what-is-a-git-snapshot

 
有問題歡迎大家在評論區留言,轉載請注明出處。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM