Android羣英傳神兵利器讀書筆記——第二章:版本控制神器——Git


 

本人一直是徐醫生的真愛粉,因爲參加比賽耽誤了8天,致使更新得有點慢,你們見諒php

  • 2.1 Git的前世此生
    • Git是什麼
    • Git安裝與配置
  • 2.2 建立Git倉庫
    • Git init
    • Git clone
  • 2.3 提交修改
    • add&&commit
    • 追加修改
    • 查看代碼倉庫狀態
    • 追溯版本歷史
  • 2.4 工做區與暫存區
    • Git操做區域
  • 2.5 Git回退
    • checkout&&reset
    • 回退版本
  • 2.6 操做歷史
  • 2.7 Git文件操做
    • git rm
    • 文件暫存
  • 2.8 遠程倉庫
    • 身份認證
    • 同步協做
    • Clone遠程倉庫
  • 2.9 分支管理
    • 建立分支
    • 查看分支
    • 合併分支
    • 刪除分支
    • 查看遠程分支
    • 推送分支
    • 分支管理思想
  • 2.10 Git圖解
  • 2.11 Tag
    • 建立Tag
    • 建立帶標籤的Tag
    • 查看Tag
    • 刪除標籤
    • 推送Tag到遠程
    • 刪除遠程Tag
  • 2.12 Git圖形化工具
    • Git for Windows
    • Github Desktop
    • Source Tree
    • Android Studio
  • 2.13 Git學習資料
    • Git練習

說到Git,就不能不提到一我的——Linus Torvaldshtml

他的一輩子基本上只幹了兩件事,一個是Linux,另外一個就是Gitgit


Git是用來作版本控制的,像日本公司作事情,每次修改文件都須要在文件第一頁新增修改履歷,詳細記錄修改內容,今後維護版本修改記錄,若是是多人同時操做,就會發生不少併發問題,能夠想象這種作法維護成本有多高,大量時間花費在履歷的維護上,同時每次只能一我的進行操做,所以高效的版本控制永遠是項目開發的重中之重github

爲了方便理解,我本身畫了個圖,意思是:每一個人都在同一條主線上工做,若是有分線讓其餘人同時工做,那麼效率將會提升不少shell

Git是目前世界上最早進的分佈式版本控制系統(沒有之一),固然把「分佈式」三個字去掉也是一樣成立的,目前市面上的版本控制工具,主要爲集中式的版本控制工具和分佈式版本控制工具兩種windows


做爲最方便易懂的版本控制方式,集中式的控制最先出如今開發界,它的使用方式與人的合做方式很是相似,即你們都去操做一份文件,若是有人佔用則等待。集中式的版本控制工具以SVN爲表明,它有一箇中央服務器控制着全部的版本管理,其餘全部的終端能夠對這個中央庫進行操做,中央庫保證版本的惟一性。bash

  • 若是中央服務器被毀,整個項目就完蛋
  • 集中式須要不斷與服務器交互,若是網絡出現故障,操做難以繼續下去

所以,它的劣勢:服務器

  • 容災性差
  • 通訊頻繁

固然,這兩個劣勢不能徹底否認了集中式的版本控制工具,只能說特定場合使用網絡


分佈式版本控制的典型就是Git,它跟集中式的最大區別就是它的終端能夠獲取到中央服務器的完整信息,就好像作了一個完整的鏡像。併發

  • 就算服務器出現問題被毀,各個終端依然有完整的備份
  • Git的各類操做能夠所有發生在本地,只須要最終完成後提交服務器便可,不須要頻繁通訊

學習Git最好的方式就是忘記SVN、VSS等版本控制工具的控制思想。做爲GIt版本控制工具,其核心在於如下幾個方面:

  • 分佈式:各個Repo都具備完整的鏡像,雖然在協做中一般會指定一臺中心服務器,但分佈式的思想是Git的第一個重要概念
  • 快照:相比SVN,Git每次記錄的都是完整的Repo信息,而不是每一個版本之間的差別,這也是Git速度快的緣由之一
  • 狀態區:瞭解Git的狀態區是學習Git的重要步驟,只有掌握了不一樣狀態區中的狀態,才能瞭解Git的核心思想
  • 分支:分支是Git最重要的功能之一,利用好分支可讓Git的使用如虎添翼

