Git哲學與使用

-- 故國神遊,多情應笑我,早生華髮。html

Git是什麼?

Git是一個版本控制工具,代碼管理工具,團隊協做工具。它跟SVN等傳統工具實現一樣的目的;但從某種程度來講,它更快,更靈活。我想絕大多數讀者都已經在接觸這個工具了,而且用於平常的項目中去了。個人這篇文章,不是做爲一個Git入門教程,也不是做爲一本大塊頭的教科書。(說到教科書,我推薦下面的這本。這本書確實好,很全面。個人這篇文章,其實就是這本書的讀書筆記而已。)java

Pro Git -- http://git.oschina.net/progit/git

接着說。個人這篇文章,主旨在於啓發你們超越平時的使用侷限,從另外一種視角去看待Git和使用Git,讓人有一種「啊哈,Git也能這麼用「的感受。這有點王婆賣瓜的味道了,這我必須認可。程序員

Git最基本的用法

不少項目組,對於剛入職的程序員,會像下面這樣對他們普及Git的知識:redis

#使用git clone克隆項目的代碼
git clone https://your-project-address

#使用git add添加修改的文件
git add your-filename

#或者使用git add --all添加全部修改的文件
git add --all

#使用git commit提交代碼到本地的代碼庫
git commit -m some-description-message

#使用git push提交代碼到遠程的代碼庫
git push

#使用git pull拉下遠程代碼庫中更新的代碼
git pull

僅使用這五個命令,確實就足夠進行團隊協做了。這是使用Git的一種模式,並且無可厚非。不過,這樣作有種僅僅把Git當成了純粹的代碼共享庫的感受,多多少少顯得有點不大規範。其實,Git有更加豐富的能力,它能讓你的項目開發有更加規範的流程,整個項目歷史有更加清晰的追溯,分工協做上也更加井井有理。併發

Git的特點

Git的特點有哪些呢?app

本地代碼庫

Git的最大特點可能就是做爲一款分佈式代碼管理工具了。Git的絕大部分操做都是在本地進行的,這使得Git更快,並且更靈活。更靈活是由於在你的改動被提交到遠程代碼庫以前,你能夠在本地進行任意的操做。另外一方面,這也意味着改動提交到遠程被共享以後,就不方便再改動舊的提交歷史了。因此,請慎重上傳改動到遠程。編輯器

歷史

代碼的提交歷史是一個項目開發歷程的記錄。這其中不只僅是情懷的記錄。更重要的是,提交歷史給了咱們項目回溯的能力,從而讓咱們可以找出問題代碼的來源,並修正它。Git的提交歷史很強大,咱們能夠去翻看歷史,還能附加上豐富的篩選條件;甚至能夠修改有問題的歷史。爲了更好地利用Git的歷史功能,咱們要時刻保持提交歷史的細緻與乾淨。這意味着,咱們要恰到好處地提交咱們的代碼,以及給它一個恰到好處的描述。分佈式

分支

Git的另外一特點就是分支了。簡單地說,分支就是不一樣的代碼故事。它們相互區別又互有聯繫,漸行漸遠又能在某一處匯合。使用分支,咱們可以控制代碼的不一樣走向,從而很好地安排咱們的開發工做。靈活使用分支能夠簡化咱們的不少工做。ide

簡單

說Git簡單,聽起來有點怪怪的。若是你要了解Git 內部原理,那確實夠複雜的。不過,Git的特點在於,即便你不瞭解這些原理,你仍然能夠靈活運用它。只用去學Git的一些基本的概念就足夠了,例如倉庫,暫存,提交,歷史,分支等。說實話,我到如今是說不出這些概念的具體定義的,並且也只是淺要地瞭解了下這些概念的原理。可是,這並不影響我去使用它。Git的特點在於,學些基本的概念和原理;剩下的,去用就夠了。這讓我想起了不少的Unix工具,如Vim,LaTex等,以及Unix哲學。

Git哲學

所謂Git哲學,是指使用Git的思惟方式。下面是我以爲的Git哲學中最要緊的幾點:

1. 保持細緻清晰的提交歷史

若是說提交歷史是一個版本控制工具最核心的模塊,我以爲一點也不爲過。代碼的提交歷史要涵蓋到具體的每一次改動,而且要有清晰一致的描述。這要求咱們:

  1. 分紅一個個小的提交,而不是一次大的提交
  2. 每次提交要給到一個簡潔明瞭的描述

