寫在前面
在團隊做過軟件開發的,版本控制必是不可或缺的一項。目前,版本控制主要分為集中式版本控制系統和分布式版本控制系統 ,即大家熟知的SVN和Git。Git是當下最流行的分布式版本控制系統,故,今天,我們就來研究一下Git的神奇之處。
淺析SVN與Git的不同
- 最基本:SVN是集中式,Git是分布式的。集中式,版本庫集中存放在中央服務器,工作時,每個人需要先從中央服務器獲取最新的版本,然后在屬于自己的分支下工作,完成工作后,再提交到中央服務器;分布式,每一個電腦都是一個完整的版本庫,可以減少中央服務器掛掉所帶來的嚴重后果。也可以這樣理解,Git相當于SVN服務端和客戶端的集合;
- 聯網需求不同:Git中,不必聯網就能看到版本迭代的信息和創建分支,而,SVN需要在聯網的情況下才能滿足上述要求;
- 分支管理難易程度不同:在SVN中,分支作為版本庫中一個目錄,若需要查看是否合并,還需要運行
svn propget svn:mergeinfo
指令;而在Git中,可以快速在幾個分支中切換和快速合并; - 存儲方式不同:SVN是按文件存儲,Git是按元數據方式存儲;
- 權限問題:在SVN中,可以設定每個賬號的權限,比如只讀、讀寫權限等,而Git就沒有相應的權限控制。這也許就是一些公司至今仍保留SVN的原因吧。
- 匯總:工具總有其側重點,沒有好與壞,只有各取所需。
安裝Git
- 第一種方法:安裝Git圖形管理工具——SourceTree,不必記那么多命令,了解基本流程就可以放心使用了,下載點這;
- 第二種方法:在Mac上安裝Git,可通過HomeBrew安裝,具體方法請參考HomeBrew的文檔;
- 補充其他平臺的安裝方法,請參考這。
- 如果大家對Mac終端的命令還不太了解的話,可以參考我的上篇文章:學好Mac常用命令,助力iOS開發
Git的使用
有兩種Git的使用方法,一種是通過終端命令控制,另一種是使用Git的圖形管理工具——SourceTree。具體兩者哪一種更好用,更有效率,那還得因人而異。筆者下面將會分別介紹這兩種方法的基本操作,希望讀者能邊讀邊動手操作一下,受益匪淺。
一.命令下的Git
1.創建版本庫:
- 首先,選擇一個合適的地方,創建一個空目錄:
Mac-Pro:~ kys-1cd gitTest
或者直接在相應目錄下,自己手動創建一個文件夾; - 其次,在終端上輸入
git init
命令,如下:
Mac-Pro:~ kys-1git init
Initialized empty Git repository in /Users/kys-1/Desktop/gitTest/.git/
這樣,一個本地倉庫就順利地建好了。 - 最后,每創建一個倉庫時,當前目錄都會多一個
.git
目錄,若是沒有看到,只需要使用ls -ah
命令即可:
Mac-Pro:gitTest kys-1$ ls -ah
. .. .DS_Store .git
很清楚可以看到,筆者的當前目錄有兩個隱藏的。
2.添加文件到版本庫
- 首先,創建一個
GitTest.md
文件,內容如下:
git is a strong software
Let's start with a good mood!
將該文件放到倉庫gitTest
所在的目錄下; - 其次,使用
git add
命令添加文件,如下:
Mac-Pro:gitTest kys-1$ git add GitTest.md
然后執行,如果不顯示任何信息,那就是運行無誤; - 最后,使用命令
git commit
將文件提交到倉庫,如下:
Mac-Pro:gitTest kys-1$ git commit -m "wrote a README"
[master (root-commit) dfaeb43] wrote a README
1 file changed, 1 insertion(+)
create mode 100644 GitTest.md
其中,-m
后面輸入的是本次提交的詳細信息,比如,完成了哪個功能或者修復了哪個bug。
3.查看倉庫狀態
-
首先,先對提交的
GitTest.md
中的信息進行修改,然后運行git status
,效果如下:
Mac-Pro:gitTest kys-1$ 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: GitTest.md no changes added to commit (use "git add" and/or "git commit -a")
4.查看修改內容
- 使用命令
git diff
可以查看具體修改了哪些內容,如下:
Mac-Pro:gitTest kys-1$ git diff
diff --git a/GitTest.md b/GitTest.md
index 00ad777..64590e1 100644
--- a/GitTest.md
+++ b/GitTest.md
@@ -1 +1,2 @@
-git is a strong software
\ No newline at end of file
+git is a strong software
+Let's start with a good mood!
\ No newline at end of file
5.版本回退
-
首先,使用
git log
命令查看歷史記錄,如下:
Mac-Pro:gitTest kys-1$ git log
//版本一
commit 988f92f1f5cf959d491ad63462e0c90372bb4b0b
Author: XiaolinSun 401788217@qq.com
Date: Fri Apr 8 11:15:08 2016 +0800add new //版本二 commit dfaeb438504942d09e7f4282bd93b560d2ee68e2 Author: XiaolinSun <401788217@qq.com> Date: Fri Apr 8 11:12:02 2016 +0800 wrote a README Mac-Pro:gitTest kys-1$ git reset --hard HEAD^ HEAD is now at dfaeb43 wrote a README Mac-Pro:gitTest kys-1$ git log //版本三 commit dfaeb438504942d09e7f4282bd93b560d2ee68e2 Author: XiaolinSun <401788217@qq.com> Date: Fri Apr 8 11:12:02 2016 +0800 wrote a README
很清晰,共有三次提交歷史。其中,988f92f1f5cf959d491ad63462e0c90372bb4b0b
這樣一串字符表示提交的版本號commit id
;
使用
git reset
命令可以回退到上一個版本,輸入git reset --hard commit id
,如下:
Mac-Pro:gitTest kys-1$ git reset --hard 988f92f
HEAD is now at 988f92f add new如果開發過程中,一不小心,回退錯了地方,可以使用
git reflog
命令查看命令歷史,如下:
Mac-Pro:gitTest kys-1$ git reflog
dfaeb43 HEAD@{0}: reset: moving to HEAD^
988f92f HEAD@{1}: commit: add new
dfaeb43 HEAD@{2}: commit (initial): wrote a README
從而,可以選擇要回到的那個版本即可。git reset --soft
直接將提交回滾到未提交狀態,如果回滾的提交超過兩個則直接回滾到指定的commit記錄;git reset --hard
直接丟棄指定commit記錄;
6.工作區與暫存區
-
工作區:上幾步中在電腦創建的文件目錄就是工作區,如下圖:
工作區 - 版本庫就是隱藏目錄
.git
; - 添加文件時,首先,用
git add
把文件添加進去,實際上是把文件修改添加到暫存區;然后,用git commit
提交更改,是把暫存區的內容提交到當前分支;最后,每次文件修改后,如果不add
到暫存區,那是不會加入到commit
。
7.撤銷修改
-
當你修改文件
GitTest.md
時,在你準備提交前,忽然發現一個錯誤,如圖:
git is a strong software
Let's start with a good mood!
Start up now!
Fight for future! //新添加的內容
這時候,必須要查看一下狀態:輸入git status
,如下:
Mac-Pro:gitTest kys-1$ 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: GitTest.md no changes added to commit (use "git add" and/or "git commit -a")
使用
git checkout -- file
命令就會丟棄工作區的修改,如下:
Mac-Pro:gitTest kys-1$ git checkout -- GitTest.md
然后再查看工作區的內容:
git is a strong software
Let's start with a good mood!
Start up now!
這個時候內容就恢復了。
8.刪除文件
- 使用
git rm
和``git commit命令就可以從版本庫刪除相應的文件,例如:我們新建一個
newFile.md`文件,然后將其加入工作區,如下所示:
新工作區
Mac-Pro:gitTest kys-1git commit -m "add newFile"
[master e278be1] add newFile
1 file changed, 1 insertion(+)
create mode 100644 newFile.md
Mac-Pro:gitTest kys-1git commit -m "delete newFile"
[master 9c28795] delete newFile
1 file changed, 1 deletion(-)
delete mode 100644 newFile.md
執行完這些命令后,文件就從版本庫中刪除了。
9.版本回滾的幾種方式及區別
- 回滾目前有兩種方式:
git revert
和git reset
-
git revert
:使用該命令進行版本回滾時,是用新的commit記錄回滾后的內容;git reset
是直接刪除指定的commit記錄; -
git revert
可以清晰看到回滾的記錄,同時,在合并其他分支時不會使發生變動的部分再次出現,保證了云端與本地的一致性;git reset
把某些commit在某個branch上刪除,因而和其他分支再次合并時,這些被回滾的commit應該還會被引入,一旦不小心執行了push
操作,后果不堪設想。
小結一下
以上操作都是在本地倉庫進行的一些操作,如果感覺上面講的有些許啰嗦,那么只需記住下面幾個命令即可:
1.git init -------創建空的版本庫;
2.git add -------添加文件到暫存區;
3.git commit -------提交文件到版本庫(倉庫);
4.git status -------查看相關狀態;
5.git diff -------查看具體修改的內容;
6.git log -------查看提交歷史記錄;
7.git reset -------回到上一版本;
8.git reflog -------查看命令歷史記錄;
9.git checkout -------丟棄工作區的修改;
10.git rm -------刪除文件;
二.SourceTree的使用
- 使用SourceTree客戶端來執行上述與本地倉庫相關的操作。
- 安裝并打開SourceTree:
- 選擇
本地
按鈕,后點擊新倉庫
,選擇創建本地倉庫
,填入自己的地址,點擊創建
就OK了(是不是很方便?):
- 我先創建一個名字
TTest
本地倉庫,演示一下后面的相關操作,點擊新建倉庫的導航條:
點擊
- 在工作區添加文件
README.md
:
解釋一下,
已暫存
就是相當于git add
操作。
- 提交操作,對比
git commit -m "add new info"
命令:
提交
- 查看具體內容修改、查看相關狀態都可以直接看到,就不在一一贅述了;
- 回到上一版本可以
回滾操作
,選擇具體的提交記錄,點擊右鍵,選擇提交回滾
即可; - 對比一下,發現
SourceTree
是如此的方便快捷!
遠程倉庫
- 概念:遠程倉庫可以用一臺電腦當做服務器,團隊其他成員可以從這個服務器克隆一份完整過程到自己的本地倉庫,同時,可以將完成的部分推送到遠程倉庫,以實現項目的跟進。由于是演示,咱就暫且使用現成的遠程倉庫——Github;
- 作為開發人員,github賬號是必備的,如果還沒有,那就得立即注冊一個。
- 創建SSH Key,因為本地的Git倉庫與Github遠程倉庫之間是通過SSH加密的。首先,需要到主目錄上查看是否有
.ssh
目錄,再查看.ssh
目錄下有沒有id_rsa
和id_rsa.pub
文件,如下,
查找.ssh目錄
發現沒有上述的兩個文件,這時需要創建:
Mac-Pro:~ kys-1 $ ssh-keygen -t rsa -C "youremail@example.com"
需要將郵件地址換成自己的地址,如下:
Mac-Pro:~ kys-1$ ssh-keygen -t rsa -C "40178217@qq.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/kys-1/.ssh/id_rsa):
Created directory '/Users/kys-1/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /Users/kys-1/.ssh/id_rsa.
Your public key has been saved in /Users/kys-1/.ssh/id_rsa.pub.
出現上述描述,就證明你成功了,然后到主目錄下找到.ssh
目錄,查看id_rsa
和id_rsa.pub
文件,id_rsa
是私鑰,需要自己保留好,id_rsa.pub
是公鑰,別人知道也無妨。
-
登錄Github賬戶,打開
Account settings
,SSH Keys
頁面,添加id_rsa.pub
文件的內容:
添加公鑰 添加SSH key的作用,是保證推送到遠程倉庫的提交確實是你提交的而不是別人代替,以確保項目被他人修改;
-
添加遠程庫:首先登陸github賬號,點擊“New repository ”按鈕,創建新倉庫,如下:
New repository
需要填寫倉庫名,描述以及是否勾選創建初始化文件等。
- 在本地倉庫下運行命令:
Mac-Pro:~ kys-1$ git remote add origin yourGitAddress
然后,將本地庫的所有內容推送到遠程庫:
Mac-Pro:~ kys-1$ git push -u origin master
到這一步,只要本地作了提交。就可以通過命令:
Mac-Pro:~ kys-1$ git push origin master
把本地master
分支的最新修改推送到GitHub上去。
- 使用
git clone
命令將遠程庫克隆到本地:
Mac-Pro:~ kys-1$ git clone yourLocalGitAddress1
- 在SourceTree下克隆遠程倉庫到本地的操作:
源URL就是遠程倉庫的地址,目標路徑是本地存儲的路徑。
創建與合并分支(與SourceTree同步對照)
概念:創建分支的目的是讓你的工作變得更靈活更有效率,當你開發新功能時,你創建了一個分支,你可以在在原來分支繼續工作,也可以在新建的分支上工作,兩者之間不會干預,當你完成了新功能,只需將新分支合并到原來分支上即可。最吸引人的是Git創建和切換分支是非常速度的。
-
創建
dev
分支,然后切換到dev
分支,使用git checkout
命令:Mac-Pro:gitTest kys-1$ git checkout -b dev Switched to a new branch 'dev'
-b
參數表示創建并切換.
-
使用
git branch
命令查看當前分支:Mac-Pro:gitTest kys-1$ git branch * dev master
-
SourceTree操作:
選擇分支按鈕
-
我們在dev分支進行操作,修改
README.md
文件內容然后提交:Mac-Pro:gitTest kys-1$ git add README.md Mac-Pro:gitTest kys-1$ git commit -m "dev branch" [dev 9be4a38] dev branch 1 file changed, 2 insertions(+), 1 deletion(-)
SourceTree操作:
-
dev
分支工作結束,切換到master
分支,Mac-Pro:gitTest kys-1$ git checkout master Switched to branch 'master' Your branch is up-to-date with 'origin/master'.
SourceTree操作:
點擊右鍵,選擇
檢出master
分支即可。
-
使用
git merge
指令把dev
分支的工作成果合并到master
分支上:Mac-Pro:gitTest kys-1$ git merge dev Updating 2269ea8..9be4a38 Fast-forward README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
SourceTree操作:選中
dev
分支,右擊選擇合并dev至master
即可,
-
使用
git branch -d dev
命令刪除dev
分支:Mac-Pro:gitTest kys-1$ git branch -d dev Deleted branch dev (was 9be4a38).
SourceTree操作:選中
dev
分支,右擊選擇刪除dev
即可。
小結一下
查看分支:git branch
創建分支:git branch <name>
切換分支:git checkout <name>
創建+切換分支:git checkout -b <name>
合并某分支到當前分支:git merge <name>
刪除分支:git branch -d <name>
沖突解決
-
制造沖突:先創建一個新的分子
conflict
,并在新分支上工作,修改README.md
內容,操作如下:Mac-Pro:gitTest kys-1$ git checkout -b conflict Switched to a new branch 'conflict' Mac-Pro:gitTest kys-1$ git add README.md Mac-Pro:gitTest kys-1$ git commit -m "make a conflict" [conflict 1bc6611] make a conflict 1 file changed, 2 insertions(+), 1 deletion(-)
切換到
master
,繼續修改README.md
內容,并提交修改:
Mac-Pro:gitTest kys-1git add README.md
Mac-Pro:gitTest kys-1$ git commit -m "add two conflicts"
[master f43d5d1] add two conflicts
1 file changed, 2 insertions(+), 1 deletion(-)-
合并分支,就會出現沖突:
Mac-Pro:gitTest kys-1git status
On branch master
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)both modified: README.md no changes added to commit (use "git add" and/or "git commit -a")
查看文件
README.md
就能看到沖突信息的提示了,紅色標記的內容就是用來標注不同分支的內容:
- 將內容改為以下內容就行了,然后重新提交就可以了。
We will make a conflict!
Mac-Pro:gitTest kys-1$ git add README.md
Mac-Pro:gitTest kys-1$ git commit -m "comflict fixed"
[master dad373b] comflict fixed
- 使用
git log --graph
可以看到分支合并圖; - 小憩一下:做到這一步是不是感覺自己好有成就感啊,下面的內容更精彩,繼續...
分支管理策略
- 上述合并分支,一大部分是在用
Fast forward
模式,這種模式又優點也有缺點,就是刪除分支后會丟掉分支信息,這時,我們需要使用一下普通模式,即使用帶有--no-ff
的git merge
,繼續上述流程:新建分支dev->修改提交->切換分支->合并分支:
Mac-Pro:gitTest kys-1git add README.md //***
Mac-Pro:gitTest kys-1git checkout master //***
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
Mac-Pro:gitTest kys-1$ git merge --no-ff -m"merge with --no-ff" dev //***
Merge made by the 'recursive' strategy.
README.md | 1 +
1 file changed, 1 insertion(+) - 當然你也可以使用
git log --graph --pretty=oneline --abbrev-commit
命令查看分支歷史:
- 補充幾點:首先,在實踐開發中,
master
分支是非常穩定的,僅用來發布新版本,但不在上面開發;其次,創建dev分支開發,等到版本發布的時候在合并到master
分支即可;團隊中每個人都有自己的分支,及時合并即可。
添加Bug分支
前述:修復Bug在所難免,修復Bug可以通過創建一個新的臨時分支修復,合并分支,刪除臨時分支。
-
情形:當你在
dev
分支上工作還沒有完成,正趕上有Bug
需要修復,這時你需要將手頭上工作暫存一下,抓緊時間修復Bug;
Mac-Pro:gitTest kys-1$ git status
On branch dev
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.md
no changes added to commit (use "git add" and/or "git commit -a")
- 使用
git stash
暫存當前工作區:
Mac-Pro:gitTest kys-1$ git stash
Saved working directory and index state WIP on dev: 40be6d0 merge with --no-ff
HEAD is now at 40be6d0 merge with --no-ff - 使用SourceTree操作:
- 這時,可以
git status
查看工作區,并可以創建Bug分支了; - 確定好在
master
分支修復Bug:
Mac-Pro:gitTest kys-1git checkout -b bug
Switched to a new branch 'bug'
Mac-Pro:gitTest kys-1git commit -m "fix bug"
[bug 2c013d1] fix bug
1 file changed, 1 insertion(+), 1 deletion(-)
在
bug
分支上修復完bug提交,就可以合并刪除bug
分支,如下:
Mac-Pro:gitTest kys-1git merge --no-ff -m "merge bug" bug
Merge made by the 'recursive' strategy.
README.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Mac-Pro:gitTest kys-1$ git branch -d bug
Deleted branch bug (was 2c013d1).SourceTree操作:
-
Bug修復完,我們需要將暫存區的分支拿出來了,切換到
dev
分支,使用git stash list
命令查看:
Mac-Pro:gitTest kys-1git stash pop
On branch dev
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.md no changes added to commit (use "git add" and/or "git commit -a")
SourceTree操作:
Feature分支
- 開發過程中,每需要開發一個新功能都需要添加一個分支,最后合并刪除,流程同上述
bug
分支相同,不再贅述。 - 強行刪除分支,例如:你在新的分支下開發功能,后期開會取消這個功能,你只能將這個分支上的內容全強制刪除,如下:
Mac-Pro:gitTest kys-1git branch -D feature
Deleted branch feature (was 5f7e86c). - SourceTree操作:
標簽管理
作用:標簽作為版本庫的快照,能夠在需要的時候很快找到對應的版本庫;
-
在指定提交節點上添加標簽,默認的標簽是打在最新提交的節點上的,使用
git tag
命令添加標簽,使用git show
命令查看標簽信息:
Mac-Pro:gitTest kys-1git tag //***
V1.0
Mac-Pro:gitTest kys-1$ git show V1.0 //***
commit d0fc2232015ae6737273fa5e94310bcfd4ef231c
Author: 40188217@qq.com
Date: Wed Apr 13 07:45:48 2016 +0800add a tag diff --git a/README.md b/README.md index 9082c3c..52ef851 100644 --- a/README.md +++ b/README.md @@ -9,4 +9,4 @@ Try a new way! Try doing a different thing! Try again! I am developing!!! - +I want to make a tag!
SourceTree操作:
- 使用
git tag -d <tagname>
命令刪除本地標簽,使用git push origin <tagname>
命令可以推送一個本地標簽,使用git push origin --tags
命令可以推送全部未推送過的本地標簽,使用git push origin :refs/tags/<tagname>
命令可以刪除一個遠程標簽,操作如下:
Mac-Pro:gitTest kys-1git push origin V1.0 //***
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (5/5), 497 bytes | 0 bytes/s, done.
Total 5 (delta 2), reused 0 (delta 0)
To https://github.com/123sunxiaolin/gitTest.git
* [new tag] V1.0 -> V1.0
推送本地未推送的標簽:
Mac-Pro:gitTest kys-1git tag -d V0.1 //***
Deleted tag 'V0.1' (was 98817ff)
Mac-Pro:gitTest kys-1$ git push origin :refs/tags/V0.1 //***
To https://github.com/123sunxiaolin/gitTest.git
- [deleted] V0.1 - SourceTree操作:點擊標簽,右擊選擇刪除即可,勾選
刪除所有遠程標簽
可以刪除遠程標簽,操作非常直觀:
忽略特殊文件
- 在Git工作目錄下,有一些配置文件我們不想提交到遠程倉庫,這時我們可以使用Git提供的
.gitignore
文件; - 忽略文件的原則是:忽略操作系統自動生成的文件,比如縮略圖等,
忽略編譯生成的中間文件、可執行文件等,忽略你自己的帶有敏感信息的配置文件,比如存放口令的配置文件。 - 首先,在Git目錄下,使用
git touch .gitignore
創建. gitignore
文件,然后編輯:
Mac-Pro:gitTest kys-1ls -ah
. .DS_Store .gitignore
.. .git README.md
- 如果你對配置文件還不甚了解,就看一下現成配置列表;
- 常用規則:
/mtk/ 過濾整個文件夾
*.zip 過濾所有.zip文件
/mtk/do.c 過濾某個具體文件
gitignore還可以指定要將哪些文件添加到版本管理中,只是在文件前加一個!
即可:
!*.zip
!/mtk/one.txt
其中,!/mtk/one.txt
只需要管理/mtk/目錄中的one.txt文件,這個目錄中的其他文件都不需要管理,說到這想必大家都明白了。
唯一的區別就是規則開頭多了一個感嘆號,Git會將滿足這類規則的文件添加到版本管理中。
- 最后一步就是將
. gitignore
文件推送到遠程倉庫即可。
寫在最后
- 在開發過程中,很多人糾結版本管理使用Git命令好呢,還是SourceTree客戶端好呢,其實這沒有明確的答案,完全取決于自己來,可以說兩種方式各有利弊,大家可以嘗試兩者結合使用,效果應該會更好。
- 寫到這,終于可以舒一口氣了,最后,附上自己寫文章時的截圖,希望大家給點掌聲以資鼓勵。
更新記錄
- 2018.11.21:更新
git revert
與git reset
命令在使用上的區別;
從4月8日開始寫,到今天才寫完,將近耗時一周,中途遇見不少問題,還好,都堅持下來了,做程序猿就得拼啊,不然怎么能攻城獅啊!
送給大家一句話:堅持到無能為力,拼搏到感動自己!