我的以爲這段放在這裏很難明白做者的意思,應該放在讀完這章以後,再來總結,這樣才能對號入座


在終端,安裝Git

查看Git的版本

若是你以前用過Git,那麼經過如下代碼可查看當前Git配置信息

固然你也能夠經過如下指令顯示全部Git項目通用的配置信息

或者經過指定的配置名來獲取單獨的配置信息

若是尚未對Git配置,那麼須要先對Git的Global參數進行基本配置後才能使用,相似於網站註冊

  • 配置單個參數
  • 配置多個參數
  • 刪除摸個配置
  • 與Linux設計思想同樣,咱們進入一個Git項目目錄,顯示全部全部文件

能夠發現有個.git的隱藏文件,打開這個文件

這裏保存了一個Git像項目的全部配置信息,而我的相關的配置信息都保存在Git的我的配置中


這個功能在Shell命令中很經常使用,開發者能夠根據本身習慣取用別名替代本來比較複雜的指令

經過上面可使用st來取代status指令,筆者還找到一個關於Git log比較好的Alias

效果如圖


版本控制就是爲了管理代碼,代碼就要放在倉庫(Repo)中,在Git中建立倉庫有兩種方式


  • 建立一個倉庫
  • 建立clone別人的倉庫

進入一個目錄,設置成Git的代碼倉庫

經過上面指令就能夠在文件目錄下建立成一個Git代碼倉庫,在建立成功後就會在該目錄下生成一個.git隱藏文件夾


Git clone用於clone一個遠程倉庫到本地,關於clone後面會繼續介紹,無論用哪一種方式都會建立一個.git的隱藏文件夾,裏面包含全部的版本記錄和配置信息,默認不要對這個文件夾修改


爲了演示咱們在項目建立一個README文件,再把README文件加入到版本控制中去

首先,建立一個README文件,並經過git status指令查看增長新文件,代碼倉庫的狀態變化

在添加文件後,Git追蹤到新文件README,並告訴開發者使用git add < file>的方式添加版本控制,最後將add後的文件經過git commit指令提交到代碼倉庫,完成一次版本的記錄

-m參數指定提交的註釋,這時經過git log指令,就能夠查看到剛纔的提交記錄

另外,Git還提供了一個git shortlog的指令,這條指令能夠根據提交者的名字進行分組,顯示每一個開發者的全部提交commit記錄,這適用於在文檔中建立發佈日誌


當開發者提交了一個commit後,發現該commit有錯,能夠隨時對這個commit進行修改,使用git commit –amend指令便可

經過這種方式能夠修改commit,而不是經過新的commit來修正前一個錯誤的commit

記住amend不是修改最近一次commit,而是整個替換掉他,對於Git來講是一個新的commit


裏面在空README文件中輸入一段文本」this is my readme!」,接下來使用git status指令查看當前代碼倉庫的版本修改

能夠發現,Git提示它檢測到了一個修改過的文件」modified: README」,並提醒使用git add\commit進行版本管理

除了使用git status查看文件的修改狀態,開發者還能夠經過git diff指令查看發生變化文件的具體變化,例如輸入git diff README

git diff指令除了比較指定文件的差別,還能夠比較提交節點間的差別,例如使用如下代碼比較與上一個commit節點間的差別

同理,經過指定不一樣的HEAD,例如HEAD^,HEAD^^,上次commit節點、上上次commit節點

除了上面Git自帶工具的diff操做,實際上Git還支持使用第三方的diff工具進行diff操做,如Meld、beyond compare等


在項目中一個倉庫一般會有很是屢次的add、commit過程,這些過程都會被記錄下來做爲追溯的證據,經過git log指令,顯示以下所示

這個Git倉庫發生了2次代碼提交,每條記錄都對應一個commit id,commit id是一個40位的16進制的SHA-1 hash code用來惟一標記一個commit

同時,咱們可使用gitk指令查看圖形化的Log記錄,Git會自動將commit串成一條時間線,每一個點就表明一個commit,點擊這些點就能夠看見相應的修改信息

