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

簡介

Git 是什么?

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

什么是版本控制?

版本控制是一種記錄一個或若干文件內容變化,以便將來查閱特定版本修訂情況的系統。

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

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

集中化的版本控制系統,諸如 CVS,Subversion 等,都有一個單一的集中管理的服務器,保存所有文件的修訂版本,而協同工作的人們都通過客戶端連到這臺服務器,取出最新的文件或者提交更新。

這么做最顯而易見的缺點是中央服務器的單點故障。如果宕機一小時,那么在這一小時內,誰都無法提交更新,也就無法協同工作。要是中央服務器的磁盤發生故障,碰巧沒做備份,或者備份不夠及時,就會有丟失數據的風險。最壞的情況是徹底丟失整個項目的所有歷史更改記錄。

img

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

img

為什么使用 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)

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

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

git-theory.png

安裝

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

Git 官方下載地址下載 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 johndoe@example.com

再次強調,如果使用了 --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 中比較常用的命令行場景。

git-cheat-sheet.png

創建

克隆一個已創建的倉庫

# 通過 SSH
$ git clone ssh://user@domain.com/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 需要輸入用戶名、密碼的繁瑣。

image.png

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

生成 SSH 公鑰

如前所述,許多 Git 服務器都使用 SSH 公鑰進行認證。 為了向 Git 服務器提供 SSH 公鑰,如果某系統用戶尚未擁有密鑰,必須事先為其生成一份。 這個過程在所有操作系統上都是相似的。 首先,你需要確認自己是否已經擁有密鑰。 默認情況下,用戶的 SSH 密鑰存儲在其 ~/.ssh 目錄下。 進入該目錄并列出其中內容,你便可以快速確認自己是否已擁有密鑰:

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

我們需要尋找一對以 id_dsaid_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 schacon@mylaptop.local

首先 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== schacon@mylaptop.local

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

然后,將上面生成的公鑰內容粘貼到 Key 編輯框并保存。至此大功告成。

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

The key field

如果覺得我的講解還不夠細致,可以參考:https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/

小結

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

Git.png

資料

git 官網 | git 官方 Github

廖雪峰的 git 教程

git-cheat-sheet

github-cheat-sheet

Github gitignore 模板

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,732評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,214評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,781評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,588評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,315評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,699評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,698評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,882評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,441評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,189評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,388評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,933評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,613評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,023評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,310評論 1 293
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,112評論 3 398
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,334評論 2 377

推薦閱讀更多精彩內容

  • Git 與 SVN 區別 Git不僅僅是個版本控制系統,它也是個內容管理系統(CMS),工作管理系統等。如果你是一...
    心至靜行至遠閱讀 713評論 0 5
  • 張愛玲曾說,“見了他,她變得很低很低,低到塵埃里。但她心里是歡喜的,從塵埃里開出花來。”這大概是對單戀者最好的詮釋...
    木安m閱讀 787評論 0 5
  • 我從來沒有在煙癮來臨的那一刻,告訴自己冷靜一下,等一等就好了,或者說去戒煙吧看些戒煙的方法。 我的第一反應就是買煙...
    戒煙的男人閱讀 116評論 0 0
  • 三月他像一個蘇醒的頑童在最后一天借著風雨嬉戲起來沒有春雷的助力春風斜雨,久久的交織成煙雨如畫 天空灰暗,風吹云也不...
    指尖芳華閱讀 303評論 12 12