[git]Git與Repo入門

轉自:http://www.cnblogs.com/angeldevil/archive/2013/11/26/3238470.htmlhtml

注:很是推薦的一篇關於git的博文git

 

目錄算法

版本控制vim

  1、原始版本控制服務器

  2、本地版本控制app

  3、集中版本控制編輯器

  4、分佈式版本控制分佈式

GIT工具

  1、得到GIT倉庫學習

  2、GIT中版本的保存

  3、GIT文件操做

  4、提交與歷史

  5、GIT分支

  6、標籤-tag

  7、Git配置

  8、其餘

REPO

版本控制

  版本控制是什麼已不用在說了,就是記錄咱們對文件、目錄或工程等的修改歷史,方便查看更改歷史,備份以便恢復之前的版本,多人協做。。。

1、原始版本控制

  最原始的版本控制是純手工的版本控制:修改文件,保存文件副本。有時候偷懶省事,保存副本時命名比較隨意,時間長了就不知道哪一個是新的,哪一個是老的了,即便知道新舊,可能也不知道每一個版本是什麼內容,相對上一版做了什麼修改了,當幾個版本過去後,極可能就是下面的樣子了:

  

2、本地版本控制

  手工管理比較麻煩且混亂,因此出現了本地版本控制系統,記錄文件每次的更新,能夠對每一個版本作一個快照,或是記錄補丁文件。好比RCS。

  

3、集中版本控制

  可是本地版本控制系統偏向於我的使用,或者多個使用的人必需要使用相同的設備,若是須要多人協做就很差辦了,因而,集中化的版本控制系統( Centralized Version Control Systems,簡稱 CVCS )應運而生,好比Subversion,Perforce。

  在CVCS中,全部的版本數據都保存在服務器上,一塊兒工做的人從服務器上同步更新或上傳本身的修改。

   

  可是,全部的版本數據都存在服務器上,用戶的本地設備就只有本身之前所同步的版本,若是不連網的話,用戶就看不到歷史版本,也沒法切換版本驗證問題,或在不一樣分支工做。。

  並且,全部數據都保存在單一的服務器上,有很大的風險這個服務器會損壞,這樣就會丟失全部的數據,固然能夠按期備份。

4、分佈式版本控制

  針對CVCS的以上缺點,出現了分佈式版本控制系統( Distributed Version Control System,簡稱 DVCS ),如GIT,Mercurial。

  DVCS不是複製指定版本的快照,而是把全部的版本信息倉庫所有同步到本地,這樣就能夠在本地查看全部版本歷史,能夠離線在本地提交,只需在連網時push到相應的服務器或其餘用戶那裏。因爲每一個用戶那裏保存的都是全部的版本數據,因此,只要有一個用戶的設備沒有問題就能夠恢復全部的數據。

  固然,這增長了本地存儲空間的佔用。

  

GIT

  必需要了解GIT的原理,才能知道每一個操做的意義是什麼,才能更容易地理解在什麼狀況下用什麼操做,而不是死記命令。固然,第一步是要得到一個GIT倉庫。

1、得到GIT倉庫

  有兩種得到GIT倉庫的方法,一是在須要用GIT管理的項目的根目錄執行:

git init

  執行後能夠看到,僅僅在項目目錄多出了一個.git目錄,關於版本等的全部信息都在這個目錄裏面。

  另外一種方式是克隆遠程目錄,因爲是將遠程服務器上的倉庫徹底鏡像一份至本地,而不是取某一個特定版本,因此用clone而不是checkout:

git clone <url>

2、GIT中版本的保存

  記錄版本信息的方式主要有兩種

  1. 記錄文件每一個版本的快照
  2. 記錄文件每一個版本之間的差別

  GIT採用第一種方式。像Subversion和Perforce等版本控制系統都是記錄文件每一個版本之間的差別,這就須要對比文件兩版本之間的具體差別,可是GIT不關心文件兩個版本之間的具體差異,而是關心文件的總體是否有改變,若文件被改變,在添加提交時就生成文件新版本的快照,而判斷文件總體是否改變的方法就是用SHA-1算法計算文件的校驗和

  GIT能正常工做徹底信賴於這種SHA-1校驗和,當一個文件的某一個版本被記錄以後會生成這個版本的一個快照,可是同樣要能引用到這個快照,GIT中對快照的引用,對每一個版本的記錄標識全是經過SHA-1校驗和來實現的

  當一個文件被改變時,它的校驗和必定會被改變(理論上存在兩個文件校驗和相同,但機率小到能夠忽略不計),GIT就以此判斷文件是否被修改,及以些記錄不一樣版本。

  在工做目錄的文件能夠處於不一樣的狀態,好比說新添加了一個文件,GIT發覺了這個文件,但這個文件是否要歸入GIT的版本控制仍是要由咱們本身決定,好比編譯生成的中間文件,咱們確定不想歸入版本控制。下面就來看下文件狀態。