git log參數設置,前面已經提到git log輸出結果的顏色搭配,更多指令能夠經過git log –help來獲取Log指令的詳細參數

除了git log指令之外,開發者還能夠經過git blame指令追溯一個指定文件的歷史修改記錄,這裏以我另外一個項目爲例

在Android Studio中,一樣能夠找到相似的功能,打開任意一個修改文件,在代碼行數的區域內,單擊鼠標右鍵,選擇Annotate選項,經過這種方式一樣能夠找到該文件每一行代碼的歷史操做人


Git一般是工做在三個區域上的,即工做區、暫存區和歷史區,其中,工做區就是開發者平時工做、修改代碼的區域;歷史區是用來保存各個版本的區域;暫存區則是Git的核心所在

暫存區實際上保存在Git根目錄下的.git隱藏文件夾中的一個叫index的文件中,開發者所作的代碼提交記錄都保存在這個文件中

當咱們向Git倉庫提交代碼時,執行add操做其實是將修改記錄保存到暫存區,例如當咱們修改了README文件並執行git add操做,再經過gitk查看歷史,如圖

能夠發現執行add操做後,Git在本地生成一個記錄,可是尚未commit,因此當前HEAD並無指向最新的修改,修改還保存在暫存區

下面再執行commit操做,繼續經過gitk查看歷史記錄

此時,HEAD已經移到最新的修改上了,也就是說,剛剛commit的內容生成了一個新的commit id,git commit操做就是將暫存區的內容所有提交,但若是內容不add到暫存區,那麼commit也就不會提交修改內容


git checkout指令是用來還原一個代碼倉庫中的文件的,例如筆者在前面的項目中,繼續修改README文件,而後執行git checkout< file>指令,此時再查看當前代碼倉庫狀態,如圖

能夠發如今修改文件以後,執行git add指令以前,若是執行checkout指令則會拋棄當前本地的全部修改,恢復到上次最後的提交版本

若是修改文件並執行git add指令後繼續修改文件,此時再執行checkout指令,查看代碼倉庫狀態

能夠發如今執行add指令將代碼提交奧暫存區後,再修改該文件,此時若是繼續執行checkout指令,則會將該文件恢復到執行add操做後的初始狀態,即恢復add後的全部修改

注意執行git status後顯示一句提示:(use 「git reset HEAD< file>…」 to unstage),Git告訴開發者能夠經過該指令將一個文件移出暫存區,這也是回退的方法,而對於已經commit的提交,若是要進行回退,則可使用git reset< last commit SHA>< file>指令,它的原理就是reset掉提交記錄,但不修改本地工做區,從而進行新的提交


當代碼倉庫中有了提交記錄後,就能夠經過git log指令查看歷史記錄,以下

在Git中,HEAD表示當前版本,那麼上一個版本就是HEAD^,上上一個版本就是HEAD^^,若是往上100個版本就不要這樣寫了,寫成HEAD~100便可

如今咱們回退到上個版本

由此能夠證實,當前版本已經回退,因此要回退到哪一個版本,只要經過HEAD找到對應的版本就能夠了,一樣你能夠寫commit id,也能夠以HEAD^、HEAD^^來表示對應版本


若是咱們回退以後,發現回退錯了,須要恢復到上一個版本,這個時候咱們能夠經過git reflog指令,查看操做歷史,從而獲取以前的commit id進行恢復

咱們執行shell的rm指令將README文件刪除,接下來執行git status查看當前代碼庫狀態

由此能夠發現,經過rm指令肯定能夠刪除一個文件,Git不只能夠監聽到增長新文件、刪除文件,還能夠監聽到文件的刪除操做,一樣經過git add\commit操做來完成一次新的提交

那麼除了從Shell的刪除指令rm的方式執行刪除操做以外,Git還提供了它的刪除指令——git rm

從新建立一個新的README文件,並提交到代碼倉庫,接下來使用git rm指令刪除這個文件

因而可知,git rm指令省去了從新執行git add的操做


這一段,我建議看了分支管理以後再看,做者放在這裏並非很符合邏輯,或者要看的話,理解個懵懵懂懂就好了

