版本控制是一種記錄一個或若干文件內容變化,以便未來查閱特定版本修訂狀況的系統。linux
記錄文件每次的更新,能夠對每一個版本作一個快照,或是記錄補丁文件,適合我的用,如RCS。git
全部的版本數據都保存在服務器上,協同開發者從服務器上同步更新或上傳本身的修改github
全部的版本數據都存在服務器上,用戶的本地只有本身之前所同步的版本,若是不連網的話,用戶就看不到歷史版本,也沒法切換版本驗證問題,或在不一樣分支工做。並且,全部數據都保存在單一的服務器上,有很大的風險這個服務器會損壞,這樣就會丟失全部的數據,固然能夠按期備份。表明產品:SVN、CVS、VSS安全
全部版本信息倉庫所有同步到本地的每一個用戶,這樣就能夠在本地查看全部版本歷史,能夠離線在本地提交,只需在連網時push到相應的服務器或其餘用戶那裏。因爲每一個用戶那裏保存的都是全部的版本數據,只要有一個用戶的設備沒有問題就能夠恢復全部的數據,但這增長了本地存儲空間的佔用。bash
Git是目前世界上最早進的分佈式版本控制系統。服務器
優勢:ssh
缺點:分佈式
在官網下載安裝文件,雙擊打開,而後一直「NEXT」就好。 下載地址以下: git-scm.com/download/wi…工具
若是你想在 Linux 上用二進制安裝程序來安裝 Git,可使用發行版包含的基礎軟件包管理工具來安裝。 若是以 Fedora 上爲例,你可使用 yum:學習
sudo yum install git
複製代碼
若是你在基於 Debian 的發行版上,請嘗試用 apt-get:
sudo apt-get install git
複製代碼
咱們如今要初始化一個本地倉庫:
git init
複製代碼
建立以後,目錄下會多一個".git"的文件夾,這個項目git的配置都在這個文件夾下面。通常咱們不須要修改此文件夾下的內容。
咱們如今須要提交一個文件到git上應該如何作呢?咱們先來看一個栗子:
vi readme.md // 新增一個文件
## --- start
這個一個git測試文件?
## --- end
git add . // 更新到暫存區
git commit -m "build: 初始化項目" // 更新到資源庫
複製代碼
執行後出現了個錯誤:
這裏是說咱們得告訴git咱們是誰,因此執行一下下面的命令
git config --global user.email "tjlovecl@example.com"
git config --global user.name "tjlovecl"
複製代碼
再次執行 commit 命令
git commit -m "build: 初始化項目"
複製代碼
這樣文件就提交上去了。
這裏簡單說明一下:
Git本地有三個工做區域:工做目錄(Working Directory)、暫存區(Stage/Index)、資源庫(Repository或Git Directory)。
總結:
咱們使用 git add 工做區的文件添加到暫存區。
使用 git commit -m "xxxx" 將暫存取的內容推到倉庫。裏面的內容信息能夠參照 「Conventional Commits」 書寫規則。
咱們可使用 git status 查看狀態, 使用 git log 查看歷史紀錄。
咱們來看下面的栗子:
咱們先創建三個文件
vi a.txt // 新增 a.txt 文件
## --- start
aaa
## --- end
git add .
git commit -m "feat: 新增a.txt文件"
vi b.txt // 新增 b.txt 文件
## --- start
bbb
## --- end
git add b.txt
vi c.txt // 新增 c.txt 文件
## --- start
ccc
## --- end
複製代碼
咱們使用 git status 查看狀態
git status
複製代碼
咱們能夠看到 a.txt 已提交到版本庫裏面,這裏不存在, b.txt 在暫存區中, c.txt在工做區。
咱們使用 git log 查看歷史紀錄:
咱們先把上面栗子中的文件提交到資源庫:
git add .
git commit -m "feat: 新增b,c模塊"
複製代碼
而後對文件進行修改:
echo ddd >> c.txt // 修改c.txt文件
echo ddd > d.txt // 新增d.txt文件
git status
複製代碼
咱們能夠看到, c.txt以前存在版本庫中,咱們須要把修改丟棄。 d.txt在版本庫中沒有,因此咱們須要刪除文件。 使用以下命令:
git checkout -- c.txt
rm d.txt
複製代碼
總結:
當文件已提交到暫存區,咱們應該如何回退呢?咱們先來修改一些文件,而且提交到暫存區
echo ddd >> c.txt // 修改c.txt文件
echo ddd > d.txt // 新增d.txt文件
git add .
git status
複製代碼
使用以下命令移除暫存區,讓文件回到工做區,而後使用上一節的方法丟棄修改
git reset HEAD .
git status
複製代碼
總結:
咱們先新增修改了一些文件,而且把他們提交到了暫存區,而後再新增修改一些文件,這些文件在工做區
echo ddd > d.txt // 新增 d.txt 文件
echo aaa >> a.txt // 修改 a.txt 文件
git add . // 把d.txt 和 a.txt文件加入暫存區
echo fff > f.txt // 新增 f.txt 文件
echo bbb >> readme.md // 修改 readme.md 文件
git status
複製代碼
接下來咱們要回退到最初的版本:
咱們先查看一下歷史:
git log
複製代碼
咱們查到了版本對應的git的id,接下來使用下面命令回退
git reset --hard a8b3ad1643671b30681b33c7506bec9badee6505
git status
複製代碼
git reflog
複製代碼
git reset --hard 2a39656
git log
複製代碼
PS:咱們常常看到 git reset --hard HEAD^ 這樣的命令, 這句話表示放棄修改的內容,回退當前的版本,HEAD 表示當前版本,HEAD^ 表示上一個版本, HEAD~100表示上100個版本。
總結:
在項目中,又些文件咱們並不須要上傳到git,只須要保留在本地,好比配置文件,第三包下載的文件,日誌文件等。 咱們先來新建文件和文件夾。
echo abc > ignore.txt
mkdir ignore
echo abc > ignore/a.txt
git status
複製代碼
這裏咱們須要新建".gitignore"文件:
vi .gitignore
## --- start
ignore.txt // 忽略 ignore.txt 文件
ignore/ // 忽略 ignore 文件夾
## --- end
git status
複製代碼
發現工做區只有 .gitignore文件,其餘的文件已被忽略。
總結:
分支就是科幻電影裏面的平行宇宙,當你正在電腦前努力學習Git的時候,另外一個你正在另外一個平行宇宙裏努力學習SVN。 若是兩個平行宇宙互不干擾,那對如今的你也沒啥影響。不過,在某個時間點,兩個平行宇宙合併了,結果,你既學會了Git又學會了SVN!
如今有了分支,就不用怕了。你建立了一個屬於你本身的分支,別人看不到,還繼續在原來的分支上正常工做,而你在本身的分支上幹活,想提交就提交,直到開發完畢後,再一次性合併到原來的分支上,這樣,既安全,又不影響別人工做。
其餘版本控制系統如SVN等都有分支管理,可是用過以後你會發現,這些版本控制系統建立和切換分支比蝸牛還慢,簡直讓人沒法忍受,結果分支功能成了擺設,你們都不去用。
但Git的分支是不同凡響的,不管建立、切換和刪除分支,Git在1秒鐘以內就能完成!不管你的版本庫是1個文件仍是1萬個文件。
當咱們建立新的分支,例如dev時,Git新建了一個指針叫dev,指向master相同的提交,再把HEAD指向dev,就表示當前分支在dev上:
你看,Git建立一個分支很快,由於除了增長一個dev指針,改改HEAD的指向,工做區的文件都沒有任何變化!
不過,從如今開始,對工做區的修改和提交就是針對dev分支了,好比新提交一次後,dev指針往前移動一步,而master指針不變:
假如咱們在dev上的工做完成了,就能夠把dev合併到master上。Git怎麼合併呢?最簡單的方法,就是直接把master指向dev的當前提交,就完成了合併:
因此Git合併分支也很快!就改改指針,工做區內容也不變!
合併完分支後,甚至能夠刪除dev分支。刪除dev分支就是把dev指針給刪掉,刪掉後,咱們就剩下了一條master分支:
下面開始實戰:
1)建立分支
git checkout -b dev
複製代碼
git checkout命令加上-b參數表示建立並切換,至關於如下兩條命令:
git branch dev
git checkout dev
複製代碼
2) 查看分支
git branch
複製代碼
echo aaaa >> a.txt
git add .
git commit -m "feat: a模塊新增一行"
複製代碼
git checkout master // 切回master分支
git merge dev // 合併dev分支到master
複製代碼
git branch -d dev
複製代碼
接下來咱們來探討切換分支對於暫存區和工做區文件的影響
1)咱們先來修改一些文件
echo bbb > b.txt
git add .
echo cccc > a.txt
git status
複製代碼
git checkout -b qa
git status
複製代碼
因此咱們能夠得出結論,有文件存在工做區或者暫存區時,切換分支後,這些文件會原封不動的帶到新的分支。
咱們能夠看一下以前的log,並無發現從dev合併到master的痕跡,那麼又沒有辦法能夠在日誌裏面留下點痕跡?
咱們能夠在merge命令中增長 "--no--ff"參數, 咱們已上面的qa分支爲例
git add .
git commit -m "feat: 新增b文件"
git checkout master
git merge --no-ff -m "chore: qa分支合併到master上" qa
git log --graph --pretty=oneline --abbrev-commit
複製代碼
總結:
1)Git鼓勵大量使用分支:
查看分支:git branch
建立分支:git branch <name>
切換分支:git checkout <name>或者git switch <name>
建立+切換分支:git checkout -b <name>或者git switch -c <name>
合併某分支到當前分支:git merge <name>
刪除分支:git branch -d <name>
複製代碼
2)有文件存在工做區或者暫存區時,切換分支後,這些文件會原封不動的帶到新的分支。
3)合併分支時,加上 --no-ff 參數就能夠用看出歷史有分支曾經作過合併。
人生不如意之事十之八九,合併分支每每也不是一路順風的。
咱們先修改一下master分支的a.txt文件
echo master >> a.txt
git add .
git commit -m "feat: 新增一行master"
複製代碼
咱們再切到qa分支上,修改a.txt文件
git checkout qa
echo qa >> a.txt
git add .
git commit -m "feat: 新增一行qa"
複製代碼
而後咱們再master分支合併一下
git checkout master
git merge --no-ff -m "chore: qa分支合併到master上" qa
git status
複製代碼
咱們打開 a.txt
git add .
git commit -m "chore: 解決qa合併到master的衝突"
複製代碼
小結:
當Git沒法自動合併分支時,就必須首先解決衝突。解決衝突後,再提交,合併完成。
解決衝突就是把Git合併失敗的文件手動編輯爲咱們但願的內容,再提交。
軟件開發中,bug就像屢見不鮮同樣。有了bug就須要修復,在Git中,因爲分支是如此的強大,因此,每一個bug均可以經過一個新的臨時分支來修復,修復後,合併分支,而後將臨時分支刪除。
當你接到一個修復一個代號101的bug的任務時,很天然地,你想建立一個分支bug-101來修復它,可是,等等,當前正在dev上進行的工做尚未提交:
echo tmpEdit >> a.txt
git add .
echo tmpEdit2 >> b.txt
git status
複製代碼
咱們可使用 stash命令把修改儲藏起來
git stash
git status
複製代碼
咱們再建立bug-101分支進行修改
git checkout -b bug-101
echo bbb >> b.txt
git add .
git commit -m "fix: 修正bug101"
複製代碼
切回master分支,而且合併
git checkout master
git merge --no-ff -m "chore: bug101合併到master上" bug-101
複製代碼
取出儲藏的修改
git stash list
git stash pop
git status
複製代碼
總結: 修復bug時,咱們會經過建立新的bug分支進行修復,而後合併,最後刪除; 當手頭工做沒有完成時,先把工做現場git stash一下,而後去修復bug,修復後,再git stash pop,回到工做現場。 通常咱們都是切獨立分支修改的,因此這個方法咱們用的不是特別多。
上面的章節裏面,咱們介紹了git的本地使用,知道了在本地各版本之間進行穿梭。 但這僅限於咱們本身玩,若是要你們一塊兒工做完成一個項目,勢必須要遠程倉庫。
雖然git是分佈式的,你們能夠相互傳輸文件,但其實不多在兩人之間的電腦上推送版本庫的修改,由於可能大家倆不在一個局域網內,兩臺電腦互相訪問不了,也可能今天你的同事病了,他的電腦壓根沒有開機。所以,分佈式版本控制系統一般也有一臺充當「中央服務器」的電腦,但這個服務器的做用僅僅是用來方便「交換」你們的修改,沒有它你們也同樣幹活,只是交換修改不方便而已。而爲了方便管理,咱們通常會把託管平臺選爲「中央服務器」。
託管平臺能夠是第三方提供的,如github,碼雲等,也能夠是咱們本身搭建的(公司使用gogs本身搭建了一個)。各類託管平臺操做大同小異,下面我就用第三方提供的github來看成咱們的「中央處理器」。
接下來咱們在github上新建一個項目:
1) 註冊登錄github
2) 新建倉庫
在倉庫頁面,咱們有兩種關聯倉庫的方式,咱們使用SSH的方式來關聯。
執行下面命令:
git remote add origin git@github.com:tjlovecl/git_yanshi.git // 關聯遠程倉庫
git push -u origin master
複製代碼
執行完成後會報一個權限驗證不經過的錯誤。
要消除這個錯誤,須要把咱們服務器的SSH公鑰放到github上。
咱們使用下面命令生成公鑰和私鑰。
ssh-keygen -t rsa
ll ~/.ssh
複製代碼
把公鑰的內容複製到gitthub上。
cat ~/.ssh/id_rsa.pub
複製代碼
咱們再執行一次,就能夠把master 分支推到遠程倉庫中去了。
git push -u origin master
複製代碼
小結:
咱們把qa推送到遠程倉庫:
git checkout qa
git push --set-upstream origin qa //第一次使用和遠程qa分支想關聯
複製代碼
之後可使用下面命令來推送
git push
複製代碼
使用下面命令來刪除遠程分支:
git push origin --delete qa
複製代碼
若是咱們本地沒有倉庫,須要把線上的倉庫克隆下來,可使用下面的命令,這裏咱們使用http的方式
cd ~
git clone https://github.com/tjlovecl/git_yanshi.git -b qa yanshi
複製代碼
咱們來解釋一下里面的兩個參數
若是咱們咱們本地有倉庫,只要拷貝線上的分支到本地: 可使用以下命令:
cd yanshi
git checkout -b master origin/master
複製代碼
小結:
若是咱們遠程分支推錯了怎麼辦?
這兩種方式孰優孰劣?咱們應該如何選擇?