每次的提交得是一個具體的總體。所謂具體的,是指你的提交不能是一次籠統的或歸納的改動;所謂總體,是指你的提交是一個已經完成的改動,而不能是懸而未決的。其實,這兩點能夠從你的提交說明中檢驗出來:

  1. 若是你的提交說明出現了像」完成用戶登陸以及實現網站首頁佈局「這樣諸如以及、和這樣的詞彙,極可能就說明你的一次提交作了不止一件事情,應該分爲兩次提交。
  2. 若是你的提交說明出現了像」完成用戶登陸(一)「、」完成用戶登陸(二)「、」完成用戶登陸(終)「等這樣連續關聯的幾個提交,說明你的這幾個提交都在作一件事情,應該壓縮爲一個提交。

其實作到這一點也很容易 --

儘量得多提交,儘量得早提交,當完成一個小的功能點時就提交。

描述應該簡潔明瞭。簡潔是指可以用一句話描述你作的事情,而且不要覆蓋其餘沒必要要的信息;明瞭是指絕對不能含糊,不只你能看得懂,也要讓局外人也能看得懂。我列了幾個要點:

  1. 若是不能作到簡潔,或者說不能用一句話描述你的提交,頗有可能說明你的提交在作不止一件事情。解決辦法是分爲屢次提交。
  2. 不要使用含糊的或者歸納的描述。像諸如」修復BUG「這樣的描述是要不得的,得說清楚修復了什麼BUG。例如說」修復用戶登陸後無端崩潰的BUG「或者」修復ISSUE 553「。
  3. 不要附加多餘的信息,例如Author,Date,Email這些信息不要附加在描述裏面了,由於提交歷史已經自動包含這些信息了。

因爲每一個提交都是一個細緻的改動單元,當項目進行到必定階段,整個提交歷史必定會顯得很長。這時候你可能會以爲提交不少很雜,會淹沒一些重要的版本發佈提交,例如上線的版本v1.0,v1.1。我想這是沒必要要的擔憂,認真地對待提交歷史,會讓整個提交歷史顯得多而不雜。並且,徹底能夠爲重要的提交打標籤。請記住 git tag 命令,它能夠爲重要的提交打標籤。

Git的提交歷史是至關靈活的。你能夠查看歷史;更厲害的,你還能夠去修改它。因此,你能夠在任意時刻去修正你的歷史。這裏有個例外,就是你沒法修改遠程倉庫的提交歷史。一方面,有的遠程代碼倉庫不支持提交歷史的修改;另外一方面,即便支持修改歷史,這樣的修改也會對其餘開發者形成混亂。關於遠程提交的準則是:

  1. 萬萬不得修改遠程倉庫的提交歷史
  2. 在將代碼提交到遠程倉庫以前,再大概檢查一下準備push的系列本地提交

2. 即便濫用,也好過從不使用多分支

-- 一個分支就是一個故事,一個劇情。使用分支是爲了避免讓第三者破壞完美的劇情。

要有意識地去使用多分支,而不是去忽略它。能夠在下面的狀況下考慮使用分支:

  1. 當在主線版本的基礎上要加上一個實驗性的特性的時候,爲了避免影響主線的開發進程,能夠獨立地在另外一個分支上開發。這時分開的兩個故事能夠並行地發展,當實驗分支穩定後,兩分支能夠合併爲同一個分支。
  2. 當在主線版本的基礎上修復一個BUG,爲了避免影響主線的正常開發,能夠獨立地另開一個分支進行。這時分開的兩個故事能夠並行地發展,當BUG修復後,能夠將BUG分支併到主線分支。

這兩個使用分支的策略都是本地臨時分支使用策略。不管是添加特性分支仍是BUG修復分支,它們都有存在週期短的特色,而且都只是爲解決某個特定問題而存在的。當這個問題被解決之後,它們就要被併入到主分支,這樣就完成了本身的歷史使命。使用分支的一種狀況是:當你要同時進行多個任務的時候。

不管是主分支,仍是上面的特性添加分支或者BUG修復分支,都是你本身一我的的任務。你要同時完成兩個或者三個任務。這時候纔是分支發揮它最大做用的時候。不要在一個分支裏同時作這幾件事情,這樣會違反第一哲學。記住:

每次只作一個任務;若是不得已要臨時切換到其餘任務,請使用分支。

Git既存在本地分支也存在遠程分支;擅用分支,實際指的是靈活運用本地分支,而不是濫用遠程分支。你能夠隨意地建立本地分支,頻繁地在多個分支的下來回工做。但不要把這一切牽扯進遠程分支。通常來講,遠程分支是長期分支,是做爲項目不一樣的發展階段或者發展路線而存在的。例如穩定版、開發版、激進版等。這通常是項目決策者操心的事情。

再囉嗦一句:若是分支再也不須要了,就刪除它。

3. 開發過程儘量私有化

私有化意味着封裝。相似於面向對象上的封裝,團隊協做上也有封裝的概念。你能夠在本地靈活地使用Git的各類操做,而不會對他人形成任何影響。不過這種靈活性應侷限於本地,而不要將冗餘公開給遠程的共享庫。這方面有些準則,其中有些是對上面兩個哲學的總結,以下:

  1. 爲了簡化工做,要靈活使用Git的各類本地操做
  2. 本地提交歷史能夠適當地混亂;但在提交到遠程倉庫前,必定要整理好
  3. 不要修改遠程倉庫的提交歷史;並且,雖然不大可能,不要隨意將新建分支推送到遠程

實踐Git

體現Git哲學的最好方式就是實踐它,用Git的方式去工做,學會使用Git思惟。接下來我會涉及到具體的Git操做。

基本操做

【這一部分純當是複習。】

初始化一個新倉庫:

git init

 

從現有倉庫克隆:

git clone <your-project-address>

 

時刻檢查目錄狀態:

git status

 

.gitignore 文件能夠聲明脫離版本控制的文件:

#haha

 

暫存修改:

git add <new-file-or-modified-file>

git add --all

 

若是不當心 git add 了某個文件,使用 git rm 從暫存區移除(附帶--cached參數移除跟蹤但不刪除文件,以便稍後在 .gitignore 文件中補上):

git rm --cached <your-added-file>

 

想知道代碼作了哪些改動(會精確到行),使用:

git diff <some-file>

git diff #這會顯示全部文件的改動

 

上面的命令是顯示工做目錄中當前文件和暫存區域快照之間的差別;若是想知道暫存區域與最近一次提交之間的差別,附加 --cached 參數:

git diff --cached <some-file>

git diff --cached 

 

提交更新:

git commit #這會爲你打開一個文本編輯器

git commit -m <your-commit-message>

 

提交歷史

爲了更好地說明用法,我使用了JFinal項目的Git源碼做爲例子。

查看提交歷史

使用 git log 能夠查看提交歷史。你應該看到相似於下面的結果:

$ git log
commit 121e247032be9e4d6a3c7eb8035914f59857c43d Author: James
<jfinal@126.com> Date: Sun Jul 26 13:40:44 2015 +0800 修改變量名,actoin 改成 action commit d330532f9db493034578d5dac1ece43c65136569 Author: James <jfinal@126.com> Date: Sun Jul 26 11:00:55 2015 +0800 變量名修改

 

能夠看到SHA-1 校驗和,做者的信息,時間以及提交說明。Git使用校驗和來指代每一次提交,例如輸出第一行的 121e247032be9e4d6a3c7eb8035914f59857c43d 。另外,若是不產生歧義的話,能夠用校驗和的前幾個字符來指代提交,例如 121e247032be9e4d6a3c 和 121e247032

若是想看某一次具體的提交,指明它的校驗和便可:

$ git log d330532f9
commit d330532f9db493034578d5dac1ece43c65136569
Author: James <jfinal@126.com>
Date:   Sun Jul 26 11:00:55 2015 +0800

    變量名修改

commit cdec1c3ceaceecfa4297c72efd8d8095640757f8
Author: James <jfinal@126.com>
Date:   Thu Jul 16 10:10:49 2015 +0800

    修改 Cache.expireAt(...) 方法上的註釋

 

這會顯示從指定提交開始往前回溯的提交歷史。若是隻是想顯示指定的這一個提交,用 -1 參數( -2 則顯示兩次提交,依次類推):