3、GIT文件操做

  版本控制就是對文件的版本控制,對於Linux來講,設備,目錄等全是文件,要對文件進行修改、提交等操做,首先要知道文件當前在什麼狀態,否則可能會提交了如今還不想提交的文件,或者要提交的文件沒提交上。

文件狀態

  GIT倉庫所在的目錄稱爲工做目錄,這個很好理解,咱們的工程就在這裏,工做時也是在這裏作修改。

  在工做目錄中的文件被分爲兩種狀態,一種是已跟蹤狀態(tracked),另外一種是未跟蹤狀態(untracked)。只有處於已跟蹤狀態的文件才被歸入GIT的版本控制。以下圖:

  

  當咱們往工做目錄添加一個文件的時候,這個文件默認是未跟蹤狀態的,咱們確定不但願編譯生成的一大堆臨時文件默認被跟蹤還要咱們每次手動將這些文件清除出去。用如下命令能夠跟蹤文件:

git add <file>

  上圖中右邊3個狀態都是已跟蹤狀態,其中的灰色箭頭只表示untracked<-->tracked的轉換而不是untracked<-->unmodified的轉換,新添加的文件確定算是被修改過的。那麼,staged狀態又是什麼呢?這就要搞清楚GIT的三個工做區域:本地數據(倉庫)目錄,工做目錄,暫存區,以下圖所示:

  

  •   git directory就是咱們的本地倉庫.git目錄,裏面保存了全部的版本信息等內容。
  •   working driectory,工做目錄(版本控制文件),就是咱們的工做目錄,其中包括未跟蹤文件及已跟蹤文件,而已跟蹤文件都是從git directory取出來的文件的某一個版本或新跟蹤的文件。
  •   staging area,暫存區,不對應一個具體目錄,其實只是git directory中的一個特殊文件。

  當咱們修改了一些文件後,要將其放入暫存區而後才能提交,每次提交時其實都是提交暫存區的文件到git倉庫,而後清除暫存區。而checkout某一版本時,這一版本的文件就從git倉庫取出來放到了咱們的工做目錄。

文件狀態的查看

  那麼,咱們怎麼知道當前工做目錄的狀態呢?哪些文件已被暫存?有哪些未跟蹤的文件?哪些文件被修改了?全部這些只須要一個命令,git status,以下圖所示:

  

  GIT在這一點作得很好,在輸出每一個文件狀態的同時還說明了怎麼操做,像上圖就有怎麼暫存、怎麼跟蹤文件、怎麼取消暫存的說明。

文件暫存

  在上圖中咱們能夠很清楚地看到,filea未跟蹤,fileb已被暫存(changes to be committed),可是怎麼還有一個fileb是modified但unstaged呢?這是由於當咱們暫存一今後文件時,暫存的是那一文件當時的版本,當暫存後再次修改了這個文件後就會提示這個文件暫存後的修改是未被暫存的。

  接下來咱們就看怎麼暫存文件,其實也很簡單,從上圖中能夠看到GIT已經提示咱們了:use "git add <file>..." to update what will be committed,經過 

git add <file>...

  就能夠暫存文件,跟蹤文件一樣是這一個命令。在這個命令中可使用glob模式匹配,好比"file[ab]",也可使用"git add ."添加當前目錄下的全部文件。

  取消暫存文件是 

git reset HEAD <file>...

   若修改了一個文件想還原修改可用

git checkout -- <file>... 

查看文件修改後的差別

  當咱們修改過一些文件以後,咱們可能想查看咱們都修改了什麼東西,用"git status"只能查看對哪些文件作了改動,若是要看改動了什麼,能夠用:

git diff

  好比下圖:

  

  ---a表示修改以前的文件,+++b表示修改後的文件,上圖表示在fileb的第一行後添加了一行"bb",原來文件的第一行擴展爲了修改後的一、2行。

  可是,前面咱們明明用"git status"看到filesb作了一些修改後暫存了,而後又修改了fileb,理應有兩次修改的,怎麼只有一個?

  由於"git diff"顯示的是文件修改後尚未暫存起來的內容,那若是要比較暫存區的文件與以前已經提交過的文件呢,畢竟實際提交的是暫存區的內容,能夠用如下命令:

  

  /dev/null表示以前沒有提交過這一個文件,這是將是第一次提交,用:

git diff --staged

  是等效的,但GIT的版本要大於1.6.1。

  再次執行"git add"將覆蓋暫存區的內容。

忽略一些文件

  若是有一些部件咱們不想歸入版本控制,也不想在每次"git status"時看到這些文件的提示,或者不少時候咱們爲了方便會使用"git add ."添加全部修改的文件,這時就會添加上一些咱們不想添加的文件,怎麼忽略這些文件呢?

  GIT固然提供了方法,只需在主目錄下創建".gitignore"文件,此文件有以下規則:

  • 全部以#開頭的行會被忽略
  • 可使用glob模式匹配
  • 匹配模式後跟反斜槓(/)表示要忽略的是目錄
  • 若是不要忽略某模式的文件在模式前加"!"

  好比:

