簡介
Git 是什麼?
Git 是一個開源的分布式版本控制系統。
什麼是版本控制?
版本控制是一種記錄一個或若幹檔案内容變化,以便将來查閱特定版本修訂情況的系統。
什麼是分布式版本控制系統?
介紹分布式版本控制系統前,有必要先了解一下傳統的集中式版本控制系統。
集中化的版本控制系統,諸如 CVS,Subversion 等,都有一個單一的集中管理的伺服器,儲存所有檔案的修訂版本,而協同工作的人們都通過用戶端連到這台伺服器,取出最新的檔案或者送出更新。
這麼做最顯而易見的缺點是中央伺服器的單點故障。如果當機一小時,那麼在這一小時内,誰都無法送出更新,也就無法協同工作。要是中央伺服器的磁盤發生故障,碰巧沒做備份,或者備份不夠及時,就會有丢失資料的風險。最壞的情況是徹底丢失整個項目的所有曆史更改記錄。

分布式版本控制系統的用戶端并不隻提取最新版本的檔案快照,而是把代碼倉庫完整地鏡像下來。這麼一來,任何一處協同工作用的伺服器發生故障,事後都可以用任何一個鏡像出來的本地倉庫恢複。因為每一次的提取操作,實際上都是一次對代碼倉庫的完整備份。
為什麼使用 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 外觀和行為的配置變量。 這些變量存儲在三個不同的位置:
-
檔案: 包含系統上每一個使用者及他們倉庫的通用配置。 如果使用帶有/etc/gitconfig
選項的--system
時,它會從此檔案讀寫配置變量。git config
-
或~/.gitconfig
檔案:隻針對目前使用者。 可以傳遞~/.config/git/config
選項讓 Git 讀寫此檔案。--global
- 目前使用倉庫的 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
檔案前錯誤送出的檔案
.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 需要輸入使用者名、密碼的繁瑣。
以下介紹以下,如何生成證書,以及在 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 方式即可。
如果覺得我的講解還不夠細緻,可以參考:
https://help.github.com/articles/adding-a-new-ssh-key-to-your-github-account/小結
最後,放一張我總結的腦圖總結一下以上的知識點。
資料
git 官網|
git 官方 Github 廖雪峰的 git 教程 git-cheat-sheet github-cheat-sheet Github gitignore 模闆