天天看點

分布式版本控制系統 Git 教程

簡介

Git 是什麼?

Git 是一個開源的分布式版本控制系統。

什麼是版本控制?

版本控制是一種記錄一個或若幹檔案内容變化,以便将來查閱特定版本修訂情況的系統。

什麼是分布式版本控制系統?

介紹分布式版本控制系統前,有必要先了解一下傳統的集中式版本控制系統。

集中化的版本控制系統,諸如 CVS,Subversion 等,都有一個單一的集中管理的伺服器,儲存所有檔案的修訂版本,而協同工作的人們都通過用戶端連到這台伺服器,取出最新的檔案或者送出更新。

這麼做最顯而易見的缺點是中央伺服器的單點故障。如果當機一小時,那麼在這一小時内,誰都無法送出更新,也就無法協同工作。要是中央伺服器的磁盤發生故障,碰巧沒做備份,或者備份不夠及時,就會有丢失資料的風險。最壞的情況是徹底丢失整個項目的所有曆史更改記錄。

分布式版本控制系統 Git 教程

分布式版本控制系統的用戶端并不隻提取最新版本的檔案快照,而是把代碼倉庫完整地鏡像下來。這麼一來,任何一處協同工作用的伺服器發生故障,事後都可以用任何一個鏡像出來的本地倉庫恢複。因為每一次的提取操作,實際上都是一次對代碼倉庫的完整備份。

分布式版本控制系統 Git 教程

為什麼使用 Git?

Git 是分布式的。這是 Git 和其它非分布式的版本控制系統,例如 svn,cvs 等,最核心的差別。分布式帶來以下好處:

工作時不需要聯網

首先,分布式版本控制系統根本沒有“中央伺服器”,每個人的電腦上都是一個完整的版本庫,這樣,你工作的時候,就不需要聯網了,因為版本庫就在你自己的電腦上。既然每個人電腦上都有一個完整的版本庫,那多個人如何協作呢?比方說你在自己電腦上改了檔案A,你的同僚也在他的電腦上改了檔案A,這時,你們倆之間隻需把各自的修改推送給對方,就可以互相看到對方的修改了。

更加安全

集中式版本控制系統,一旦中央伺服器出了問題,所有人都無法工作。

分布式版本控制系統,每個人電腦中都有完整的版本庫,是以某人的機器挂了,并不影響其它人。

原理

版本庫

當你一個項目到本地或建立一個 git 項目,項目目錄下會有一個隐藏的

.git

子目錄。這個目錄是 git 用來跟蹤管理版本庫的,千萬不要手動修改。

哈希值

Git 中所有資料在存儲前都計算校驗和,然後以校驗和來引用。 這意味着不可能在 Git 不知情時更改任何檔案内容或目錄内容。 這個功能建構在 Git 底層,是構成 Git 哲學不可或缺的部分。 若你在傳送過程中丢失資訊或損壞檔案,Git 就能發現。

Git 用以計算校驗和的機制叫做 SHA-1 散列(hash,哈希)。 這是一個由 40 個十六進制字元(0-9 和 a-f)組成字元串,基于 Git 中檔案的内容或目錄結構計算出來。 SHA-1 哈希看起來是這樣:

24b9da6552252987aa493b52f8696cd6d3b00373           

Git 中使用這種哈希值的情況很多,你将經常看到這種哈希值。 實際上,Git 資料庫中儲存的資訊都是以檔案内容的哈希值來索引,而不是檔案名。

檔案狀态

在 GIt 中,你的檔案可能會處于三種狀态之一:

  • 已修改(modified)

已修改表示修改了檔案,但還沒儲存到資料庫中。

  • 已暫存(staged)

已暫存表示對一個已修改檔案的目前版本做了标記,使之包含在下次送出的快照中。

  • 已送出(committed)

已送出表示資料已經安全的儲存在本地資料庫中。 

工作區域

與檔案狀态對應的,不同狀态的檔案在 Git 中處于不同的工作區域。

  • 工作區(working)

當你

git clone

一個項目到本地,相當于在本地克隆了項目的一個副本。

工作區是對項目的某個版本獨立提取出來的内容。 這些從 Git 倉庫的壓縮資料庫中提取出來的檔案,放在磁盤上供你使用或修改。

  • 暫存區(staging)