$ git log d330532f9 -1
commit d330532f9db493034578d5dac1ece43c65136569
Author: James <jfinal@126.com>
Date:   Sun Jul 26 11:00:55 2015 +0800

    變量名修改

 

使用 git log --pretty=oneline 能夠顯示更緊湊的提交信息,每次提交用一行來顯示:

$ git log --pretty=oneline
121e247032be9e4d6a3c7eb8035914f59857c43d 修改變量名,actoin 改成 action
d330532f9db493034578d5dac1ece43c65136569 變量名修改
cdec1c3ceaceecfa4297c72efd8d8095640757f8 修改 Cache.expireAt(...) 方法上的註釋
749fbe0d8e9da0e33fe2b30085f7467e86881e17 JFinal 2.0 release ^_^
52633ce2da704cf35a48aa9b8a1afe99d6c2ed1d JFinal 2.0 release ^_^
1e00c07348bd7b1ed16bb5c224e0a0de67b9b13b JFinal 2.0 release ^_^
0330d7ed5f3d742eaca201456927d9cecb40e215 JFinal 2.0 release ^_^
aa4a95af60a1dc12dfd649bd208de473dcfb369f jfinal 1.9 release ^_^
af6469eb6f49c23cba8215f2b0e9c8d51cd5f8c9 jfinal 1.9 release ^_^
4ab71ce41cca8b7d16bef89655b51e6de6548d30 jfinal 1.9 release ^_^
03a3c5a2bdb848ad2f9a30e29eba4f468176497f jfinal 1.9 release ^_^

 

使用 -p 選項展開每次提交所作的修改。例如咱們使用下面的命令展開哈希前綴爲 d330532f9 的那次提交的修改:

$ git log d330532f9 -p -1
commit d330532f9db493034578d5dac1ece43c65136569
Author: James <jfinal@126.com>
Date:   Sun Jul 26 11:00:55 2015 +0800

    變量名修改

diff --git a/.gitignore b/.gitignore
index 416db66..b1e58ba 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,7 @@ integration-repo
 /build/
 
 # IDEA metadata and output dirs
+/.idea/^M
 *.iml
 *.ipr
 *.iws