這裏的暫存不是前文中說到的暫存區,而是指一次備份與恢復操做

舉個例子,當前開發者正在dev分支上進行一個新功能的開發,可是開發到一半,測試人員提了一個bug須要解決,這時候開發者一般須要建立一個bug分支來修改這個bug,可是當前dev分支並非乾淨的,新功能開發到一半直接從dev上拉分支,代碼是不完善的,可能會編譯不過,在這種狀況下,可使用git stash指令將當前修改暫存起來,把修改前的分支做爲新的bug分支,而不會帶有新修改的代碼,等從新切換回dev分支的時候再把代碼pop出來,繼續開發

例如,你checkout了一個bug分支,修改了bug,使用git merge指令合併到了master分支並刪除了bug分支,從新切換到dev分支,想繼續以前的新功能開發,這時候就須要將以前執行git stash指令暫存的代碼pop出來,恢復以前操做

首先,你可使用git stash list指令查看當前暫存的內容,接下來經過git stash apply指令或者git stash pop指令進行內容恢復,這兩個指令做用是同樣的,區別是前者不會刪除記錄(你也可使用git stash drop刪除記錄),然後者會


既然Git是分佈式代碼倉庫,那麼開發者確定是須要多臺服務器同時進行協同操做的,我的開發者能夠經過Github獲取免費的遠程Git服務器器,或者使用國內開源中國的OSChina的Git服務器,對於企業用戶,則能夠銅鼓開源的Gitlab搭建企業級的Git遠程服務器

目前大部分的互聯網公司都會用Gitlab搭建本身的代碼庫和代碼庫管理平臺


當本地Git倉庫與Git遠程倉庫進行通訊的時候,須要經過SSH進行身份認證


進入.ssh目錄,查看是否已經存在id_ras文件和idras.pub文件

因爲我沒用過,因此不存在,經過下面指令生成這兩個文件

執行命令後,按三次Enter鍵,這裏設置的密碼就爲空了,而且建立了key

該命令生成的id_rsa和id_rsa.pub兩個文件就是SSH Key的祕鑰對,id_rsa是私鑰用於驗證本身的身份,而id_rsa.pub是公鑰用在Git遠程服務器上代表本身身份


下面須要把生成的SSH的公鑰保存到Git遠程服務器上,例如Github上,能夠在我的配置界面找到添加SSH Key的設置

選擇右邊列表上的」Add an SSH key」,將生成的id_ras.pub文件內容複製到Key輸入框中便可


當開發者在本地創建了Git倉庫想與遠程Git倉庫同步,這樣Github、Gitlab上的遠程倉庫就能夠做爲本地的備份,或者與其餘開發者進行協同工做


首先,在Github建立一個新的Repo(代碼倉庫)

點擊後,Github提示填寫相關的Repo信息

最後,點擊Create repository按鈕,建立好一個代碼倉庫,建立完畢後,Github提示如何使用這個Repo

在建立好的Repo中,Github會提示如何使用這個Repo,完整的指令都列出來了,開發者只須要按照說明操做就能夠了


下面咱們提交剛纔建立的Git項目

咱們再看看Github

README已經提交上去了,回過頭來看看添加到遠程服務器的代碼

這條指令中的origin指的就是遠程倉庫的名字,你也能夠叫別的名字,可是默認遠程倉庫都叫origin,以便區分

而下面一條指令使用代碼把修改推送到遠程倉庫,代碼以下

因爲git push指令加上了-u參數,因此Git不但會把本地的master分支內容推送到遠程新的master分支,還會把本地的master分支和遠程的master分支關聯起來

在Push到遠程分支以後,再次Push的時候就不用-u參數了,能夠直接使用git push或者git push origin master指定倉庫和分支名將新的修改推送到遠程分支

在實際項目中常常會發生這樣的協做問題,即開發者A將Push修改到Repo時,開發者B已經將本身的修改Push到了Repo,這時候開發者A在Push時候,Git會提示使用git pull指令先來獲取最新的修改,但這樣會在Git歷史中留下一個Merge History,這並非開發者但願的,所以在這種狀況下,可使用git pull –rebase指令拉取最新修改,該指令的做用是拉取本地代碼後,將本地未提交的代碼做用到最新版本中,從而避免多餘的Merge History