暫存區是一個檔案,儲存了下次将送出的檔案清單資訊,一般在 Git 倉庫目錄中。 有時候也被稱作`‘索引’',不過一般說法還是叫暫存區。

  • 本地倉庫(local)

送出更新,找到暫存區域的檔案,将快照永久性存儲到 Git 本地倉庫。

  • 遠端倉庫(remote)

以上幾個工作區都是在本地。為了讓别人可以看到你的修改,你需要将你的更新推送到遠端倉庫。

同理,如果你想同步别人的修改,你需要從遠端倉庫拉取更新。

安裝

Linux

Debian/Ubuntu

如果你使用的系統是 Debian/Ubuntu , 安裝指令為:

$ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \
> libz-dev libssl-dev
$ apt-get install git-core
$ git --version
git version 1.8.1.2           

Centos/RedHat

如果你使用的系統是 Centos/RedHat ,安裝指令為:

$ yum install curl-devel expat-devel gettext-devel \
> openssl-devel zlib-devel
$ yum -y install git-core
$ git --version
git version 1.7.1           

Windows

Git 官方下載下傳位址

下載下傳 exe 安裝包。按照安裝向導安裝即可。

建議安裝 Git Bash 這個 git 的指令行工具。

Mac

下載下傳 mac 安裝包。按照安裝向導安裝即可。

配置

Git 自帶一個 

git config

 的工具來幫助設定控制 Git 外觀和行為的配置變量。 這些變量存儲在三個不同的位置:

  1. /etc/gitconfig

     檔案: 包含系統上每一個使用者及他們倉庫的通用配置。 如果使用帶有 

    --system

     選項的 

    git config

     時,它會從此檔案讀寫配置變量。
  2. ~/.gitconfig

     或 

    ~/.config/git/config

     檔案:隻針對目前使用者。 可以傳遞 

    --global

     選項讓 Git 讀寫此檔案。
  3. 目前使用倉庫的 Git 目錄中的 

    config

     檔案(就是 

    .git/config

    ):針對該倉庫。

每一個級别覆寫上一級别的配置,是以 

.git/config

 的配置變量會覆寫 

/etc/gitconfig

 中的配置變量。

在 Windows 系統中,Git 會查找 

$HOME

 目錄下(一般情況下是 

C:\Users\$USER

)的 

.gitconfig

 檔案。 Git 同樣也會尋找 

/etc/gitconfig

 檔案,但隻限于 MSys 的根目錄下,即安裝 Git 時所選的目标位置。

使用者資訊

當安裝完 Git 應該做的第一件事就是設定你的使用者名稱與郵件位址。 這樣做很重要,因為每一個 Git 的送出都會使用這些資訊,并且它會寫入到你的每一次送出中,不可更改:

$ git config --global user.name "John Doe"
$ git config --global user.email [email protected]           

再次強調,如果使用了 

--global

 選項,那麼該指令隻需要運作一次,因為之後無論你在該系統上做任何事情, Git 都會使用那些資訊。 當你想針對特定項目使用不同的使用者名稱與郵件位址時,可以在那個項目目錄下運作沒有 

--global

 選項的指令來配置。

很多 GUI 工具都會在第一次運作時幫助你配置這些資訊。

.gitignore

.gitignore

檔案可能從字面含義也不難猜出:這個檔案裡配置的檔案或目錄,會自動被 git 所忽略,不納入版本控制。

在日常開發中,我們的項目經常會産生一些臨時檔案,如編譯 Java 産生的

*.class

檔案,又或是 IDE 自動生成的隐藏目錄(Intellij 的

.idea

目錄、Eclipse 的

.settings

目錄等)等等。這些檔案或目錄實在沒必要納入版本管理。在這種場景下,你就需要用到

.gitignore

配置來過濾這些檔案或目錄。

配置的規則很簡單,也沒什麼可說的,看幾個例子,自然就明白了。

這裡推薦一下 Github 的開源項目:

https://github.com/github/gitignore

在這裡,你可以找到很多常用的模闆,如:Java、Nodejs、C++ 的

.gitignore

模闆等等。

指令

國外網友制作了一張 Git Cheat Sheet,總結很精煉,各位不妨收藏一下。

本節選擇性介紹 git 中比較常用的指令行場景。

建立

克隆一個已建立的倉庫

# 通過 SSH
$ git clone ssh://[email protected]/repo.git

#通過 HTTP
$ git clone http://domain.com/user/repo.git           

建立一個新的本地倉庫

$ git init           

添加修改

添加修改到暫存區

# 把指定檔案添加到暫存區
$ git add xxx

# 把目前所有修改添加到暫存區
$ git add .

# 把所有修改添加到暫存區
$ git add -A           

送出修改到本地倉庫

# 送出本地的所有修改
$ git commit -a

# 送出之前已标記的變化
$ git commit

# 附加消息送出
$ git commit -m 'commit message'           

儲藏

有時,我們需要在同一個項目的不同分支上工作。當需要切換分支時,偏偏本地的工作還沒有完成,此時,送出修改顯得不嚴謹,但是不送出代碼又無法切換分支。這時,你可以使用

git stash

将本地的修改内容作為草稿儲藏起來。

官方稱之為儲藏,但我個人更喜歡稱之為存草稿。

# 1. 将修改作為目前分支的草稿儲存
$ git stash

# 2. 檢視草稿清單
$ git stash list
stash@{0}: WIP on master: 6fae349 :memo: Writing docs.

# 3.1 删除草稿
$ git stash drop stash@{0}

# 3.2 讀取草稿
$ git stash apply stash@{0}           

撤銷修改

撤銷本地修改

# 移除緩存區的所有檔案(i.e. 撤銷上次git add)
$ git reset HEAD

# 将HEAD重置到上一次送出的版本,并将之後的修改标記為未添加到緩存區的修改
$ git reset <commit>

# 将HEAD重置到上一次送出的版本,并保留未送出的本地修改
$ git reset --keep <commit>

# 放棄工作目錄下的所有修改
$ git reset --hard HEAD

# 将HEAD重置到指定的版本,并抛棄該版本之後的所有修改
$ git reset --hard <commit-hash>

# 用遠端分支強制覆寫本地分支
$ git reset --hard <remote/branch> e.g., upstream/master, origin/my-feature

# 放棄某個檔案的所有本地修改
$ git checkout HEAD <file>           
删除添加

.gitignore

檔案前錯誤送出的檔案
$ git rm -r --cached .
$ git add .
$ git commit -m "remove xyz file"           

撤銷遠端修改

建立一個新的送出,并復原到指定版本

$ git revert <commit-hash>           

徹底删除指定版本

# 執行下面指令後,commit-hash 送出後的記錄都會被徹底删除,使用需謹慎
$ git reset --hard <commit-hash>
$ git push -f           

更新與推送

更新

# 下載下傳遠端端版本,但不合并到HEAD中
$ git fetch <remote>

# 将遠端端版本合并到本地版本中
$ git pull origin master

# 以rebase方式将遠端分支與本地合并
$ git pull --rebase <remote> <branch>           

推送

# 将本地版本推送到遠端端
$ git push remote <remote> <branch>

# 删除遠端端分支
$ git push <remote> :<branch> (since Git v1.5.0)
$ git push <remote> --delete <branch> (since Git v1.7.0)

# 釋出标簽
$ git push --tags           

檢視資訊

顯示工作路徑下已修改的檔案

$ git status           

顯示與上次送出版本檔案的不同

$ git diff           

顯示送出曆史

# 從最新送出開始,顯示所有的送出記錄(顯示hash, 作者資訊,送出的标題和時間)
$ git log

# 顯示某個使用者的所有送出
$ git log --author="username"

# 顯示某個檔案的所有修改
$ git log -p <file>           

顯示搜尋内容

# 從目前目錄的所有檔案中查找文本内容
$ git grep "Hello"

# 在某一版本中搜尋文本
$ git grep "Hello" v2.5           

分支與标簽

增删查分支

# 列出所有的分支
$ git branch

# 列出所有的遠端分支
$ git branch -r

# 基于目前分支建立新分支
$ git branch <new-branch>

# 基于遠端分支建立新的可追溯的分支
$ git branch --track <new-branch> <remote-branch>

# 删除本地分支
$ git branch -d <branch>

# 強制删除本地分支,将會丢失未合并的修改
$ git branch -D <branch>           

切換分支

# 切換分支
$ git checkout <branch>

# 建立并切換到新分支
$ git checkout -b <branch>           

标簽

# 給目前版本打标簽
$ git tag <tag-name>

# 給目前版本打标簽并附加消息
$ git tag -a <tag-name>           

合并與重置

merge 與 rebase 雖然是 git 常用功能,但是強烈建議不要使用 git 指令來完成這項工作。

因為如果出現代碼沖突,在沒有代碼比對工具的情況下,實在太艱難了。

你可以考慮使用各種 Git GUI 工具。

合并

# 将分支合并到目前HEAD中
$ git merge <branch>           

重置

# 将目前HEAD版本重置到分支中,請勿重置已釋出的送出
$ git rebase <branch>           

Github

Github 作為最著名的代碼開源協作社群,在程式員圈想必無人不知,無人不曉。

這裡不贅述 Github 的用法,确實有不會用的新手同學,可以參考官方教程:

https://guides.github.com/

clone 方式

Git 支援三種協定:HTTPS / SSH / GIT

而 Github 上支援 HTTPS 和 SSH。

HTTPS 這種方式要求你每次 push 時都要輸入使用者名、密碼,有些繁瑣。

而 SSH 要求你本地生成證書,然後在你的 Github 賬戶中注冊。第一次配置麻煩是麻煩了點,但是以後就免去了每次 push 需要輸入使用者名、密碼的繁瑣。

分布式版本控制系統 Git 教程

以下介紹以下,如何生成證書,以及在 Github 中注冊。

生成 SSH 公鑰

如前所述,許多 Git 伺服器都使用 SSH 公鑰進行認證。 為了向 Git 伺服器提供 SSH 公鑰,如果某系統使用者尚未擁有密鑰,必須事先為其生成一份。 這個過程在所有作業系統上都是相似的。 首先,你需要确認自己是否已經擁有密鑰。 預設情況下,使用者的 SSH 密鑰存儲在其 

~/.ssh

 目錄下。 進入該目錄并列出其中内容,你便可以快速确認自己是否已擁有密鑰:

$ cd ~/.ssh
$ ls
authorized_keys2  id_dsa       known_hosts
config            id_dsa.pub           

我們需要尋找一對以 

id_dsa

id_rsa

 命名的檔案,其中一個帶有 

.pub

 擴充名。 

.pub

 檔案是你的公鑰,另一個則是私鑰。 如果找不到這樣的檔案(或者根本沒有 

.ssh

 目錄),你可以通過運作 

ssh-keygen

 程式來建立它們。在 Linux/Mac 系統中,

ssh-keygen

 随 SSH 軟體包提供;在 Windows 上,該程式包含于 MSysGit 軟體包中。

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/schacon/.ssh/id_rsa):
Created directory '/home/schacon/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/schacon/.ssh/id_rsa.
Your public key has been saved in /home/schacon/.ssh/id_rsa.pub.
The key fingerprint is:
d0:82:24:8e:d7:f1:bb:9b:33:53:96:93:49:da:9b:e3 [email protected]           

首先 

ssh-keygen

 會确認密鑰的存儲位置(預設是 

.ssh/id_rsa

),然後它會要求你輸入兩次密鑰密碼。如果你不想在使用密鑰時輸入密碼,将其留白即可。

現在,進行了上述操作的使用者需要将各自的公鑰發送給任意一個 Git 伺服器管理者(假設伺服器正在使用基于公鑰的 SSH 驗證設定)。 他們所要做的就是複制各自的 

.pub

 檔案内容,并将其通過郵件發送。 公鑰看起來是這樣的:

$ cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU
GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3
Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA
t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En
mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx
NrRFi9wrf+M7Q== [email protected]           

在你的 Github 賬戶中,依次點選 Settings > SSH and GPG keys > New SSH key

然後,将上面生成的公鑰内容粘貼到

Key

編輯框并儲存。至此大功告成。

後面,你在克隆你的 Github 項目時使用 SSH 方式即可。

分布式版本控制系統 Git 教程

如果覺得我的講解還不夠細緻,可以參考:

https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/

小結

最後,放一張我總結的腦圖總結一下以上的知識點。

分布式版本控制系統 Git 教程

資料

git 官網

|

git 官方 Github 廖雪峰的 git 教程 git-cheat-sheet github-cheat-sheet Github gitignore 模闆

繼續閱讀