diff --git a/src/com/jfinal/config/Routes.java b/src/com/jfinal/config/Routes.ja
index fab2604..8ad1b03 100644
--- a/src/com/jfinal/config/Routes.java
+++ b/src/com/jfinal/config/Routes.java
@@ -86,11 +86,11 @@ public abstract class Routes {

 

使用 --stat 選項僅顯示代碼修改的統計信息(僅顯示簡要的增刪行數統計,特別適合做代碼審查):

$ git log --stat
commit 121e247032be9e4d6a3c7eb8035914f59857c43d
Author: James <jfinal@126.com>
Date:   Sun Jul 26 13:40:44 2015 +0800

    修改變量名,actoin 改成 action

 src/com/jfinal/core/ActionMapping.java | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

commit d330532f9db493034578d5dac1ece43c65136569
Author: James <jfinal@126.com>
Date:   Sun Jul 26 11:00:55 2015 +0800

    變量名修改

 .gitignore                                             |  1 +
 src/com/jfinal/config/Routes.java                      |  6 +++---
 src/com/jfinal/plugin/activerecord/Sqls.java           |  4 ++--
 src/com/jfinal/plugin/activerecord/tx/TxByMethods.java | 14 +++++++-------
 src/com/jfinal/plugin/redis/RedisInterceptor.java      | 11 ++++++++++-
 5 files changed, 23 insertions(+), 13 deletions(-)

 

我從《Pro Git》中摘出了一些選項及說明:

選項 說明
-p 按補丁格式顯示每一個更新之間的差別。
--stat 顯示每次更新的文件修改統計信息。
--shortstat 只顯示 --stat 中最後的行數修改添加移除統計。
--name-only 僅在提交信息後顯示已修改的文件清單。
--name-status 顯示新增、修改、刪除的文件清單。
--abbrev-commit 僅顯示 SHA-1 的前幾個字符,而非全部的 40 個字符。
--relative-date 使用較短的相對時間顯示(好比,「2 weeks ago」)。
--graph 顯示 ASCII 圖形表示的分支合併歷史。
--pretty 使用其餘格式顯示歷史提交信息。可用的選項包括 oneline,short,full,fuller 和 format(後跟指定格式)。

 

Git提交歷史的一大特點在於能夠按照條件篩選歷史。例如篩選出最近兩週到最近一週的提交歷史:

$ git log --since=2.weeks --until=1.weeks
commit cdec1c3ceaceecfa4297c72efd8d8095640757f8
Author: James <jfinal@126.com>
Date:   Thu Jul 16 10:10:49 2015 +0800

    修改 Cache.expireAt(...) 方法上的註釋

 

我也列出了一些可以設置篩選條件的一些選項,一樣來源於《Pro Git》:

選項 說明
-(n) 僅顯示最近的 n 條提交
--since, --after 僅顯示指定時間以後的提交。
--until, --before 僅顯示指定時間以前的提交。
--author 僅顯示指定做者相關的提交。
--committer 僅顯示指定提交者相關的提交。
-- 命令的最後一個選項,後跟路徑名錶示只關心某一路徑下的提交歷史

 

修改提交歷史

Git提交歷史的另外一大特點在於你能夠修改它。不過格外注意的是,不要修改那些已經推送到遠程版本庫的提交歷史

 

首先介紹如何撤銷。這多少與修改歷史無關,由於此時的歷史可能還未造成。

若是隻是但願將某個文件的改動從暫存區拿出來,而保持文件原有內容不變,使用命令:

git reset HEAD <your-file>

 

其中HEAD指代最近一次提交(*)。你可使用HEAD變量來避免使用哈希值。

下述命令會令整個項目的狀態回退(保留修改):

git reset HEAD

 

若是想將文件恢復到最近一次提交的版本,使用命令 git checkout 。這會使得其從暫存區拿出來(若是已經存入暫存區),而且文件內容恢復到最近一次提交的狀態:

git checkout <your-file>

 

若是想直接撤銷全部改動(包括修改),使用命令:

git reset --hard HEAD    #恢復全部改動到最近一次提交

git reset --hard HEAD~1 #恢復全部改動到最近一次提交的上一次提交

git reset --hard HEAD~2 #恢復全部改動到最近一次提交的前兩次提交

git reset --hard d330532 #恢復到指定提交

 

帶有 --hard 選項的版本回退是一個不可恢復的操做,請謹慎用之。

 

當咱們完成提交後,發現漏掉了某些改動(例如忘記添加相應的API註釋)。這時咱們固然能夠將改動做爲一次新的提交提交一發。不過,還有其餘的方案,即將漏掉的改動從新補回到對應的歷史提交中,畢竟漏掉的改動確實是那次提交的一部分。Git給了咱們修改提交的能力。

若是隻是要修改最近的一次提交,使用 git add 命令暫存相應的改動,而後輸入命令 git commit --amend 。這會把你代入修改提交說明的編輯器中。保存後退出,咱們就完成了咱們的提交修改。

若是隻是想修改最近一次提交的提交說明,直接輸入 git commit --amend ,而後進入編輯器修改提交說明並保存退出便可。

 

要修改歷史中更早的提交,就要用到 git rebase -i 交互式的提交歷史修改工具。我在命令行中輸入:

git rebase -i HEAD~4

 

它會帶我進入一個文本編輯器中(在個人系統裏意外地是VIM)。關注前四行,會看到咱們能夠修改最近的四次提交歷史( HEAD~4 指定)。其中提交由早到晚地排列,與 git log 顯示順序相反。

1 pick 749fbe0 JFinal 2.0 release ^_^
2 pick cdec1c3 修改 Cache.expireAt(...) 方法上的註釋
3 pick d330532 變量名修改
4 pick 121e247 修改變量名,actoin 改成 action

 

這時咱們能夠修改某次提交,例如修改第2行的提交,只需將 pick 換成 edit 便可。而後保存並退出編輯器。

pick 749fbe0 JFinal 2.0 release ^_^
edit cdec1c3 修改 Cache.expireAt(...) 方法上的註釋
pick d330532 變量名修改
pick 121e247 修改變量名,actoin 改成 action

 

像以前同樣,使用 git commit --amend 修改提交;最後使用 git rebase --continue 完成修改任務。

咱們也能夠刪除某個提交,只需將相應的提交行刪掉便可。例如刪除第2行的提交:

pick 749fbe0 JFinal 2.0 release ^_^
pick d330532 變量名修改
pick 121e247 修改變量名,actoin 改成 action

 

從新排列提交也是OK的。只須要從新排列便可。例以下面的編輯把最近一次提交移到最前,最先的一次提交移到最近:

pick 121e247 修改變量名,actoin 改成 action
pick cdec1c3 修改 Cache.expireAt(...) 方法上的註釋
pick d330532 變量名修改
pick 749fbe0 JFinal 2.0 release ^_^

 

一個有用的功能是壓制提交,即把多個提交合併成一次提交。例以下面的編輯將多個描述都爲」JFinal 2.0 release ^_^「的提交合併爲一個提交:

pick 0330d7e JFinal 2.0 release ^_^
squash 1e00c07 JFinal 2.0 release ^_^
squash 52633ce JFinal 2.0 release ^_^
squash 749fbe0 JFinal 2.0 release ^_^
pick cdec1c3 修改 Cache.expireAt(...) 方法上的註釋

 

相應地,能夠拆分一個提交。它的技巧在於 edit 某次提交,而後調用 git reset HEAD^ 回到父提交,而後再屢次 git commit 便可。

git reset HEAD^
git add file1
git commit -m "add file1"
git add file2
git commit -m "add file2"
git rebase --continue

 

當準備進入交互式rebase工具時,若是當前的工做區存在修改而沒有被提交,則會被禁止進入。此時咱們能夠先將修改提交;有時又不但願這麼作,可能咱們的代碼改動還不能構成一個完整的提交。咱們只但願先保存本身的工做,而後在須要的時候釋放出來。這時就用到 git stash 命令了。

咱們能夠將改動保存在一個棧中,稱之爲儲藏(Stashing)

git stash

 

而後查看棧狀態:

$ git stash list
stash@{0}: WIP on master: 121e247 修改變量名,actoin 改成 action

 

由於是棧,能夠屢次調用 git stash ,而後查看棧狀態:

$ git stash list
stash@{0}: WIP on master: 121e247 修改變量名,actoin 改成 action
stash@{1}: WIP on master: 121e247 修改變量名,actoin 改成 action
stash@{2}: WIP on master: 121e247 修改變量名,actoin 改成 action

 

而後在適當的時候,釋放一個儲藏。既能夠釋放指定的儲藏,例如 stash@{0}stash@{1} stash@{2},也能夠默認釋放最近的儲藏(stash@{0}):

git stash apply    

git stash apply stash@{2}

 

當儲藏再也不須要時,刪除它:

git stash drop stash@{2}

 

或者當即釋放最近的儲藏並刪除它:

git stash pop

 

儲藏的典型應用場景是當工做區有未提交的修改時,要切回到舊提交去修改( git rebase -i )或者切換到其餘分支( git checkout )。

 

分支

Git的分支是從某個分支引出的一個分叉。在Git中建立分支時,必定是以某個分支爲基準,這個分支就是你當前工做的分支。

分支基本操做

要查看當前在哪一個分支下工做,輸入命令:

git branch

 

此時會列出全部本地分支,行首標有*號的是當前工做分支。

建立分支:

git branch <new-branch-name>

 

切換到新分支:

git checkout <new-branch-name>

 

同時建立及切換分支:

git checkout -b <new-branch-name>

 

合併分支:

git checkout master
git merge <new-branch-name>

 

這能保證將新分支的改動合併到主分支。

刪除分支:

git branch -d <new-branch-name>

 

只有已被合併的分支才能順利刪除,不然會提示錯誤。

若是要強制刪除分支,使用命令:

git branch -D <new-branch-name>

 

分支思惟

以上只是分支的基本操做命令。要想活用這些命令,就要知道分支的使用思惟。分支的使用思惟,我以爲就是一句話,重複以前的一句話:

當你要放下手中的任務,臨時切換到其餘任務時,使用分支。

我這裏想舉一個關於分支使用的簡單的不能再簡單的例子。

首先你在進行master上進行主線開發,實現功能點一。忽然你臨時接到任務,完成功能點二,並立刻上線。此時你不得不放下手中的工做,投入到實現功能點二中去。

這時,你首先要作的是保存你正在進行的工做以便未來能夠恢復。可使用儲藏 git stash 或者臨時提交你的代碼以在未來經過 git commit --amend 修改你的歷史。這裏假設你使用的是儲藏。

而後新建分支並切換到新分支工做:

git checkout -b feature2

 

當你完成功能點二的開發時,提交你的代碼:

git add --all

git commit -m "finish feature 2"

 

以後切換到主分支,合併feature2分支:

git checkout master

git merge feature2

 

改動能夠提交到遠程上線:

git push

 

而後你可使用 git stash pop 恢復你的工做。

分支工做流程:

隊伍中的長期分支控制了不一樣的開發進度。通常來講,應該有一個穩定分支和開發分支:你能夠將master做爲穩定分支,並配有一個develop分支;或者反過來,將master做爲開發分支,並配有一個stable分支。這裏假設master是穩定分支,而develop是開發分支。develop分支通常比master要超前,而且當測試穩定後纔會併入到master分支發佈。因此通常的工做流程就是:

在develop分支開發,測試穩定後併入到master分支發佈

另外,若是已發佈的版本遭遇到一個緊急BUG亟待修復,這時你應該保存develop分支的工做,而後切換到master分支去修復。由於要緊急發佈,你應當切換到穩定的master分支完成BUG修復,而不是基於不穩定develop分支。當修復完畢併發布後,再回到develop分支恢復工做。

Git找bug的能力:

利用分支,咱們能夠很好地分離了咱們的不一樣工做,不讓它們相互干擾,從而減小bug的來源;利用歷史,咱們能夠追蹤代碼的變化,爲咱們找出問題代碼提供了途徑。其實Git也爲咱們提供了其餘的好用的工具,利於咱們調試。

git blame:誰動了個人代碼

你是否會驚奇你的代碼爲何忽然變成這副模樣?不要緊,使用 git blame 命令能夠顯示你的代碼是誰最後修改的。命令格式:

git blame -L 12,22 simple.rb

 

能夠顯示文件simple.rb的第12至22行這塊代碼最後是誰、何時修改並提交的。

二分查找

還有一個有趣的命令是 git bisect 。它能夠以二分查找的策略逐步逼近你在乎的壞代碼的來源。

首先輸入 git bisect start 來啓動二分查找。

輸入 git bisect bad 來告知當前的提交已是問題提交了。

而後輸入 git bisect good <good-commit> 來告知你知道的最晚的正常提交。

接着就能夠肯定壞代碼的來源在<good-commit>和當前提交之間,二分查找策略就能夠開啓了,這時Git監測處於中間的一個提交。假設從<good-commit>到當前提交一共有12個提交,記編號爲0、一、…、11. 這時咱們檢出的提交應該是6.

你能夠輸入 git bisect good 來告知這個提交是正常的,這樣它會捨棄編號爲0、一、…、6的提交;也能夠輸入 git bisect bad 來告知問題依然存在,這樣它會捨棄編號爲七、八、…、11的提交。而後繼續二分策略…一直到咱們只剩下一個問題提交的時候。這個提交就是咱們的問題提交的最初來源。

當你完成的時候,應該運行 git bisect reset 從新回到最初的地方。

Git使用總結:

  1.  在調用 git add --all 前,應該使用 git status 查看你要添加的改動,以避免添加進沒必要要的改動。
  2.  要忽略的文件添加到 .gitignore 中去。
  3.  git commit 時要給到一個簡潔明瞭的描述。
  4.  git push 前要用 git log 檢查本身的提交歷史。
  5.  必要時要修改本地提交歷史,它們的命令是 git commit --amend 和 git rebase -i
  6.  不要修改遠程提交歷史,這每每意味着,你只能修改最近的幾個歷史。 
  7.  要靈活地使用本地分支。它們的命令主要是 git branch 、 git checkout 等。
  8.  切換分支前注意保存本身的工做,用到的工具是 git stash
  9.  不要隨意將本地分支push到遠程。

超越Git

Git是偉大的,但咱們依然要超越Git;畢竟Git只是一個工具,而咱們是使用工具的人。Git的功能是代碼管理和版本控制,但Git的本質在於其重視團隊,重視協做的開發精神。它重視協做,但又不束縛我的的創造。它使得每一個人均可以自由地編碼,同時又保持整個項目開發的協調一致。

相關文章
相關標籤/搜索