當遠程分支上的代碼有內容更新時,經過git pull指令便可拉取最新的代碼更新,若是拉取的更新代碼與本地沒有衝突,那麼Git將在本地自動進行代碼Merge工做


Github實際上就已經提示開發者如何使用git clone將一個遠程代碼倉庫clone到本地了,如圖

在Clone的時候,能夠選擇Https的方式或者SSH的方式進行Clone操做,但一般狀況下都會使用SSH的方式,由於Https的方式會要求帳號密碼驗證,而SSH則是經過對稱加密祕鑰來驗證的,比較方便,並且SSH協議在終端下對Git項目有優化,傳輸效率較高


舉個例子,筆者如今要開發一個新功能,須要大概3個月的時間,可是筆者不能天天都把未完成的代碼提交到其餘開發者天天都在使用的分支上,這樣其餘開發者拉取了筆者的代碼以後,就可能所以編譯不過,而沒法正常工做,可是筆者又不能直接新建一個代碼倉庫,這樣倉庫太多,很難管理,而使用Git,筆者能夠新建一個分支,在這個新的分支上開發新的功能而不會影響其餘開發者的工做,新的分支不只可以備份個人代碼,讓我可以開發新的功,並且當新功能開發完畢後,能夠經過合併分支將整個新功能Merge到其餘開發者正在使用的分支中


對於開發者的每次提交,Git都把它們串成一條時間線,這條時間線就是一個獨立的分支,不建立其餘分支時,默認只有一條時間線,在Git裏這個分支叫主分支即master分支,經過gitk指令能夠很清楚地看見各個分支的產生、合併狀況

因爲這裏只有筆者一我的操做,因此只建立了一個分支即主分支,經過一下指令,能夠建立一個新的分支並切換到該分支上

這裏須要注意的是,在前文中筆者也講到了checkout指令,此checkout指令非彼checkout指令,checkout後面跟分支名才表明分支操做,若是跟的是文件名,則表明恢復操做,另外經過-b參數,可使Git建立並自動切換到該分支,該命令等價於

若是該分支已經存在,那麼直接使用checkout<分支名>就能夠切換到該分支,可是在切換時,若是當前分支有過還未提交的修改,則Git是沒法切換分支的,此時最好的辦法就是經過git stash指令將修改暫存並恢復到原始版本,再切換分支


經過git branch指令能夠列出當前全部本地分支

在當前分支上會多一個*,用來表示當前所處的分支,經過指定-r參數能夠列出全部遠程分支,或者使用-a參數列舉全部本地和遠程分支


開發者切換到dev分支後,對內容進行修改,接下來執行add和commit操做,此時開發者再切換到master分支,查看當前修改,你會發現dev分支上以前作的修改在master分支上都沒有生效,由於這兩個是不一樣的分支,它們之間是徹底獨立不受影響的,因此咱們切換到master分支,而後Merge分支dev到master主分支中,經過下面代碼完成合並工做

在合併分支的時候,常常會發生Merge衝突的問題,這是全部版本控制工具都沒法避免的一個問題,Git在合併的時候,會對文件進行自動Merge,若是沒有衝突,則自動合併代碼,若是有衝突,Git會把衝突的代碼都顯示在代碼中,讓開發者刪除廢棄的代碼,最終完成合並操做


在合併分支時,還有一種Rebase操做,它與Merge操做所實現的功能基本是同樣的,惟一的區別是,使用Rebase操做後Git時間線會被進行合併,而Nerge操做不會


當一個臨時分支使用完畢後,最合適的操做是把這個分支刪除,避免過多的分支形成混亂,刪除一個再也不使用的分支,代碼以下

這裏有一點注意的是,當一個分支從未進行過合併的時候,若是刪除分支會收到提醒信息,若是須要強制刪除使用-D參數


當開發者從遠程倉庫clone代碼倉庫時,實際上Git自動把本地的master分支和遠程的master分支行對應起來了,而且遠程倉庫的默認名稱是origin,咱們經過如下指令查看遠程分支

或者使用如下指令查看詳細信息


