分佈式版本控制系統與集中式版本控制系統有何不一樣呢?首先,分佈式版本控制系統根本沒有「中央服務器」,每一個人的電腦上都是一個完整的版本庫,這樣,你工做的時候,就不須要聯網了,由於版本庫就在你本身的電腦上。既然每一個人電腦上都有一個完整的版本庫,那多我的如何協做呢?比方說你在本身電腦上改了文件A,你的同事也在他的電腦上改了文件A,這時,大家倆之間只需把各自的修改推送給對方,就能夠互相看到對方的修改了。git
和集中式版本控制系統相比,分佈式版本控制系統的安全性要高不少,由於每一個人電腦裏都有完整的版本庫,某一我的的電腦壞掉了沒關係,隨便從其餘人那裏複製一個就能夠了。而集中式版本控制系統的中央服務器要是出了問題,全部人都無法幹活了。github
在實際使用分佈式版本控制系統的時候,其實不多在兩人之間的電腦上推送版本庫的修改,由於可能大家倆不在一個局域網內,兩臺電腦互相訪問不了,也可能今天你的同事病了,他的電腦壓根沒有開機。所以,分佈式版本控制系統一般也有一臺充當「中央服務器」的電腦,但這個服務器的做用僅僅是用來方便「交換」你們的修改,沒有它你們也同樣幹活,只是交換修改不方便而已。數據庫
Windows下要使用不少Linux/Unix的工具時,須要Cygwin這樣的模擬環境,Git也同樣。Cygwin的安裝和配置都比較複雜,就不建議你折騰了。不過,有高人已經把模擬環境和Git都打包好了,名叫msysgit,只須要下載一個單獨的exe安裝程序,其餘什麼也不用裝,絕對好用。安全
msysgit是Windows版的Git,從http://msysgit.github.io/下載,而後按默認選項安裝便可。服務器
安裝完成後,在開始菜單裏找到「Git」->「Git Bash」,蹦出一個相似命令行窗口的東西,就說明Git安裝成功!ssh
安裝完成後,還須要最後一步設置,在命令行輸入:編輯器
$ git config --global user.name "Your Name" $ git config --global user.email "email@example.com"
由於Git是分佈式版本控制系統,因此,每一個機器都必須自報家門:你的名字和Email地址。你也許會擔憂,若是有人故意冒充別人怎麼辦?這個沒必要擔憂,首先咱們相信你們都是善良無知的羣衆,其次,真的有冒充的也是有辦法可查的。分佈式
注意git config
命令的--global
參數,用了這個參數,表示你這臺機器上全部的Git倉庫都會使用這個配置,固然也能夠對某個倉庫指定不一樣的用戶名和Email地址工具
切換到相應的目錄 而後執行 fetch
$ git init
瞬間Git就把倉庫建好了,並且告訴你是一個空的倉庫(empty Git repository),細心的讀者能夠發現當前目錄下多了一個.git
的目錄,這個目錄是Git來跟蹤管理版本庫的,沒事千萬不要手動修改這個目錄裏面的文件,否則改亂了,就把Git倉庫給破壞了。
初始化一個Git倉庫,使用git init
命令。
添加文件到Git倉庫,分兩步:
第一步,使用命令git add <file>
,注意,可反覆屢次使用,添加多個文件;
第二步,使用命令git commit
,完成。
要隨時掌握工做區的狀態,使用git status
命令。
若是git status
告訴你有文件被修改過,用git diff
能夠查看修改內容。
HEAD
指向的版本就是當前版本,所以,Git容許咱們在版本的歷史之間穿梭,使用命令git reset --hard commit_id
。
穿梭前,用git log
能夠查看提交歷史,以便肯定要回退到哪一個版本。
要重返將來,用git reflog
查看命令歷史,以便肯定要回到將來的哪一個版本。
Git和其餘版本控制系統如SVN的一個不一樣之處就是有暫存區的概念。
先來看名詞解釋。
工做區(Working Directory):就是你在電腦裏能看到的目錄,好比個人learngit
文件夾就是一個工做區:
版本庫(Repository):工做區有一個隱藏目錄.git
,這個不算工做區,而是Git的版本庫。
Git的版本庫裏存了不少東西,其中最重要的就是稱爲stage(或者叫index)的暫存區,還有Git爲咱們自動建立的第一個分支master
,以及指向master
的一個指針叫HEAD
。
分支和HEAD
的概念咱們之後再講。
前面講了咱們把文件往Git版本庫裏添加的時候,是分兩步執行的:
第一步是用git add
把文件添加進去,實際上就是把文件修改添加到暫存區;
第二步是用git commit
提交更改,實際上就是把暫存區的全部內容提交到當前分支。
由於咱們建立Git版本庫時,Git自動爲咱們建立了惟一一個master
分支,因此,如今,git commit
就是往master
分支上提交更改。
你能夠簡單理解爲,須要提交的文件修改統統放到暫存區,而後,一次性提交暫存區的全部修改。
俗話說,實踐出真知。如今,咱們再練習一遍,先對readme.txt
作個修改,好比加上一行內容:
Git is a distributed version control system. Git is free software distributed under the GPL. Git has a mutable index called stage.
而後,在工做區新增一個LICENSE
文本文件(內容隨便寫)。
先用git status
查看一下狀態:
$ git status # On branch master # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: readme.txt # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # LICENSE no changes added to commit (use "git add" and/or "git commit -a")
Git很是清楚地告訴咱們,readme.txt
被修改了,而LICENSE
還歷來沒有被添加過,因此它的狀態是Untracked
。
如今,使用兩次命令git add
,把readme.txt
和LICENSE
都添加後,用git status
再查看一下:
$ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # new file: LICENSE # modified: readme.txt #
如今,暫存區的狀態就變成這樣了:
因此,git add
命令實際上就是把要提交的全部修改放到暫存區(Stage),而後,執行git commit
就能夠一次性把暫存區的全部修改提交到分支。
$ git commit -m "understand how stage works" [master 27c9860] understand how stage works 2 files changed, 675 insertions(+) create mode 100644 LICENSE
一旦提交後,若是你又沒有對工做區作任何修改,那麼工做區就是「乾淨」的:
$ git status # On branch master nothing to commit (working directory clean)
如今版本庫變成了這樣,暫存區就沒有任何內容了:
git add 是把工做區的改動推送到暫存區
git commit 是把暫存區的內容提交到版本庫
場景1:當你改亂了工做區某個文件的內容,想直接丟棄工做區的修改時,用命令git checkout -- file
。
場景2:當你不但改亂了工做區某個文件的內容,還添加到了暫存區時,想丟棄修改,分兩步,第一步用命令git reset HEAD file
,就回到了場景1,第二步按場景1操做。
場景3:已經提交了不合適的修改到版本庫時,想要撤銷本次提交,參考版本回退一節,不過前提是沒有推送到遠程庫。
刪錯了,能夠很輕鬆地把誤刪的文件恢復到最新版本,由於版本庫裏還有呢:
$ git checkout -- test.txt
git checkout
實際上是用版本庫裏的版本替換工做區的版本,不管工做區是修改仍是刪除,均可以「一鍵還原」。
命令git rm
用於刪除一個文件。若是一個文件已經被提交到版本庫,那麼你永遠不用擔憂誤刪,可是要當心,你只能恢復文件到最新版本,你會丟失最近一次提交後你修改的內容。
註冊github賬號,並建立倉庫
第1步:建立SSH Key。在用戶主目錄下,看看有沒有.ssh目錄,若是有,再看看這個目錄下有沒有id_rsa
和id_rsa.pub
這兩個文件,若是已經有了,可直接跳到下一步。若是沒有,打開Shell(Windows下打開Git Bash),建立SSH Key:
$ ssh-keygen -t rsa -C "youremail@example.com"
你須要把郵件地址換成你本身的郵件地址,而後一路回車,使用默認值便可,因爲這個Key也不是用於軍事目的,因此也無需設置密碼。
若是一切順利的話,能夠在用戶主目錄裏找到.ssh
目錄,裏面有id_rsa
和id_rsa.pub
兩個文件,這兩個就是SSH Key的祕鑰對,id_rsa
是私鑰,不能泄露出去,id_rsa.pub
是公鑰,能夠放心地告訴任何人。
第2步:登錄GitHub,打開「Account settings」,「SSH Keys」頁面:
而後,點「Add SSH Key」,填上任意Title,在Key文本框裏粘貼id_rsa.pub
文件的內容
有https協議和git也就是ssh協議,https協議在每次push時都須要數據賬號和密碼,略麻煩,能夠稍微控制push的次數。
本地的learngit
倉庫下運行命令:
$ git remote add origin git@github.com:mh335776191/learngit.git
添加後,遠程庫的名字就是origin
,這是Git默認的叫法,也能夠改爲別的,可是origin
這個名字一看就知道是遠程庫。
originorigin
把本地庫的內容推送到遠程,用git push
命令,其實是把當前分支master
推送到遠程。
因爲遠程庫是空的,咱們第一次推送master
分支時,加上了-u
參數,Git不但會把本地的master
分支內容推送的遠程新的master
分支,還會把本地的master
分支和遠程的master
分支關聯起來,在之後的推送或者拉取時就能夠簡化命令。
從如今起,只要本地做了提交,就能夠經過命令:
要克隆一個倉庫,首先必須知道倉庫的地址,而後使用命令克隆。$ git push origin mastergit clone
分支
Git鼓勵大量使用分支:
查看分支:git branch
建立分支:git branch <name>
切換分支:git checkout <name>
建立+切換分支:git checkout -b <name>
合併某分支到當前分支:git merge <name>
刪除分支:git branch -d <name>
當Git沒法自動合併分支時,就必須首先解決衝突。解決衝突後,再提交,合併完成。
用git log --graph
命令能夠看到分支合併圖。
在實際開發中,咱們應該按照幾個基本原則進行分支管理:
首先,master
分支應該是很是穩定的,也就是僅用來發布新版本,平時不能在上面幹活;
那在哪幹活呢?幹活都在dev
分支上,也就是說,dev
分支是不穩定的,到某個時候,好比1.0版本發佈時,再把dev
分支合併到master
上,在master
分支發佈1.0版本;
你和你的小夥伴們每一個人都在dev
分支上幹活,每一個人都有本身的分支,時不時地往dev
分支上合併就能夠了。
因此,團隊合做的分支看起來就像這樣:
Git分支十分強大,在團隊開發中應該充分應用。
合併分支時,加上--no-ff
參數就能夠用普通模式合併,合併後的歷史有分支,能看出來曾經作過合併,而fast forward
合併就看不出來曾經作過合併。
修復bug時,咱們會經過建立新的bug分支進行修復,而後合併,最後刪除;
當手頭工做沒有完成時,先把工做現場git stash
一下,而後去修復bug,修復後,再git stash pop
,回到工做現場
若是要丟棄一個沒有被合併過的分支,能夠經過git branch -D <name>
強行刪除。
多人協做的工做模式一般是這樣:
首先,能夠試圖用git push origin branch-name
推送本身的修改;
若是推送失敗,則由於遠程分支比你的本地更新,須要先用git pull
試圖合併;
若是合併有衝突,則解決衝突,並在本地提交;
沒有衝突或者解決掉衝突後,再用git push origin branch-name
推送就能成功!
若是git pull
提示「no tracking information」,則說明本地分支和遠程分支的連接關係沒有建立,用命令git branch --set-upstream branch-name origin/branch-name
。
這就是多人協做的工做模式,一旦熟悉了,就很是簡單。
查看遠程庫信息,使用git remote -v
;
本地新建的分支若是不推送到遠程,對其餘人就是不可見的;
從本地推送分支,使用git push origin branch-name
,若是推送失敗,先用git pull
抓取遠程的新提交;
在本地建立和遠程分支對應的分支,使用git checkout -b branch-name origin/branch-name
,本地和遠程分支的名稱最好一致;
創建本地分支和遠程分支的關聯,使用git branch --set-upstream branch-name origin/branch-name
;
從遠程抓取分支,使用git pull
,若是有衝突,要先處理衝突。
發佈一個版本時,咱們一般先在版本庫中打一個標籤,這樣,就惟一肯定了打標籤時刻的版本。未來不管何時,取某個標籤的版本,就是把那個打標籤的時刻的歷史版本取出來。因此,標籤也是版本庫的一個快照。
Git的標籤雖然是版本庫的快照,但其實它就是指向某個commit的指針(跟分支很像對不對?可是分支能夠移動,標籤不能移動),因此,建立和刪除標籤都是瞬間完成的。
命令git tag <name>
用於新建一個標籤,默認爲HEAD
,也能夠指定一個commit id;
git tag -a <tagname> -m "blablabla..."
能夠指定標籤信息;
git tag -s <tagname> -m "blablabla..."
能夠用PGP簽名標籤;
命令git tag
能夠查看全部標籤。
刪除標籤
命令git push origin <tagname>
能夠推送一個本地標籤;
命令git push origin --tags
能夠推送所有未推送過的本地標籤;
命令git tag -d <tagname>
能夠刪除一個本地標籤;
命令git push origin :refs/tags/<tagname>
能夠刪除一個遠程標籤。
有些時候,你必須把某些文件放到Git工做目錄中,但又不能提交它們,好比保存了數據庫密碼的配置文件啦,等等,每次git status
都會顯示「Untracked files ...」,有強迫症的童鞋內心確定不爽。
好在Git考慮到了你們的感覺,這個問題解決起來也很簡單,在Git工做區的根目錄下建立一個特殊的.gitignore
文件,而後把要忽略的文件名填進去,Git就會自動忽略這些文件。
不須要從頭寫.gitignore
文件,GitHub已經爲咱們準備了各類配置文件,只須要組合一下就可使用了。全部配置文件能夠直接在線瀏覽:https://github.com/github/gitignore
忽略文件的原則是:
.class
文件;使用Windows的童鞋注意了,若是你在資源管理器裏新建一個.gitignore
文件,它會很是弱智地提示你必須輸入文件名,可是在文本編輯器裏「保存」或者「另存爲」就能夠把文件保存爲.gitignore
了。
忽略某些文件時,須要編寫.gitignore
;
.gitignore
文件自己要放到版本庫裏,而且能夠對.gitignore
作版本管理!
有沒有常常敲錯命令?好比git status
?status
這個單詞真心很差記。
若是敲git st
就表示git status
那就簡單多了,固然這種偷懶的辦法咱們是極力同意的。
咱們只須要敲一行命令,告訴Git,之後st
就表示status
:
$ git config --global alias.st status
好了,如今敲git st
看看效果。
固然還有別的命令能夠簡寫,不少人都用co
表示checkout
,ci
表示commit
,br
表示branch
:
$ git config --global alias.co checkout $ git config --global alias.ci commit $ git config --global alias.br branch
之後提交就能夠簡寫成:
$ git ci -m "bala bala bala..."
--global
參數是全局參數,也就是這些命令在這臺電腦的全部Git倉庫下都有用。
配置Git的時候,加上--global
是針對當前用戶起做用的,若是不加,那隻針對當前的倉庫起做用。
配置文件放哪了?每一個倉庫的Git配置文件都放在.git/config
文件中:
$ cat .git/config [core] repositoryformatversion = 0 filemode = true bare = false logallrefupdates = true ignorecase = true precomposeunicode = true [remote "origin"] url = git@github.com:michaelliao/learngit.git fetch = +refs/heads/*:refs/remotes/origin/* [branch "master"] remote = origin merge = refs/heads/master [alias] last = log -1
別名就在[alias]
後面,要刪除別名,直接把對應的行刪掉便可。
而當前用戶的Git配置文件放在用戶主目錄下的一個隱藏文件.gitconfig
中
配置別名也能夠直接修改這個文件,若是改錯了,能夠刪掉文件從新經過命令配置。