1. 集中式VS分佈式
- 集中式:CVS、SVN
速度慢,必須聯網,版本庫在中央服務器中,使用簡單 - 分佈式:Git
速度快,無需聯網,安全性高,每個人的電腦都有完整的版本庫,中央服務器用來交換大家的改動,分支管理強大,使用較複雜
注: GitHub:免費提供Git存儲。提供Git倉庫託管服務,充當用於交換的免費中央服務器。
遠程倉庫實際上和本地倉庫沒啥不同,純粹爲了7x24小時開機並交換大家的修改
2. 版本回退和前進
- 版本回退/前進(重置HEAD指針)
git reset --hard HEAD~
回退到上一個版本
git reset --hard 91588fb
回退到指定版本
Git的版本回退速度非常快,因爲Git在內部有個指向當前版本的HEAD指針,當你回退版本的時候,Git僅僅是把HEAD從指向某個版本即可。
git reset
命令既可以回退版本,也可以把暫存區的修改回退到工作區。當我們用HEAD時,表示最新的版本. - 查看歷史操作記錄
git reflog
用git reflog查看命令歷史,以便確定要回到未來的哪個版本 git log -n 3
查看最新三條提交日誌
3.工作區和暫存區
工作區有一個隱藏目錄.git
,這個不算工作區,而是Git的版本庫。
Git的版本庫裏存了很多東西,其中最重要的就是稱爲stage
(或者叫index)的暫存區,還有Git爲我們自動創建的第一個分支master
,以及指向master的一個指針叫HEAD
前面講了我們把文件往Git版本庫裏添加的時候,是分兩步執行的:
-
第一步是用
git add
把文件添加進去,實際上就是把文件修改添加到暫存區; -
第二步是用
git commit
提交更改,實際上就是把暫存區的所有內容提交到當前分支。
因爲我們創建Git版本庫時,Git自動爲我們創建了唯一一個master
分支,所以,現在,git commit
就是往master分支上提交更改。
你可以簡單理解爲,需要提交的文件修改通通放到暫存區,然後,一次性提交暫存區的所有修改。
4. 管理修改
Git跟蹤並管理的是修改,而非文件。
你會問,什麼是修改?比如你新增了一行,這就是一個修改,刪除了一行,也是一個修改,更改了某些字符,也是一個修改,刪了一些又加了一些,也是一個修改,甚至創建一個新文件,也算一個修改。
Git管理的是修改,當你用git add命令後,在工作區的第一次修改被放入暫存區,準備提交,但是,在工作區的第二次修改並沒有放入暫存區,所以,git commit只負責把暫存區的修改提交了,也就是第一次的修改被提交了,第二次的修改不會被提交。
git diff HEAD -- xx.txt
比較xx.txt文件本地和倉庫最新的區別。
Git是跟蹤修改的,每次修改,如果不用git add到暫存區,那就不會加入到commit中,所以提交的過程是本地工作區->暫存區stage->版本庫
4.撤銷修改
git checkout -- readme.txt
讓這個文件回到最近一次git commit或git add時的狀態(git checkout
其實是用版本庫裏的版本替換工作區的版本,無論工作區是修改還是刪除,都可以“一鍵還原”。)
--
很重要,沒有--
,就變成了“切換到另一個分支”的命令git reset HEAD xx.txt
取消暫存區的修改到工作區。
git rese
t命令既可以回退版本,也可以把暫存區的修改回退到工作區。當我們用HEAD時,表示最新的版
5.分支管理
git checkout -b dev
我們創建dev分支,然後切換到dev分支,等價於git branch dev
和git checkout dev
兩條命令git branch
命令查看當前分支git checkout master
切換到master分支git merge dev
命令用於合併指定分支到當前分支,dev分支的最新提交是完全一樣的。
注意到上面的Fast-forward信息,Git告訴我們,這次合併是“快進模式”,也就是直接把master指向dev的當前提交,所以合併速度非常快git merge --no-ff -m "merged bug fix 101" issue-101
通常,合併分支時,如果可能,Git會用Fast forward
模式,但這種模式下,刪除分支後,會丟掉分支信息。如果要強制禁用Fast forward模式--no-ff
,Git就會在merge時生成一個新的commit,這樣,從分支歷史上就可以看出分支信息git branch -d dev
就可以放心地刪除dev分支了
我們注意到切換分支使用git checkout ,而前面講過的撤銷修改則是git checkout – filename,同一個命令,有兩種作用,確實有點令人迷惑
git log --graph --pretty=oneline -abbrev-commit
看到分支的合併情況,可以看到分支樹結構。
當Git無法自動合併分支時,就必須首先解決衝突。解決衝突後,再提交,合併完成
。
解決衝突就是把Git合併失敗的文件手動編輯爲我們希望的內容,再提交。git log --graph
命令可以看到分支合併圖,如下圖,內容比較豐富。
- 分支策略
在實際開發中,我們應該按照幾個基本原則進行分支管理:
首先,master分支應該是非常穩定的,也就是僅用來發布新版本,平時不能在上面幹活;
那在哪幹活呢?幹活都在dev分支上,也就是說,dev分支是不穩定的,到某個時候,比如1.0版本發佈時,再把dev分支合併到master上,在master分支發佈1.0版本;
你和你的小夥伴們每個人都在dev分支上幹活,每個人都有自己的分支,時不時地往dev分支上合併就可以了。
所以,團隊合作的分支看起來就像這樣:
git stash
當前工作現場“儲藏”起來,等以後恢復現場後繼續工作,之後,用git status查看工作區,就是乾淨的(除非有沒有被Git管理的文件),因此可以放心地創建分支來修復bug。git stash list
查看保存起來的工作現場- 恢復工作現場:
- 用
git stash apply
恢復,但是恢復後,stash內容並不刪除,你需要用git stash drop
來刪除 - 用
git stash pop
,恢復的同時把stash內容也刪了 git stash apply stash@{0}
有多次stash,選擇性恢復
git cherry-pick 4c805e2
複製(合併)一個特定的提交內容到當前分支;一般用於bug修復完成後需要把這個改動合併到其他分支。git remote
orgit remote -v
查看遠程庫的信息。你從遠程倉庫克隆時,實際上Git自動把本地的master
分支和遠程的master
分支對應起來了,並且,遠程倉庫的默認名稱是origin
git push origin master
把該分支上的所有本地提交推送到遠程庫git pull
獲取最新提交
6.標籤
發佈一個版本時,我們通常先在版本庫中打一個標籤(tag)
,這樣,就唯一確定了打標籤時刻的版本。將來無論什麼時候,取某個標籤的版本,就是把那個打標籤的時刻的歷史版本取出來。所以,標籤也是版本庫的一個快照
。
Git的標籤雖然是版本庫的快照,但其實它就是指向某個commit的指針(跟分支很像對不對?但是分支可以移動,標籤不能移動
),所以,創建和刪除標籤都是瞬間完成的.
tag就是一個讓人容易記住的有意義的名字
,它跟某個commit綁在一起
git tag v1.0
默認標籤是打在最新提交的commit上的,默認爲HEADgit tag v0.9 f52c633
對某次提交打標籤git tag
查看標籤git show tagName
查看某個標籤的信息git tag -a v0.1 -m "version 0.1 released" 1094adb
還可以創建帶有說明的標籤,用-a
指定標籤名,-m
指定說明文字git tag -d v0.1
刪除標籤git push origin <tagname>
推送某個標籤到遠程git push origin --tags
一次性推送全部尚未推送到遠程的本地標籤- 如果標籤已經推送到遠程,要刪除遠程標籤就麻煩一點
先從本地刪除:git tag -d v0.9
然後,從遠程刪除。刪除命令也是push,但是格式如下:git push origin :refs/tags/v0.9
7.忽略特殊文件
有些時候,你必須把某些文件放到Git工作目錄中,但又不能提交它們,比如保存了數據庫密碼的配置文件啦,等等,每次git status
都會顯示Untracked files ...
,有強迫症的童鞋心裏肯定不爽。
好在Git考慮到了大家的感受,這個問題解決起來也很簡單,在Git工作區的根目錄下創建一個特殊的.gitignore
文件,然後把要忽略的文件名填進去,Git就會自動忽略這些文件。
不需要從頭寫.gitignore文件,GitHub已經爲我們準備了各種配置文件,只需要組合一下就可以使用了。所有配置文件可以直接在線瀏覽:https://github.com/github/gitignore
略文件的原則是:
- 忽略操作系統自動生成的文件,比如縮略圖等;
- 忽略編譯生成的中間文件、可執行文件等,也就是如果一個文件是通過另一個文件自動生成的,那自動生成的文件就沒必要放進版本庫,比如Java編譯產生的.class文件;
- 忽略你自己的帶有敏感信息的配置文件,比如存放口令的配置文件。