要把本地建立的分支同步到遠程倉庫上,一樣是使用git push指令


Git雖然是一個無中央集權的版本控制系統,但在通常開發過程當中一般仍是會指定一臺服務器做爲Git版本中央庫,同時使用分支對中央庫進行版本控制


在Git中央服務器上(origin),都會有一個默認的主分支(master),而通常的開發不會直接在主分支上進行,主分支永遠用於打Tag和發佈release版本,保證發出去的版本必定是完善的、已驗證過的,並且在團隊中,也只有Leader以上級別的開發者纔有權限將其餘分支的代碼Merge到主分支,所以開發時,最少會創建一個develop分支,全部的最新開發進展都同步到develop分支


在開發過程當中,項目常常有一些須要緊急完成的功能或者須要緊急修復的bug,針對這些打斷正常開發流程的事情,一樣能夠利用分支來進行處理,這些分支稱之爲功能分支或輔助分支,這些分支的管理與develop分支的處理基本相似,但要注意的是,一旦完成修改應該馬上刪除這些分支,保證代碼庫的乾淨



Tag的概念相似於branch,區別是branch是能夠不斷改變、Merge的Tag則不行,Tag能夠認爲是一個快照、一個記錄點,用於記錄某個commit點或分支的歷史快照,Tag一般打在Master分支上,以保證代碼的準確性


建立一個Tag使用如下指令

也能夠在指定commit id上建立Tag

這裏能夠發現commit id並無寫全,實際上經過前六、7位SHA-1 Code,Git就能夠查找到相應的id


除了普通的Tag,還能夠建立帶有註釋的Tag,經過-a參數能夠指定Tag名,經過-m參數指定註釋文字


查看全部的Tag

也能夠經過git show< tagname>指令查看指定Tag的詳細信息


Tag的刪除與分支的刪除相似,經過-d參數便可


若是直接使用git push指令是沒法將一個Tag推送到遠程倉庫的,要把一個Tag推送到遠程,使用如下指令

或者經過指定–tags參數來推送全部的本地Tag


要刪除遠程Tag,就必須先刪除本地Tag

刪除本地Tag後,再從新Push到遠程代碼倉庫,此時指令與推送新建Tag到遠程有所不一樣


  • Git for Windows:該工具在Windows系統中提供了Git bash終端工具和Git GUI工具,英語教學遊戲工具地址https://git-for-windows.github.io/
  • Github Desktop:Github是使用最普遍的網絡Git庫,它也提供了本身的Git圖形化界面工具,地址https://desktop.github.com/
  • Source Tree:將Git中不少操做進行了封裝,能夠很方便地使用圖形化界面完成Git的操做,地址https://www.sourcetreeapp.com/
  • Android Studio:當一個項目被添加到Git Root後,在Android Studio中打開VCS菜單,就能夠進行版本控制的管理了

  • Git權威指南的中文版:http://git-scm.com/book/zh/v1/
  • Git Community Book學習資料:http://gitbook.liuhui998.com/
  • WIKI的Git主頁:https://git.wiki.kernel.org/index.php/Main_Page/
  • 圖解Git最好的網站:http://marklodato.github.io/visual-git-guide/index-zh-cn.html

  • Git dojo:練習快捷鍵的網站,將枯燥無味的學習變成有趣的在線遊戲https://www.shortcutfoo.com/app/dojos/git
  • 15分鐘練習Git:做者虛擬了一個終端,並將Git學習分解成一個個小任務,讓開發者在模擬的真實環境中學習https://try.github.io/levels/1/challenges/1
  • LearnGitBranching:與Learn Git 15 min很是相似,這個網站也模擬了一個Git終端界面

到這裏Git這章就結束了,我的感受徐醫生的思路並非從一個0Git入門的角度出發,一開始我看起來仍是比較吃力的,只是有個大概的概念和思路,接着我又去廖雪峯老師的網站讀了一遍,簡直是順口溜,由於是先看了徐醫生的,懂得概念和思路後,讀起來很是簡單

學習資料:

廖雪峯老師Git教程傳送門 經常使用Git命令大全思惟導圖–猴子搬來的救兵Castiel傳送門

相關文章
相關標籤/搜索