git是一種分佈式版本控制系統。而與之相對就是集中式版本控制系統。集中式版本控制系統的表明是CVS和Subversion,其版本庫集中存放在中央服務器上,幹活的時候,要先從中央服務器取得最新的版本,而後開始幹活,幹完活了,再把本身的活推送給中央服務器。每一個開發者之間沒法進行版本的傳遞。因此集中式版本控制系統最大的毛病就是必須聯網才能工做。html
而分佈式版本控制系統根本沒有「中央服務器」,每一個人的電腦上都是一個完整的版本庫,這樣,你工做的時候,就不須要聯網了,由於版本庫就在你本身的電腦上,因此能夠在本地進行提交。既然每一個人電腦上都有一個完整的版本庫,那多我的如何協做呢?對於分佈式版本庫系統,每一個開發者之間是能夠直接進行版本的傳遞的,比方說你在本身電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時,大家倆之間只需把各自的修改推送給對方,就能夠互相看到對方的修改了。可是在實際開發中,爲了方便版本的傳遞(交換修改),一般也會有一箇中央服務,這個中央服務器是一個裸版本庫,僅僅是爲了方便版本傳遞,沒有這個中央服務器也能正常工做,只是沒有這麼方便而已。git
① 初始化,建立版本庫
要想使用git,那麼咱們須要建立一個版本庫,用於存儲該項目自己及其歷史。爲此,咱們須要建立一個項目根目錄,如first-steps,而後進入到項目根目錄下,而後在該項目根目錄下執行git init
,init命令會在當前目錄下建立一個名爲.git的隱藏目錄,並在其中建立一個版本庫,這個帶版本庫的項目目錄,咱們一般稱爲工做區。服務器
> cd /path/to/first-steps > git init Initialized empty Git repository in /path/to/first-steps/.git/
② 首次提交
版本庫建立好以後,就能夠進行提交了,提交分爲兩步,第一,先使用add命令將須要提交的文件添加到暫存區;第二,而後使用commit命令將暫存區中的內容提交到版本庫中。提交完成後,git會給該提交賦予一個散列值,以下面的c12ac1c,用於標識此次新提交。分佈式
> git add foo.txt bar.txt > git commit --message "Sample project imported." [master (root-commit) c12ac1c] Sample project imported. 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 bar.txt create mode 100644 foo.txt
③ 檢查狀態
如今咱們能夠修改一下foo.txt內容而且刪除bar.txt,而後天就一個index.html文件,而後經過git status
命令,能夠查看到該項目從上次提交以來全部發生的修改。fetch
> git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: bar.txt modified: foo.txt Untracked files: (use "git add <file>..." to include in what will be committed) index.html no changes added to commit (use "git add" and/or "git commit -a")
④ 提交修改
工做區有了修改後,一樣也是須要使用add和commit進行提交。版本控制
> git add foo.txt index.html > git rm bar.txt rm 'bar.txt' > git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: bar.txt modified: foo.txt new file: index.html > git commit --message "Some changes" [master f1c648a] Some changes 3 files changed, 13 insertions(+) delete mode 100644 bar.txt create mode 100644 index.html
能夠看到,新的提交也有一個對應的散列值(f1c648a),這裏使用到了git rm
命令,其與rm命令的區別就是,rm僅僅是刪除工做區的文件,並無從暫存區中刪除;而git rm 是刪除工做區的文件同時將修改添加到暫存區中。 因此,git rm bar.txt
等價於 rm bar.txt
和 git add bar.txt
,就是多了一個將工做區修改添加到暫存區的操做。code
⑤ 顯示歷史
咱們能夠經過git log
來查看項目的提交歷史,全部的提交都會按時間順序被降序排列出來。htm
> git log commit f1c648a033ad509f5ffe08f96152432be1c12c7b (**HEAD ->** **master**) Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> Date: Tue Dec 31 11:01:40 2019 +0800 Some changes commit c12ac1ced34a57104f29f4bceea13f88e2c3cbcf Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> Date: Tue Dec 31 10:32:32 2019 +0800 Sample project imported.
① 克隆版本庫
git提供了一個clone命令,能夠將某個版本庫克隆到指定的目錄下面。其用法爲git clone 版本庫地址 目標版本庫所在目錄
,能夠在任何目錄下執行clone命令,若是沒有指定目標版本庫所在的目錄,那麼是直接將版本庫克隆到當前目錄下面,而且是將.git目錄和工做區內容及其所在的目錄都克隆過去,即整個項目克隆過去,可是若是指定了目標版本庫所在的目錄,那麼克隆的僅僅是.git目錄和工做區內容,即以目標版本庫所在目錄做爲項目根目錄。ci
> mkdir /path/to/first-steps-clone > git clone /path/to/first-steps /path/to/first-steps-clone Cloning into first-steps-clone... done.
② 從源版本庫中取回修改
如今咱們分別在first-steps 和 first-steps-clone中進行一次提交,如:開發
// first-steps修改foo.txt的內容 > cd /path/to/first-steps > git add foo.txt > git commit --message 'A change in the original'
// first-steps-clone修改index.html的內容 > cd /path/to/first-steps-clone > git add index.html > git commit --message 'A change in the clone'
如今兩個版本庫中都做了相應的修改,就像兩個開發者分別在開發,這個時候就須要同步對方的修改,對於clone版本庫(first-steps-clone)而言,由於克隆的時候,源版本庫的路徑已經存儲在了克隆版本庫中,因此能夠直接用git pull
命令取回源版本庫的修改。
這裏須要注意的是,雖然源版本庫修改的是foo.txt文件,克隆版本庫修改的是index.html文件,可是執行git pull
命令後並不能自動合併,由於執行git pull
命令的時候,克隆版本庫中對index.html進行了修改而且提交到了版本庫中,而執行git pull
命令以後,獲取到了修改foo.txt的提交,與當前修改index.html的提交出現分叉了,因此須要把源版本庫中對foo.txt的修改和克隆版本庫中對index.html的修改進行一次手動合併merge。由於同一個分支中不能出現分叉,必須將其合併成一個。可是若是執行git pull
命令的時候,克隆版本庫中沒有進行任何提交,那麼獲取到foo.txt的提交後就沒有出現分叉,因此能夠自動合併。
> git log --graph * commit 3f78c7f4b0c6c3bd9e8ee5b15d061cb9018c9f44 (**HEAD ->** **master**) |\ Merge: f324964 b40f4a0 | | Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | | Date: Tue Dec 31 12:43:05 2019 +0800 | | | | Merge branch 'master' of /Users/banma-798/Downloads/first-steps | | | * commit b40f4a0d0e4344f49afaad609659046014031fbc (**origin/master**, **origin/HEAD**) | | Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | | Date: Tue Dec 31 12:25:34 2019 +0800 | | | | A change in the original | | * | commit f324964540fbc031fbbea42d3fc853c5722a4236 |/ Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | Date: Tue Dec 31 12:42:55 2019 +0800 | | A change in the clone | * commit f1c648a033ad509f5ffe08f96152432be1c12c7b | Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> | Date: Tue Dec 31 11:01:40 2019 +0800 | | Some changes | * commit c12ac1ced34a57104f29f4bceea13f88e2c3cbcf Author: hongbiao.lhb <hongbiao.lhb@alibaba-inc.com> Date: Tue Dec 31 10:32:32 2019 +0800 Sample project imported.
能夠看到,分支出現了分叉,而後又收到merge合併爲了一個分支。總共有5次提交,最初的2次提交+克隆版本庫的提交+源版本庫的提交+手動merge的提交。
③ 從任意版本庫中取回修改git pull
在沒有參數的狀況,只能在克隆版本庫中執行,去取回源版本庫的修改。而源版本庫中執行git pull是沒法從克隆版本庫獲取到克隆版本庫的修改的。
> cd /path/to/first-steps > git pull fatal: No remote repository specified. Please, specify either a URL or a remote name from which new revisions should be fetched.
可是能夠經過指定版本庫路徑和分支名的方式來從任何一個版本庫中取回修改,即git pull 版本庫路徑 分支名
,如:
> cd /path/to/first-steps > git pull /path/to/first-steps-clone master
① 克隆裸版本庫
所謂裸版本庫,就是一個不帶工做區的版本庫,僅僅用於開發者之間傳遞提交的一個匯聚點,能夠經過git clone --bare來建立一個裸的版本庫。
> git clone --bare /path/to/first-steps /path/to/first-steps-bare.git > Cloning into bare repository first-steps-bare.git... done.
② push推送修改到裸版本庫
爲何必需要建立一個裸版本庫呢?由於push命令只能將修改推送到裸版本庫中。用法爲git push 裸版本庫路徑 分支
> git push /path/to/first-steps-bare.git master
這裏須要注意的是,若是另外一個開發者在咱們以前已經作過一次push操做,那麼咱們再次執行push命令就會被拒絕推送,這個時候,咱們必須先把其餘人的提交pull過來而後才能接着push。
對於克隆版本庫而言,執行push和pull命令的時候,能夠直接用origin表明源版本庫,如:
> git push origin master > git pull origin master
因此能夠看到,若是本身的版本庫比目標版本庫的要落後,那麼是沒法push推送本身的修改到目標版本庫的,因此在實際開發中,若是咱們提交了一個版本,可是忽然發現該次提交存在重大bug,咱們沒法經過在本地直接回退到上一個版本而後在push推送到目標版本庫的方式去取消上次提交,由於一旦回退版本,那麼你的版本庫就比目標版本庫落後了,因此push推送失敗。固然,咱們能夠經過帶上-f參數來強制提交上去,可是不建議這麼作。
// 強制推送修改到目標版本庫 > git push -f origin master