# 此爲註釋 – 將被 Git 忽略
*.a # 忽略全部 .a 結尾的文件
!lib.a # 但 lib.a 除外
/TODO # 僅僅忽略項目根目錄下的 TODO 文件,不包括 subdir/TODO
build/ # 忽略 build/ 目錄下的全部文件
doc/*.txt # 會忽略 doc/notes.txt 但不包括 doc/server/arch.txt

移除文件

  當咱們要刪除一個文件時,咱們可能就直接用GUI刪除或者直接rm [file]了,可是看圖:

  

  咱們須要將文件添加到暫存區才能提交,而移除文件後是沒法添加到暫存區的,那麼怎麼移除一個文件讓GIT再也不將其歸入版本控制呢?上圖中GIT已經給出了說明:

git rm <file>...

  執行以上命令後提交就能夠了,有時咱們只是想將一些文件從版本控制中剔除出去,但仍保留這些文件在工做目錄中,好比咱們一不當心將編譯生成的中間文件歸入了版本控制,想將其從版本控制中剔除出去但在工做目錄中保留這些文件(否則再次編譯可要花費更多時間了),這時只須要添加"--cached"參數。

  若是咱們以前不是經過"git rm"刪除了不少文件呢?好比說經過patch或者經過GUI,若是這些文件命名沒有規則,一個一個地執行"git rm"會搞死人的,這時能夠用如下命令:

  

移動文件

  和移除文件同樣,移動文件不能夠經過GUI直接重命令或用"mv"命令,而是要用"git mv",否則同移除文件同樣你會獲得以下結果:

  

  若是要重命名文件可使用

git mv old_name new_name

  這個命令等效於

mv old_name new_name

git rm old_name

git add new_name

交互式暫存

  使用git add -i能夠開啓交互式暫存,如圖所示,系統會列出一個功能菜單讓選擇將要執行的操做。

  

移除全部未跟蹤文件

git clean [options]  通常會加上參數-df,-d表示包含目錄,-f表示強制清除。

儲藏-Stashing

  可能會遇到這樣的狀況,你正在一個分支上進行一個特性的開發,或者一個Bug的修正,可是這時忽然有其餘的事情急需處理,這時該怎麼辦?不可能就在這個工做進行到一半的分支上一塊兒處理,先把修改的Copy出去?太麻煩了。這種狀況下就要用到Stashing了。假如咱們如今的工做目錄是這樣子的

$ git status
# On branch master
# Changes to be committed:
#
(use "git reset HEAD <file>..." to unstage)
#
#
modified:
index.html
#
# Changed but not updated:
#
(use "git add <file>..." to update what will be committed)
#
#
modified:
lib/simplegit.rb

  此時若是想切換分支就能夠執行如下命令

$ git stash
Saved working directory and index state \
"WIP on master: 049d078 added the index file"
HEAD is now at 049d078 added the index file
(To restore them type "git stash apply")

  這時你會發現你的工做目錄變得很乾淨了,就能夠隨意切分支進行其餘事情的處理了。

  咱們可能不僅一次進行"git stash",經過如下命令能夠查看全部stash列表

$ git stash list
stash@{0}: WIP on master: 049d078 added the index file
stash@{1}: WIP on master: c264051... Revert "added file_size"

  當緊急事情處理完了,須要從新回來這裏進行原來的工做時,只需把Stash區域的內容取出來應用到當前工做目錄就行,命令就是

git stash apply

  若是不基參數就應用最新的stash,或者能夠指定stash的名字,如:stash@{1},可能經過

git stash show

  顯示stash的內容具體是什麼,同git stash apply同樣,能夠選擇指定stash的名字。

  git stash apply以後再git stash list會發現,apply後的stash還在stash列表中,若是要將其從stash列表中刪除能夠用

git stash drop

  丟棄這個stash,stash的命令參數均可選擇指定stash名字,不然就是最新的stash。

  通常狀況下apply stash後應該就能夠把它從stash列表刪除了,先apply再drop仍是比較繁瑣的,使用如下一條命令就能夠同時完成這兩個操做

git stash pop

  若是咱們執行git stash時工做目錄的狀態是部分文件已經加入了暫存區,部分文件沒有,當咱們執行git stash apply以後會發現全部文件都變成了未暫存的,若是想維持原來的樣子操持原來暫存的文件仍然是暫存狀態,能夠加上--index參數

git stash apply --index

  還有這麼一種狀況,咱們把原來的修改stash了,而後修復了其餘一些東西並進行了提交,可是,這些提交的文件有些在以前已經被stash了,那麼git stash apply時就極可能會遇到衝突,這種狀況下就能夠在stash時因此提交的基礎上新建一個分支,而後再apply stash,固然,這兩個步驟有一人簡單的完成方法

git stash branch <branch name>

4、提交與歷史

  瞭解了文件的狀態,咱們對文件進行了必要的修改後,就要把咱們所作的修改放入版本庫了,這樣之後咱們就能夠在須要的時候恢復到如今的版本,而要恢復到某一版,通常須要查看版本的歷史。

提交

  提交很簡單,直接執行"git commit"。執行git commit後會調用默認的或咱們設置的編譯器要咱們填寫提示說明,可是提交說明最好按GIT要求填寫:第一行填簡單說明,隔一行填寫詳細說明。由於第一行在一些狀況下會被提取使用,好比查看簡短提交歷史或向別人提交補丁,因此字符數不該太多,40爲好。下面看一下查看提交歷史。

查看提交歷史

  查看提交歷史使用以下圖的命令

  

  如圖所示,顯示了做者,做者郵箱,提交說明與提交時間,"git log"可使用放多參數,好比:

  

  僅顯示最新的1個log,用"-n"表示。

  

  顯示簡單的SHA-1值與簡單提交說明,oneline僅顯示提交說明的第一行,因此第一行說明最好簡單點方便在一行顯示。

  "git log --graph"以圖形化的方式顯示提交歷史的關係,這就能夠方便地查看提交歷史的分支信息,固然是控制檯用字符畫出來的圖形。

  "git log"的更多參數能夠查看命令幫助。

不通過暫存的提交

 若是咱們想跳過暫存區直接提交修改的文件,可使用"-a"參數,但要慎重,別一不當心提交了不想提交的文件

git commit -a

  若是須要快捷地填寫提交說明可以使用"-m"參數

git commit -m 'commit message'

修訂提交

  若是咱們提交事後發現有個文件改錯了,或者只是想修改提交說明,這時能夠對相應文件作出修改,將修改過的文件經過"git add"添加到暫存區,而後執行如下命令:

git commit --amend

  而後修改提交說明覆蓋上次提交,但只能重寫最後一次提交。

重排提交

  經過衍合(rebase)能夠修改多個提交的說明,並能夠重排提交歷史,拆分、合併提交,關於rebase在講到分支時再說,這裏先看一下重排提交。

  假設咱們的提交歷史是這樣的:

  

  若是咱們想重排最後兩個提交的提交歷史,能夠藉助交互式rebase命令: 

 git rebase -i HEAD~2 或 git rebase -i 3366e1123010e7d67620ff86040a061ae76de0c8

  HEAD~2表示倒數第三個提交,這條命令要指定要重排的最舊的提交的父提交,此處要重排Second commit與Third commit,因此要指定Initial commit的Commit ID。如圖所示:

  

  註釋部分詳細說明了每一個選項的做用,若是咱們想交互這兩個提交,只需把開頭的這兩行交換下位置就OK了,交換位置後保存,而後看下提交歷史:

  

  能夠看到提交歷史已經變了,並且最新的兩個提交的Commit ID變了,若是這些提交已經push到了遠程服務器,就不要用這個命令了。

刪除提交與修改提交說明

  若是要刪除某個提交,只須要刪除相應的行就能夠了,而要修改某個提交的提交說明的話,只須要把相應行的pick改成reward。

合併提交-squashing

  合併提交也很簡單,從註釋中的說明看,只須要把相應的行的pick改成squash就能夠把這個提交全併到它上一行的提交中。

拆分提交

  至於拆分提交,因爲Git不可能知道你要作哪裏把某一提交拆分開,把以咱們就須要讓Git在須要拆分的提交處停下來,由咱們手動修改提交,這時要把pick改成edit,這樣Git在處理到這個提交時會停下來,此時咱們就能夠進行相應的修改並屢次提交來拆分提交。

撤銷提交

  前面說了刪除提交的方法,可是若是是多人合做的話,若是某個提交已經Push到遠程倉庫,是不能夠用那種方法刪除提交的,這時就要撤銷提交

git revert <commit-id>

  這條命令會把指定的提交的全部修改回滾,並同時生成一個新的提交。

Reset

  git reset會修改HEAD到指定的狀態,用法爲

git reset [options] <commit>

  這條命令會使HEAD提向指定的Commit,通常會用到3個參數,這3個參數會影響到工做區與暫存區中的修改:

  • --soft: 只改變HEAD的State,不更改工做區與暫存區的內容
  • --mixed(默認): 撤銷暫存區的修改,暫存區的修改會轉移到工做區
  • --hard: 撤銷工做區與暫存區的修改

cherry-pick

  當與別人和做開發時,會向別人貢獻代碼或者接收別人貢獻的代碼,有時候可能不想徹底Merge別人貢獻的代碼,只想要其中的某一個提交,這時就可使用cherry-pick了。就一個命令

 git cherry-pick <commit-id>

filter-branch

  這條命令能夠修改整個歷史,如從全部歷史中刪除某個文件相關的信息,全局性地更換電子郵件地址。

5、GIT分支

   分支被稱之爲GIT最強大的特性,由於它很是地輕量級,若是用Perforce等工具應該知道,建立分支就是克隆原目錄的一個完整副本,對於大型工程來講,太費時費力了,而對於GIT來講,能夠在瞬間生成一個新的分支,不管工程的規模有多大,由於GIT的分支其實就是一指針而已。在瞭解GIT分支以前,應該先了解GIT是如何存儲數據的。

  前面說過,GIT存儲的不是文件各個版本的差別,而是文件的每個版本存儲一個快照對象,而後經過SHA-1索引,不僅是文件,包換每一個提交都是一個對象並經過SHA-1索引。不管是文本文件,二進制文件仍是提交,都是GIT對象。

GIT對象

   每一個對象(object) 包括三個部分:類型大小內容。大小就是指內容的大小,內容取決於對象的類型,有四種類型的對象:"blob"、"tree"、 "commit" 和"tag"。

  • 「blob」用來存儲文件數據,一般是一個文件。
  • 「tree」有點像一個目錄,它管理一些「tree」或是 「blob」(就像文件和子目錄)
  • 一個「commit」指向一個"tree",它用來標記項目某一個特定時間點的狀態。它包括一些關於時間點的元數據,如提交時間、提交說明、做者、提交者、指向上次提交(commits)的指針等等。
  • 一個「tag」是來標記某一個提交(commit) 的方法。

  好比說咱們執行了如下代碼進行了一次提交:

$ git add README test.rb LICENSE2
$ git commit -m 'initial commit of my project'

  如今,Git 倉庫中有五個對象:三個表示文件快照內容的 blob 對象;一個記錄着目錄樹內容及其中各個文件對應 blob 對象索引的 tree 對象;以及一個包含指向 tree 對象(根目錄)的索引和其餘提交信息元數據的 commit 對象。概念上來講,倉庫中的各個對象保存的數據和相互關係看起來以下圖:

  

  若是進行屢次提交,倉庫的歷史會像這樣:

  

分支引用

  所謂的GIT分支,其實就是一個指向某一個Commit對象的指針,像下面這樣,有兩個分支,master與testing:

  

  而咱們怎麼知道當前在哪個分支呢?其實就是很簡單地使用了一個名叫HEAD的指針,如上圖所示。HEAD指針的值能夠爲一個SHA-1值或是一個引用,看如下例子:

  

  git的全部版本信息都保存了Working Directory下的.git目錄,而HEAD指針就保存在.git目錄下,如上圖全部,目前爲止已經有3個提交,經過查看HEAD的值能夠看到咱們當前在master分支:refs/heads/master,當咱們經過git checkout取出某一特定提交後,HEAD的值就是成了咱們checkout的提交的SHA-1值。

  記錄咱們當前的位置很簡單,就是能過HEAD指針,HEAD指向某一提交的SHA-1值或是某一分支的引用。

新建分支

git branch <branch-name>

  有時須要在新建分支後直接切換到新建的分支,能夠直接用checkout的-b選項

git checkout -b <branch-name>

刪除分支

git branch -d <branch-name>

  若是在指定的分支有一些unmerged的提交,刪除分支會失敗,這裏可使用-D參數強制刪除分支。

git branch -D <branch-name>

檢出分支或提交

  檢出某一分支或某一提交是同一個命令

git checkout <branch-name> | <commit>

分支合併(merge)

  當咱們新建一個分支進行開發,並提交了幾回更新後,感受是時候將這個分支的內容合回主線了,這是就能夠取出主線分支,而後把分支的更新merge回來:

git checkout master

git merge testing

  若是master分支是testing分支的直接上游,即從master延着testing分支的提交歷史往前走能夠直接走到testing分支的最新提交,那麼系統什麼也不須要作,只須要改變master分支的指針便可,這被稱之爲"Fast Forward"。

  可是,通常狀況是這樣的,你取出了最新的master分支,好比說master分支最新的提交是C2(假設共3次提交C0<-C1<-C2),在此基礎上你新建了分支,當你在分支上提交了C三、C5後想將br1時merge回master時,你發現已經有其餘人提交了C4,這時候就不能直接修改master的指針了,否則會丟失別人的提交,這個時候就須要將你新建分支時master所在的提交(C2)後的修改(C4),與你新建分支後在分支上的修改(C三、C5)作合併,將合併後的結果做爲一個新的提交提交到master,GIT能夠自動推導出應該基於哪一個提交進行合併(C2),若是沒有衝突,系統會自動提交新的提交,若是有衝突,系統會提示你解決衝突,當衝突解決後,你就能夠將修改加入暫存區並提交。提交歷史相似下面這樣(圖來自Pro-Git):

  

  merge後的提交是按時間排序的,好比下圖,咱們在rename提交處新建分支test,在test上提交Commit from branch test,而後回到master提交commit in master after committing in branch,再將test分支merge進master,這時看提交提交歷史,Commit from branch test是在commit in master...以前的,儘管在master上咱們是在rename的基礎上提交的commit in master...而GIT會在最後添加一個新的提交(Merge branch 'test')表示咱們在此處將一個分支merge進來了。這種狀況會有一個問題,好比說在rename提交處某人A從你這裏Copy了一個GIT倉庫,而後你release了一個patch(經過git format-patch)給A,這時候test分支尚未merge進來,因此patch中只包含提交:commit in master...而後你把test分支merge了進來又給了A一個patch,這個patch會包含提交:Commit from branch test,而這個patch是以rename爲base的,若是commit in master...和Commit from branch test修改了相同的文件,則第二次的patch可能會打不上去,由於以rename爲base的patch可能在新的Code上找不到在哪一個位置應用修改。

  

分支衍合(rebase)

  有兩種方法將一個分支的改動合併進另外一個分支,一個就是前面所說的分支合併,另外一個就是分支衍合,這兩種方式有什麼區別呢?

  分支合併(merge)是將兩個分支的改動合併到一塊兒,並生成一個新的提交,提交歷史是按時間排序的,即咱們實際提交的順序,經過git log --graph或一些圖形化工具,可能很明顯地看到分支的合併歷史,若是分支比較多就很混亂,並且若是以功能點新建分支,等功能點完成後合回主線,因爲merge後提交是按提交時間排序的,提交歷史就比較亂,各個功能點的提交混雜在一塊兒,還可能遇到上面提到的patch問題。

  而分支衍合(rebase)是找到兩個分支的共同祖先提交,將要被rebase進來的分支的提交依次在要被rebase到的分支上重演一遍,即回到兩個分支的共同祖先,將branch(假如叫experiment)的每次提交的差別保存到臨時文件裏,而後切換到要衍合入的分支(假如是master),依次應用補丁文件。experiment上有幾回提交,在master就生成幾回新的提交,並且是連在一塊兒的,這樣合進主線後每一個功能點的提交就都在一塊兒,並且提交歷史是線性的

   對比merge與rebase的提交歷史會是下圖這樣的(圖來自Pro-GIt):

  (merge)

  (rebase)

 

  rebase後C3提交就不存在了,取而代之的是C3',而master也成爲了experiment的直接上游,只需一次Fast Forward(git merge)後master就指向了最新的提交,就能夠刪除experiment分支了。

衍合--onto

git rebase --onto master server client

  這條命令的意思是:檢出server分支與client分支共同祖先以後client上的變化,而後在master上重演一遍。

父提交

  HEAD表示當前所在的提交,若是要查看當前提交父提交呢?git log查看提交歷史,顯然太麻煩了,並且輸入一長串的Commit-ID也不是一個使人愉悅的事。這時可藉助兩個特殊的符號:~與^。

  ^ 表示指定提交的父提交,這個提交可能由多個交提交,^以後跟上數字表示第幾個父提交,不跟數字等同於^1。

  ~n至關於n個^,好比~3=^^^,表示第一個父提交的第一個父提交的第一個父提交。

遠程分支

  遠程分支以(遠程倉庫名)/(分支名)命令,遠程分支在本地沒法移動修改,當咱們clone一個遠程倉庫時會自動在本地生成一個名叫original的遠程倉庫,下載遠程倉庫的全部數據,並新建一個指向它的分支original/master,但這個分支咱們是沒法修改的,因此須要在本地從新一個分支,好比叫master,並跟蹤遠程分支。

  Clone了遠程倉庫後,咱們還會在本地新建其餘分支,而且可能也想跟蹤遠程分支,這時能夠用如下命令:

git checkout -b [branch_name] --track|-t <remote>/<remote-banch>

  和新建分支的方法同樣,只是加了一個參數--track或其縮寫形式-t,能夠指定本地分支的名字,若是不指定就會被命名爲remote-branch。

  要拉取某個遠程倉庫的數據,能夠用git fetch:

git fetch <remote>

  當拉取到了遠程倉庫的數據後只是把數據保存到了一個遠程分支中,如original/master,而這個分支的數據是沒法修改的,此時咱們能夠把這個遠程分支的數據合併到咱們當前分支

git merge <remote>/<remote-branch>

  若是當前分支已經跟蹤了遠程分支,那麼上述兩個部分就能夠合併爲一個

git pull

  當在本地修改提交後,咱們可能須要把這些本地的提交推送到遠程倉庫,這裏就能夠用git push命令,因爲本地能夠由多個遠程倉庫,因此須要指定遠程倉庫的名字,並同時指定須要推的本地分支及須要推送到遠程倉庫的哪個分支

git push <remote> <local-branch>:<remote-branch>

  若是本地分支與遠程分支同名,命令能夠更簡單

git push <remote> <branch-name> 等價於 git push <remote> refs/heads/<branch-name>:refs/for/<branch-name>

  若是本地分支的名字爲空,能夠刪除遠程分支。

  前面說過能夠有不止一個遠程分支f,添加遠程分支的方法爲

git remote add <short-name> <url>

6、標籤-tag

  做爲一個版本控制工具,針對某一時間點的某一版本打tag的功能是必不可少的,要查看tag也很是簡單,查看tag使用以下命令

git tag

  參數"-l"能夠對tag進行過濾

git tag -l "v1.1.*"

  Git 使用的標籤有兩種類型:輕量級的(lightweight)和含附註的(annotated)。輕量級標籤就像是個不會變化的分支,實際上它就是個指向特定提交對象的引用。而含附註標籤,其實是存儲在倉庫中的一個獨立對象,它有自身的校驗和信息,包含着標籤的名字,電子郵件地址和日期,以及標籤說明,標籤自己也容許使用 GNU Privacy Guard (GPG) 來簽署或驗證。

  輕量級標籤只需在git tag後加上tag的名字,若是tag名字

git tag <tag_name>

  含附註的標籤須要加上參數-a(annotated),同時加上-m跟上標籤的說明

git tag -a <tag_name> -m "<tag_description>"

  若是你有本身的私鑰,還能夠用 GPG 來簽署標籤,只須要把以前的 -a 改成 -s(signed)

  查看標籤的內容用

 git show <tag_name>

  驗證已簽署的標籤用-v(verify)

git tag -v <tag_name>

  有時在某一個版本忘記打tag了,能夠在後期再補上,只需在打tag時加上commit-id

  要將tag推送到遠程服務器上,能夠用

git push <remote> <tag_name>

  或者能夠用下面的命令推送全部的tag

git push <remote> --tags

7、Git配置

  使用"git config"能夠配置Git的環境變量,這些變量能夠存放在如下三個不一樣的地方:

  • /etc/gitconfig 文件:系統中對全部用戶都廣泛適用的配置。若使用 git config 時用 --system選項,讀寫的就是這個文件。
  • ~/.gitconfig 文件:用戶目錄下的配置文件只適用於該用戶。若使用 git config 時用 --global選項,讀寫的就是這個文件。
  • 當前項目的 git 目錄中的配置文件(也就是工做目錄中的 .git/config 文件):這裏的配置僅僅針對當前項目有效。每個級別的配置都會覆蓋上層的相同配置,因此 .git/config 裏的配置會覆蓋/etc/gitconfig 中的同名變量。

  在 Windows 系統上,Git 會找尋用戶主目錄下的 .gitconfig 文件。主目錄即 $HOME 變量指定的目錄,通常都是 C:\Documents and Settings\$USER。此外,Git 還會嘗試找尋 /etc/gitconfig 文件,只不過看當初 Git 裝在什麼目錄,就以此做爲根目錄來定位。

  最基礎的配置是配置git的用戶,用來標識做者的身份

git config --global user.name <name>

git config --global user.email <email>

  文本編輯器也能夠配置,好比在git commit的時候就會調用咱們設置的文本編輯器

git config --global core.editor vim

  另外一個經常使用的是diff工具,好比咱們想用可視化的對比工具

git config --global merge.tool meld

  要查看全部的配置,能夠用

git config --list

  或者能夠在git config後加上配置項的名字查看具體項的配置

git config user.name

  做爲一個懶人,雖然checkout、status等命令只是一個單詞,可是仍是嫌太長了,咱們還能夠給命令設置別名如

git config --global alias.co checkout

  這樣git co就等於git checkout

  前面說地,git配置項都保存在那3個文件裏,能夠直接打開相應的配置文件查看配置,也能夠直接修改這些配置文件來配置git,想刪除某一個配置,直接刪除相應的行就好了

  

8、其餘

  關於GIT各命令的說明能夠查看相關幫助文檔,經過如下方法:

git help <command>或git <command> --help

REPO

repo start <topic_name>

  開啓一個新的主題,其實就是每一個Project都新建一個分支。

repo init -u <url> [OPTIONS]

  在當前目錄下初始化repo,會在當前目錄生生成一個.repo目錄,像Git Project下的.git同樣,-u指定url,能夠加參數-m指定manifest文件,默認是default.xml,.repo/manifests保存manifest文件。.repo/projects下有全部的project的數據信息,repo是一系列git project的集合,每一個git project下的.git目錄中的refs等目錄都是連接到.repo/manifests下的。

repo manifest

  能夠根據當前各Project的版本信息生成一個manifest文件

repo sync [PROJECT1...PROJECTN]

  同步Code。

repo status

  查看本地全部Project的修改,在每一個修改的文件前有兩個字符,第一個字符表示暫存區的狀態。

- no change same in HEAD and index
A added not in HEAD, in index
M modified in HEAD, modified in index
D deleted in HEAD, not in index
R renamed not in HEAD, path changed in index
C copied not in HEAD, copied from another in index
T mode changed same content in HEAD and index, mode changed
U unmerged conflict between HEAD and index; resolution required

  每二個字符表示工做區的狀態 

letter meaning description
- new/unknown not in index, in work tree
m modified in index, in work tree, modified
d deleted in index, not in work tree

 

repo prune <topic> 

  刪除已經merge的分支

repo abandon <topic>

  刪除分支,不管是否merged

repo branch或repo branches

  查看全部分支

repo diff

  查看修改

repo upload

  上傳本地提交至服務器

repo forall [PROJECT_LIST]-c COMMAND

  對指定的Project列表或全部Project執行命令COMMAND,加上-p參數可打印出Project的路徑。

repo forall -c 'git reset --hard HEAD;git clean -df;git rebase --abort'

  這個命令能夠撤銷整個工程的本地修改。

 

  說明:文中關於Git的知識大多來自Pro-GIt,這本書感受不錯,想學習的能夠找來看:Pro-Git

相關文章
相關標籤/搜索