標籤:
看了廖雪峰寫的教程,由淺入深,花了三天的時間學完了,做一下學習筆記吧
Git簡介
Linus建立Linux之後為方便管理Linux代碼,自己用C寫了這個分布式版本控制系統。2008年的時候GitHub網站上線,為開源項目免費提供Git儲存。
集中式vs分布式:
集中式版本控制系統,版本庫存放在中央伺服器,每個人用的都是自己的電腦,用的時候先從伺服器上獲得新版本,工作完了再推送給中央伺服器。缺點是必須連網使用,效率低。
分布式版本控制系統,沒有中央伺服器,每個人的電腦都是一個完整的版本庫,工作的時候不需要連網,要想實現協作,每個人只需把各自修改的部分推送給對方。一般有一台電腦充當中央伺服器,僅僅是為了方便大家交換修改。分布式安全性更高。
安裝Git
Linux、Unix、Mac、Windows幾大平台均能運行Git,最常用Linux就只記錄Linux上的安裝了。
首先,嘗試在shell裡輸入git看看有沒有安裝:
在Ubuntu裡安裝很簡單,一條命令sudo apt-get install git
若在其他 Linux版本裡可以去Git官網下載原始碼,解壓後輸入:./config, make, sudo make install
安裝好之後,為本地git庫設定:
$ git config --global user.name "Your Name"
$ git config --global user.email "[email protected]"
建立版本庫
1、建立git庫
合適的地方建立一個空目錄,進入目錄後執行git init命令把這個目錄變成可以管理的倉庫;
$ mkdir git
$ cd git
$ git init
注意,倉庫建立好之後會產生一個隱藏的檔案夾.git,用來跟蹤管理版本,不能隨意修改
2、添加檔案到git庫
注意版本控制系統只能跟蹤文字檔的改動,沒法跟蹤二進位檔案的變化。
添加檔案分兩步:
第一步,使用命令git add 添加檔案到倉庫
第二部,使用命令git commit –m “XXX” 提交改動,引號內為說明,一般輸入改動記錄
查看庫狀態、修改檔案
假如對某個檔案進行修改,可以運行git status 命令查看狀態
上面顯示檔案修改過,但是沒有準備提交。
雖然git告訴我們test.txt檔案被修改了,但是沒有顯示具體修改了什麼內容,這個時候需要git diff命令查看
結果顯示在第二行添加了一句話。
在明確知道有哪些改動之後就可以提交到倉庫了,提交修改跟提交新檔案是同樣的操作:
git add test.txt
在執行第二部之前,再次運行git status看看當前倉庫的狀態:
發現有改動準備提交,下一步就可以放心的提交了:
git commit –m “add one line”
提交完之後可再次查看狀態:
總結:
?git status可以查看當前工作區的狀態
?如git status告訴你有檔案修改了,用git diff查看具體修改的內容,以決定是否提交修改
版本退回
在不斷對檔案進行修改後,然後不斷提交修改到版本庫裡,每次提交到git就像儲存了一個“快照”,在git裡這個快照被稱為commit,隨時都能恢複到最近的一個版本。
首先用git log命令查看記錄:
可以看見從最近到最遠的提交日誌,若嫌顯示太亂可以加上–pretty=oneline參數:
每次改動只在一行內顯示commit id(版本號碼)和改動內容。
好了,現在準備將test.txt檔案回退到上一個版本:
在git中HEAD表示目前的版本,上一個版本就是HEAD^,上上個版本就是HEAD^^,簡略寫法如當前往上100個版本寫成HEAD~100。
使用git reset –hard HEAD^命令就回退到了上一個版本:
可以看到回到了第一個版本,這個時候再用git log查看版本記錄:
發現之前的版本不見了,好比你從21世紀坐時光穿梭機來到了19世紀,想再回去21世紀已經回不去了,腫麼辦?
辦法還是有的,只要能找到之前版本的commit id(版本號碼)就可以,使用git reflog查看每一次的命令:
發現之前的版本號碼為afa4020,這時就可以再恢複到哪個版本:
註:版本號碼僅僅是前幾位,沒有寫全(全部的太長了0-0),git會根據前幾位自動去找
總結:
?HEAD 指向當前的版本號碼,git允許在不同版本之間穿梭,git reset –hard commit_id
?穿梭前,用git log查看記錄,以確定退回到哪個版本
?要重返未來,用git reflog查看曆史命令以確定未來的版本號碼
工作區和暫存區
工作區就是在電腦上能看見的目錄,比如之前建立的目錄git就是一個工作區;
版本庫,在工作區有一個隱藏的目錄.git,這個就是版本庫。
在版本庫中最重要的一部分是稱為stage的暫存區,還有自動建立的第一個分支master,以及指向mater的指標HEAD。
前幾節講到把檔案添加到版本庫分兩步執行:
第一步git add 實際就是將檔案添加到暫存區;
第二部git commit提交修改,就是將暫存區中的內容提交到當前分支,暫存區就會被清空。
管理修改
這一節還是為了進一步瞭解git工作機制。
舉個例子,我們對一個檔案進行一次修改,然後添加:git add filename
然後第二次對該檔案進行修改,不執行add命令,然後執行git commit -m “…”
我們會發現僅僅是提交了第一次修改,第二次修改並沒有提交。也就是說git管理的是修改,並不會對工作區的檔案進行修改。
撤銷修改
情況一:修改了檔案,但沒有add到暫存區,需要撤銷檔案的修改:git checkout – test.txt 或者 手動還原修改
情況二:修改檔案後add到了暫存區,又再次修改了檔案,需要撤銷第二次修改:git checkout – test.txt 相當於把暫存區的恢複到工作區,此時暫存區有第一次的修改需要commit提交到分支。
情況三:修改檔案後add到了暫存區,需要撤銷修改:git reset HEAD test.txt 將暫存區修改刪除,此時工作區還有修改沒撤銷,然後git checkout – test.txt 撤銷工作區的修改
情況四:修改後add並commit了,需要撤銷修改:git reset –hard HEAD^ 也就是版本退回
總結:一句話總結就是git checkout – 會使檔案回到最近一次git commit或者git add前檔案的狀態,這個地方有點繞,必須花時間才能弄明白的。。。。。
刪除檔案
在工作區刪除一個檔案rm test.txt ,這個時候工作區和版本庫就不一致了,git status會告訴你那些檔案刪除了,現在有兩個選擇:
一、確實是要從版本庫中刪除
git rm test.txt
git commit –m “remove test.txt”
二、恢複刪除的檔案:
git checkout – test.txt
遠程倉庫
我們可以自己搭建我們自己的git伺服器,現階段有一個神奇的網站GitHub提供git倉庫託管服務,所以只需要免費註冊一個GitHub帳號:開啟https://github.com/pricing進行註冊。
本地Git庫跟遠程GitHub倉庫之間傳輸是通過SSH加密的,所以需要一點設定:
第一步,建立SSH Key。在使用者主目錄下,看看有沒有.ssh目錄,如果有再看看目錄下有沒 沒有id_rsa和id_rsa.pub兩個檔案,若都有,可直接下一步;若沒有,開啟shell建立
$ ssh-keygen –t rsa –C “your email [email protected]***.com”
這時在主目錄下的.ssh目錄下就有id_rsa和id_rsa.pub兩個檔案,id_rsa是私密金鑰,id_rsa.pub是公開金鑰
第二步,登入Github,開啟設定,在左側SSH keys裡添加,點擊“New SSH key”,title任意填 ,在key文字框裡粘貼id_rsa.pub檔案的內容。
這時Github就能識別你的電腦,允許你推送修改。多個電腦可添加多個公開金鑰。
登入GitHub後右上方添加 new respository按鈕,建立一個新的倉庫。在respository name處填寫git,其他保持預設,就成功建立了一個新的git倉庫。目前,這個倉庫還是空的,首先我們把本地git庫關聯我們的遠程倉庫:
$ git remote add origin https://github.com/JasonLiu1991/git.git
千萬注意將JasonLiu1991替換成你的GitHub的賬戶名。
添加後,遠程庫的名字就是origin,這個是git預設的叫法,也可以改成別的
這個地方常用的命令:
git remote 不帶選項時,就是列出所有遠程主機:
git remote -v -v選項就是查看遠程主機的網址:
git remote show <主機名稱> 查看該主機的詳細資料
git remote add <主機名稱> <網址> 添加遠程主機
git remote rm <主機名稱> 刪除遠程主機
git remote rename <原主機名稱> <新主機名稱> 重新命名
下一步就是將本地庫的內容推送到遠程庫:
$ git push –u origin master
該命令的意思就是將本地的master分支推送到遠程origin主機上。
由於遠程庫是空的,第一次推送master分支時加上-u參數,Git不僅會將master分支推送到遠端master分支,還會將本地的master分支關聯遠端master分支,方便以後。
這時,在GitHub頁面上就看到了同步過來的內容,以後本地有修改提交了就可以通過命令:
$ git push origin master
至此,就擁有了完整的分布式版本庫。
git push命令詳解:
$ git push <遠程主機名稱> <本地分支名>:<遠程分支名>
如果省略遠程分支名,則表示將本地分支推送到與之存在“追蹤關係”的遠程分支,若遠程分支不存在就自動建立。git push origin master 就是將本地的master分支推送到origin主機的master分支。如果後者不存在,則會被建立。
如果省略本地分支名,則表示刪除指定的遠程分支,因為這等同於推送一個空的本地分支到遠程分支
$ git push origin :master
等同於
$ git push origin --delete master
註:
這裡還會有一個問題就是每次push的時候都需要輸入賬戶名密碼,有點麻煩,解決辦法:
在本地git庫的目錄下有一個.git目錄,.git裡有一個config檔案,
將url = https:// github.com/JasonLiu1991/git. git替換成:
url = https://[UserName]:[Password]@github.com/JasonLiu1991/git. git即可
從遠程庫複製
$ git clone <版本庫的網址> 該命令就會在本地產生一個目錄,與遠端版本庫同名
分支管理
在版本退回一節裡,每次提交Git都將他們串成一條時間軸,這條時間軸就是一個分支。目前只有一條時間軸,叫做主分支master。master指向提交,HEAD指向當前分支:
每次提交,master向前移動一步。
當我們建立分支,例如dev,git就建立了一個指標叫dev,建立時指向master相同的提交,HEAD指向dev,表示當前分支在dev上:
圖上可以看出,git建立一個分支就是增加了一個指標,移動了一下HEAD,檔案沒有變化。
從現在開始,對工作區的修改就是針對dev分支了,比如提交修改,就是dev向前移動一步:
假如在dev上的工作完成了,就可以把dev合并到master上,方法就是直接把master指標指向dev當前的提交:
合并完之後甚至可以刪除dev分支。
原理弄明白了就開始操作
首先,建立分支dev,並切換到分支dev
$ git checkout -b dev
參數-b表示建立並切換,相當於以下兩條命令:
$git branch dev 建立分支
$git checkout dev 切換到分支
$ git branch 查看當前分支,前面帶*號表示當前分支:
現在我們再提交修改就是發生在dev分支之上了,當然可以隨時切換:git branch master
切換回master分支之後,我們想把dev的工作成果合并到master:
$ git merge dev
git merge 命令用於合并指定分支到當前分支:
可以看到是Fast-forward,這是快速合并。
合并完成後就可以刪除dev分支了:
$ git branch –d dev
小結:
Git鼓勵大量使用分支:
查看分支:git branch
建立分支:git branch
切換分支:git checkout
建立+切換分支:git checkout -b
合并某分支到當前分支:git merge
刪除分支:git branch -d
解決衝突
合并的時候會遇到衝突,舉例:
建立一個分支feature1
$ git checkout –b feature1
修改檔案最後一行,加上ttttttt字元,並提交修改
切換回主分支,同樣修改檔案,在最後一行加上pppppppp字元,提交修改
現在兩個分支各自有不同的提交:
現在合并,會有衝突:
提示存在衝突,必須解決後才再提交修改
Git用<<<<<<<,=======,>>>>>>>標記出不同分支的內容,我們手動修改後就提交了
我們用git log --graph --pretty=oneline可以看到分支的合并情況:
分支管理原則
在前面介紹到的Fast forward模式,刪除分支後就會丟失分支資訊。
如果要強行禁用Fast forward模式,git會在merge時產生一個新的commit,這樣從分支曆史上就能看到分支資訊了。
命令:git merge --no-ff –m “******” dev
因為這樣合并是要建立新commit,所以要加上-m參數。這樣合并後就能用log查看分支曆史:git log --graph --pretty=oneline
不使用Fast forward模式,原理
分支策略:
在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面幹活;
那在哪幹活呢?幹活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本發布時,再把dev分支合并到master上,在master分支發布1.0版本;
你和你的小夥伴們每個人都在dev分支上幹活,每個人都有自己的分支,時不時地往dev分支上合并就可以了。
所以,團隊合作的分支看起來就像這樣:
Bug分支
軟體開發經常需要修複bug,在git中,每個bug都可以通過一個新的臨時分支開修複,修複後合并,然後將分支刪除。
好了,當接到任務修複一個代號101的bug任務,很自然的,想建立一個分支issue-101來修複它,但是,等等,當前在dev上進行的工作還沒完成不想提交,怎麼辦?
幸好git提供了一個stash功能,將工作現場暫時儲存起來,需要的時候再恢複回來繼續工作:
現在可以放心的來修複bug了,假如需要在master分支上修複這個bug,就從master建立分支:
等修複完之後,切換到master分支,完成合併,最後刪除issue-101分支就完成了。
Bug修複完了,是時候回到dev分支繼續工作了,現在就需要恢複之前儲存起來的工作區:
兩種方法:
首先git stash list命令查看一下:
方法一,git stash apply恢複,但是恢複後stash內容不刪除,需要用git stash drop來刪除
方法二,git stash pop,恢複的同時刪除
當然也可以多次stash,恢複的時候用git stash list查看,然後恢複指定的stash:
$ git stash apply [email protected]{0}
小結:
修複bug時,我們會通過建立新的bug分支進行修複,然後合并,最後刪除;
當手頭工作沒有完成時,先把工作現場git stash一下,然後去修複bug,修複後,再git stash pop,回到工作現場。
Feature分支
開發一個新feature,最好建立一個分支;
如果要丟棄一個沒有被合并過的分支,可以通過git branch -D 強行刪除。
git branch –d 這樣刪除一個沒合并過的分支會提示你失敗。
多人協作
多人協作的工作模式通常是這樣:
首先,可以試圖用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 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,如果有衝突,要先處理衝突。
標籤管理
發布一個版本時,我們通常先在版本庫中打一個標籤(tag),這樣,就唯一確定了打標籤時刻的版本。
建立標籤:
切換到需要打標籤的分支上,然後,git tag v1.0 就可以打一個新標籤,git tag查看已有標籤:
若要對曆史某個版本打標籤,只需要git log查看曆史commit的id就可以:
git show <tagname>git show 可以查看標籤的詳細內容
還可以建立帶有說明的標籤,-a指定標籤名,-m指定解說文字
$ git tag –a v0.1 –m “version 0.1 released” 9e93424
操作標籤:
如果標籤打錯了,可以刪除:
$ git tag –d v1.0
因為建立的標籤儲存在本地,還沒有推送到遠程
若要推送某個標籤:$ git push origin <tagname>
若要推送全部尚未推送的標籤:$ git push origin –tags
如果標籤已經推送到了遠程,要刪除遠程標籤就麻煩點,點從本地開始刪除:
$ git tag –d v0.9
然後遠程刪除:
$ git push origin :refs/tags/v0.9
自訂git
比如,讓git顯示顏色:
$ git config --global color.ui true
忽略特殊檔案:
在工作區的一些檔案不想提交到遠程,但每次git status都會顯示Untracked files…
要想讓git忽略某些檔案,需要在工作區建立一個特殊的.gitignore檔案,然後把忽略的檔案名稱填進去,注意.gitignore檔案本身需要放到版本庫裡。
設定別名
比如,git status不好敲,可以設定成git st,具體命令:
$ git config --gobal alias.st status
現在敲git st效果等於git status
常用的:
$ git config --global alias.co checkout
$ git config --global alias.ci commit
$ git config --global alias.br branch
git reset HEAD file命令是將暫存區的修改撤銷掉(unstage),重新放回工作區,可設定別名:
$ git config --global alias.unstage ‘reset HEAD‘
甚至還有人喪心病狂地把lg配置成了:
git config --global alias.lg "log --color --graph --pretty=format:‘%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset‘ --abbrev-commit"
效果很酷炫:
註:配置git時加上–global參數意思是針對目前使用者起作用,如果不加,僅針對當前倉庫
設定檔:
每個倉庫都有一個設定檔,.git/config
每個使用者也有一個設定檔,在使用者主目錄下.gitconfig
最後附上參考的兩位大神的原文地址:
廖雪峰
http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000
阮一峰
http://www.ruanyifeng.com/blog/2014/06/git_remote.html
Git教程(筆記)