Git內(nèi)部培訓(xùn)課件

Git內(nèi)部培訓(xùn)課件

Git簡(jiǎn)介

什么是版本控制

版本控制系統(tǒng)(Version Control System离唐,簡(jiǎn)稱VCS)是一種記錄一個(gè)或若干文件內(nèi)容變化,以便將來(lái)查閱特定版本修訂情況的系統(tǒng)纽甘。

按類型可以分為:

  • 本地版本控制系統(tǒng)


    例如RCS(至少我是從來(lái)沒(méi)有用過(guò))
    本地版本控制系統(tǒng)解決了版本的管理問(wèn)題肮韧,再也不用時(shí)不時(shí)的把工程目錄锐想,通過(guò)手工拷貝的方式來(lái)存檔了帮寻。但本地版本控制系統(tǒng)的缺點(diǎn)是,無(wú)法解決多人協(xié)作的問(wèn)題赠摇。

  • 集中化的版本控制系統(tǒng)


    例如CVS固逗,SVN等(公司中SVN應(yīng)該用的比較多)
    有一個(gè)集中管理的服務(wù)器浅蚪,所有開(kāi)發(fā)人員通過(guò)客戶端連到這臺(tái)服務(wù)器,取出最新的 文件 或者提交更新烫罩。管理員可以掌控每個(gè)開(kāi)發(fā)者的權(quán)限惜傲。
    集中化的VCS不但解決了版本控制問(wèn)題,還可以多人協(xié)作贝攒。但缺點(diǎn)也是有的盗誊,就是太依賴于遠(yuǎn)程服務(wù)器收叶,CVS服務(wù)器宕機(jī)后孵延,會(huì)影響所有人的工作柱查。版本記錄只保存在一臺(tái)服務(wù)器上怒见,會(huì)有數(shù)據(jù)丟失風(fēng)險(xiǎn)。

  • 分布式版本控制系統(tǒng)


    例如Git
    客戶端并不只提取最新版本的文件佳谦,而是把 代碼倉(cāng)庫(kù) 完整地鏡像下來(lái)殴蹄。每一次的提取操作荚藻,實(shí)際上都是一次對(duì) 代碼倉(cāng)庫(kù) 的完整備份咽扇。
    所以并沒(méi)有"中心服務(wù)器"的概念邪财,所謂的"Git服務(wù)器",也同每個(gè)人的電腦一樣质欲,只是為了多人協(xié)作時(shí)树埠,方便大家交換數(shù)據(jù)而已。

什么是Git

Git是目前世界上最先進(jìn)的分布式版本控制系統(tǒng)(沒(méi)有之一)
好不好用嘶伟,看看它的開(kāi)發(fā)者是誰(shuí)就知道了:Linux之父 Linus Torvalds

小歷史: Linux內(nèi)核社區(qū)原本使用的是名為BitKeeper的商業(yè)化版本控制工具怎憋,2005年,因?yàn)樯鐓^(qū)內(nèi)有人試圖破解BitKeeper的協(xié)議奋早,BitMover公司收回了免費(fèi)使用BitKeeper的權(quán)力盛霎。
Linus原本可以出面道個(gè)歉赠橙,繼續(xù)使用BitKeeper耽装,然而并沒(méi)有。期揪。掉奄。Linus大神僅用了兩周時(shí)間,自已用C寫(xiě)了一個(gè)分布式版本控制系統(tǒng)凤薛,于是Git誕生了姓建!

為什么要使用Git

為什么要使用Git,或者說(shuō)Git相比SVN有什么優(yōu)勢(shì)呢缤苫?

  • 分布式

  • 分支管理

  • GitHub

安裝Git

  • 大多數(shù)Linux發(fā)行版已經(jīng)預(yù)裝了Git速兔,系統(tǒng)默認(rèn)自帶,如果不帶活玲。涣狗〉瘢可以源碼make安裝或使用yum/apt等直接安裝,過(guò)程不贅述了镀钓。
  • macOS下穗熬,安裝Xcode后,它的CLI工具里應(yīng)該會(huì)包含Git了丁溅』秸幔或者使用brew手工安裝一下。
  • Windows下窟赏,可以直接下載安裝 msysGit 妓柜。 或者如果你的機(jī)器上已經(jīng)有Cygwin,也可以直接用在它下面安裝Git饰序。
  • 圖形工具推薦使用 SourceTree领虹,查看分支非常直觀 。IntelliJ IDEA等IDE也會(huì)自帶一些圖形化的工具求豫,在合并代碼時(shí)很高效塌衰。

學(xué)習(xí)路徑

  • 首先,忘掉SVN/CVS蝠嘉,不要把Git的各種操作與它們做類比最疆,切記。
  • 剛開(kāi)始不要依賴圖形客戶端蚤告。首先應(yīng)該將精力用在理解原理上 -> 然后掌握一些基本CLI命令努酸,動(dòng)手操作實(shí)踐 -> 最后在實(shí)際工作中使用GUI工具以提高效率。
  • 重度Windows用戶使用Git時(shí)杜恰,與平時(shí)熟悉GUI的環(huán)境會(huì)有些違和感获诈,畢竟Git是Linux下的產(chǎn)物,Git遵循Linux的哲學(xué)心褐,Simple舔涎,簡(jiǎn)單直接,但Simple并不等于Easy逗爹。需要轉(zhuǎn)換一下思維亡嫌。

了解Git的工作原理

記錄文件整體快照

Git和其他版本控制系統(tǒng)的主要差別在于,Git只關(guān)心文件數(shù)據(jù)的 整體 是否發(fā)生變化掘而,而大多數(shù)其他系統(tǒng)則只關(guān)心 文件內(nèi)容 的具體差異挟冠。

SVN在每個(gè)版本中,以單一文件為單位袍睡,記錄各個(gè)文件的差異:

Git在每個(gè)版本中知染,以當(dāng)時(shí)的全部文件為單位,記錄一個(gè)快照:

大多數(shù)操作都在本地執(zhí)行

Git的絕大多數(shù)操作都只需要訪問(wèn)本地文件和資源斑胜,不用連網(wǎng)控淡。因?yàn)槟愕谋緳C(jī)上色瘩,就已經(jīng)是完整的代碼庫(kù)了。這樣一來(lái)逸寓,在無(wú)法連接公司內(nèi)網(wǎng)的環(huán)境中居兆,也可以愉快的寫(xiě)代碼了。
例如竹伸,如果想看當(dāng)前版本的文件和一個(gè)月前的版本之間有何差異泥栖,Git會(huì)取出一個(gè)月前的快照和當(dāng)前文件作一次差異運(yùn)算,而不用每次都請(qǐng)求遠(yuǎn)程服務(wù)器勋篓。

時(shí)刻保持?jǐn)?shù)據(jù)完整性

在保存到Git之前吧享,所有數(shù)據(jù)都要進(jìn)行內(nèi)容的校驗(yàn)和(checksum)計(jì)算,并將此結(jié)果作為數(shù)據(jù)的唯一標(biāo)識(shí)和索引譬嚣。
這項(xiàng)特性作為Git的設(shè)計(jì)哲學(xué)钢颂,建在整體架構(gòu)的最底層拜银。所以如果文件在傳輸時(shí)變得不完整殊鞭,或者磁盤損壞導(dǎo)致文件數(shù)據(jù)缺失,Git都能立即察覺(jué)尼桶。
Git使用SHA-1算法計(jì)算數(shù)據(jù)的校驗(yàn)和操灿,通過(guò)對(duì)文件的內(nèi)容或目錄的結(jié)構(gòu)計(jì)算出一個(gè)SHA-1哈希值,作為指紋字符串泵督。該字串由40個(gè)十六進(jìn)制字符組成趾盐,看起來(lái)就像是:
24b9da6552252987aa493b52f8696cd6d3b00373
Git的工作完全依賴于這類指紋字串,所以你會(huì)經(jīng)承±埃看到這樣的哈希值救鲤。實(shí)際上,所有保存在 Git數(shù)據(jù)庫(kù)中的東西都是用此哈希值來(lái)作索引的秩冈,而不是靠文件名本缠。

多數(shù)操作僅添加數(shù)據(jù)

常用的Git操作大多僅僅是把數(shù)據(jù)添加到數(shù)據(jù)庫(kù),很難讓Git執(zhí)行任何不可逆操作漩仙。在Git中一旦提交快照之后就完全不用擔(dān)心丟失數(shù)據(jù)搓茬,特別是養(yǎng)成定期推送到其他倉(cāng)庫(kù)的習(xí)慣的話犹赖。

文件的三種狀態(tài)

對(duì)于任何一個(gè)文件队他,在 Git 內(nèi)都只有三種狀態(tài):已提交(committed) 已修改(modified) 已暫存(staged)
已提交表示該文件已經(jīng)被安全地保存在本地?cái)?shù)據(jù)庫(kù)中了;
已修改表示修改了某個(gè)文件峻村,但還沒(méi)有提交保存麸折;
已暫存表示把已修改的文件放在下次提交時(shí)要保存的清單中。

由此我們看到 Git 管理項(xiàng)目時(shí)粘昨,文件流轉(zhuǎn)的三個(gè)工作區(qū)域:Git 的工作目錄垢啼,暫存區(qū)域窜锯,以及本地倉(cāng)庫(kù)。

每個(gè)項(xiàng)目都有一個(gè)名為.git的目錄芭析,它是 Git用來(lái)保存元數(shù)據(jù)和對(duì)象數(shù)據(jù)庫(kù)的地方锚扎。該目錄非常重要,每次克隆鏡像倉(cāng)庫(kù)的時(shí)候馁启,實(shí)際拷貝的就是這個(gè)目錄里面的數(shù)據(jù)驾孔。
從項(xiàng)目中取出某個(gè)版本的所有文件和目錄,用以開(kāi)始后續(xù)工作的叫做工作目錄惯疙。這些文件實(shí)際上都是從Git目錄中的壓縮對(duì)象數(shù)據(jù)庫(kù)中提取出來(lái)的翠勉,接下來(lái)就可以在工作目錄中對(duì)這些文件進(jìn)行編輯。
所謂的暫存區(qū)域只不過(guò)是個(gè)簡(jiǎn)單的文件霉颠,一般都放在 Git 目錄中对碌。有時(shí)候人們會(huì)把這個(gè)文件叫做索引文件,不過(guò)標(biāo)準(zhǔn)說(shuō)法還是叫暫存區(qū)域蒿偎。

基本的 Git 工作流程如下:

  1. 在工作目錄中修改某些文件朽们。
  2. 對(duì)修改后的文件進(jìn)行快照,然后保存到暫存區(qū)域诉位。
  3. 提交更新华坦,將保存在暫存區(qū)域的文件快照永久轉(zhuǎn)儲(chǔ)到 Git 目錄中。

所以不从,我們可以從文件所處的位置來(lái)判斷狀態(tài):如果是Git目錄中保存著的特定版本文件惜姐,就屬于已提交狀態(tài);如果作了修改并已放入暫存區(qū)域椿息,就屬于已暫存狀態(tài)歹袁;如果自上次取出后,作了修改但還沒(méi)有放到暫存區(qū)域寝优,就是已修改狀態(tài)条舔。

創(chuàng)建版本庫(kù)

有兩種取得Git項(xiàng)目倉(cāng)庫(kù)的方法。第一種是在現(xiàn)存的目錄下乏矾,通過(guò)導(dǎo)入所有文件來(lái)創(chuàng)建新的Git倉(cāng)庫(kù)孟抗。 第二種是從已有的Git倉(cāng)庫(kù)克隆出一個(gè)新的鏡像倉(cāng)庫(kù)來(lái)。

在目錄中創(chuàng)建新倉(cāng)庫(kù)

如果一個(gè)目錄還沒(méi)有使用Git進(jìn)行管理钻心,只需到此項(xiàng)目所在的目錄凄硼,執(zhí)行git init,初始化后捷沸,在當(dāng)前目錄下會(huì)出現(xiàn)一個(gè)名為.git的目錄

$ mkdir learngit
$ cd learngit
$ git init

從已有的倉(cāng)庫(kù)克隆

如果Git項(xiàng)目已經(jīng)存在摊沉,可以使用git clone從遠(yuǎn)程服務(wù)器上復(fù)制一份出來(lái),Git支持多種協(xié)議:

$ git clone mobgit@134.32.51.60:learngit.git  #使用SSH傳輸協(xié)議
$ git clone git://134.32.51.60/learngit.git  #使用Git傳輸協(xié)議
$ git clone https://134.32.51.60/learngit.git  #使用HTTPS傳輸協(xié)議

版本庫(kù)基本操作

檢查當(dāng)前文件狀態(tài)

使用git status命令可以查看文件的狀態(tài)

$ git status
On branch master
Initial commit
nothing to commit (create/copy files and use "git add" to track)

出現(xiàn)如上的提示痒给,說(shuō)明現(xiàn)在的工作目錄相當(dāng)干凈说墨,所有已跟蹤文件在上次提交后都未被更改過(guò)骏全。

現(xiàn)在我們做一些改動(dòng),添加一個(gè)readme.txt進(jìn)去尼斧,然后再看一下?tīng)顟B(tài)

$ cat>readme.txt
hello git
^C

git status
On branch master

Initial commit

Untracked files:
  (use "git add <file>..." to include in what will be committed)
    readme.txt

nothing added to commit but untracked files present (use "git add" to track)

Untracked files顯示了這個(gè)新創(chuàng)建的readme.txt處于未跟跟蹤狀態(tài)

跟蹤新文件

使用git add命令開(kāi)始跟蹤一個(gè)新文件

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   readme.txt


readme.txt已 被跟蹤 姜贡,并處于 暫存狀態(tài)

將本次修改暫存

現(xiàn)在我們?cè)賹?duì)readme.txt進(jìn)行修改,添加一行棺棵,再執(zhí)行git status查看狀態(tài)

$ git status
On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)

    new file:   readme.txt

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.txt


可以看到readme.txt 不僅出現(xiàn)在了Changes to be committed鲁豪,還出現(xiàn)在了Changes not staged for commit
由此可見(jiàn),Git關(guān)心的是 Changes 律秃,而不是文件本身爬橡。
再次執(zhí)行git add,可以將 本次修改 提交到暫存區(qū)棒动,Changes not staged for commit提示消失

提交更新

使用git commit命令將暫存區(qū)中的內(nèi)容提交至版本庫(kù)糙申,工作區(qū)又是干凈的了

$ git commit -m "my first commit"
[master (root-commit) 6c8912a] my first commit
 1 file changed, 2 insertions(+)
 create mode 100644 readme.txt

$ git status
On branch master
Your branch is based on 'origin/master', but the upstream is gone.
  (use "git branch --unset-upstream" to fixup)
nothing to commit, working tree clean

注意:一定要使用-m參數(shù)加入注釋,認(rèn)真描述本次的提交具體做了些什么船惨,這對(duì)于以后我們查詢歷史記錄非常重要柜裸。

如果覺(jué)得使用暫存區(qū)過(guò)于繁瑣,可以在commit時(shí)直接使用-a參數(shù)粱锐,Git就會(huì)自動(dòng)把所有已經(jīng)跟蹤過(guò)的文件暫存起來(lái)一并提交疙挺,從而跳過(guò)git add步驟。

$ git commit -a -m "my first commit"

查看歷史

使用git log命令可以查看歷史記錄

$ git log
commit 43c5d337ffdd76f33ce5f5f90103d57e55474956
Author: BlueXIII <bluexiii@163.com>
Date:   Thu Dec 8 14:45:59 2016 +0800

    this is my second commit

commit 6c8912ad2a8e90a7ba32cc8578fd0069a205221b
Author: BlueXIII <bluexiii@163.com>
Date:   Thu Dec 8 14:38:09 2016 +0800

    my first commit

可以看到怜浅,每次更新都有一個(gè)SHA-1校驗(yàn)和铐然、作者的名字和電子郵件地址、提交時(shí)間恶座、提交說(shuō)明搀暑。

撤消操作

撤消操作在這里這里不做重點(diǎn)描述了,只列出幾個(gè)常用命令跨琳。
修改最后一次提交:
git commit --amend
取消已經(jīng)暫存的文件:
git reset HEAD readme.txt
取消對(duì)文件的修改:
git checkout -- readme.txt

遠(yuǎn)程倉(cāng)庫(kù)

之前介紹了在本地倉(cāng)庫(kù)的一些操作自点。但當(dāng)與他人協(xié)作開(kāi)發(fā)某個(gè)項(xiàng)目時(shí),需要至少使用一個(gè)遠(yuǎn)程倉(cāng)庫(kù)脉让,以便推送或拉取數(shù)據(jù)桂敛,分享各自的工作進(jìn)展。

克隆遠(yuǎn)程庫(kù)

之前已經(jīng)在講新建倉(cāng)庫(kù)時(shí)已經(jīng)提到溅潜,如何克隆遠(yuǎn)程庫(kù)术唬,這里再重復(fù)列一遍:

$ git clone mobgit@134.32.51.60:learngit.git  #使用SSH傳輸協(xié)議
$ git clone git://134.32.51.60/learngit.git  #使用Git傳輸協(xié)議
$ git clone https://134.32.51.60/learngit.git  #使用HTTPS傳輸協(xié)議

查看綁定的遠(yuǎn)程庫(kù)

如果之前我們使用的git clone命令直接克隆了一個(gè)遠(yuǎn)程倉(cāng)庫(kù)到本機(jī),Git就已經(jīng)默認(rèn)綁定了一個(gè)名為origin的遠(yuǎn)程庫(kù)伟恶。當(dāng)然我們還可以手工綁定其它遠(yuǎn)程庫(kù)碴开,遠(yuǎn)程倉(cāng)庫(kù)可以有多個(gè)毅该。
使用git remote -v命令列出我們綁定了哪些遠(yuǎn)程庫(kù):

$ git remote -v
origin  mobgit@134.32.51.60:learngit.git (fetch)
origin  mobgit@134.32.51.60:learngit.git (push)

接下來(lái)還可以使用git remote show origin來(lái)查看這個(gè)名為origin的遠(yuǎn)程庫(kù)的更詳細(xì)的信息博秫,這里先不細(xì)講

$ git remote show origin
* remote origin
  Fetch URL: mobgit@134.32.51.60:learngit.git
  Push  URL: mobgit@134.32.51.60:learngit.git
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    dev
    master
    serverfix
    serverfix2
  Remote branches:
    dev        tracked
    master     tracked
    serverfix  tracked
    serverfix2 tracked
  Local branches configured for 'git pull':
    dev        merges with remote dev
    master     merges with remote master
    serverfix  merges with remote serverfix
    serverfix2 merges with remote serverfix2
  Local refs configured for 'git push':
    dev        pushes to dev        (up to date)
    master     pushes to master     (up to date)
    serverfix  pushes to serverfix  (up to date)
    serverfix2 pushes to serverfix2 (up to date)

手工添加一個(gè)遠(yuǎn)程倉(cāng)庫(kù)

我們先讓管理員新建一個(gè)名為learngit2的遠(yuǎn)程倉(cāng)庫(kù)潦牛,再使用remote add命令將它添加進(jìn)來(lái),取名為repo2

$ git remote add repo2 mobgit@134.32.51.60:learngit2.git

$ git remote -v
origin  mobgit@134.32.51.60:learngit.git (fetch)
origin  mobgit@134.32.51.60:learngit.git (push)
repo2   mobgit@134.32.51.60:learngit2.git (fetch)
repo2   mobgit@134.32.51.60:learngit2.git (push)

現(xiàn)在我們有origin和repo2兩個(gè)遠(yuǎn)程倉(cāng)庫(kù)了

從遠(yuǎn)程倉(cāng)庫(kù)抓取數(shù)據(jù)

使用git fetch [remote-name]從遠(yuǎn)程倉(cāng)庫(kù)抓取數(shù)據(jù)挡育,注意fetch命令只是將遠(yuǎn)端的數(shù)據(jù)拉到本地倉(cāng)庫(kù)巴碗,并不自動(dòng)合并到當(dāng)前工作分支(關(guān)于分支稍后講解)
例如要抓取名為origin遠(yuǎn)程倉(cāng)庫(kù):

$ git fetch origin

推送數(shù)據(jù)到遠(yuǎn)程倉(cāng)庫(kù)

使用git push [remote-name] [branch-name]將本機(jī)的工作成果推送到遠(yuǎn)程倉(cāng)庫(kù)
例如要將本地的master分支推送到origin遠(yuǎn)程倉(cāng)庫(kù)上:

$ git push origin master

分支

也許到之前為止,大家會(huì)覺(jué)得Git和Svn除了實(shí)現(xiàn)原理不同以及實(shí)現(xiàn)了分布式之外即寒,在日常使用上并沒(méi)有什么太大的區(qū)別(甚至更繁瑣)橡淆。但接下來(lái)的分支,才是Git的精髓部分母赵。

為什么要使用分支

舉個(gè)簡(jiǎn)單的例子:假設(shè)你準(zhǔn)備開(kāi)發(fā)一個(gè)新功能逸爵,但是需要兩周才能完成,第一周你寫(xiě)了50%的代碼凹嘲,如果立刻提交师倔,由于代碼還沒(méi)寫(xiě)完,不完整的代碼庫(kù)會(huì)導(dǎo)致別人不能干活了周蹭。如果等代碼全部寫(xiě)完再一次提交趋艘,又存在丟失每天進(jìn)度的巨大風(fēng)險(xiǎn)。
于是你創(chuàng)建了一個(gè)屬于你自己的分支凶朗,別人看不到瓷胧,還繼續(xù)在原來(lái)的分支上正常工作,而你在自己的分支上干活棚愤,想提交就提交搓萧,直到開(kāi)發(fā)完畢后,再一次性合并到原來(lái)的分支上宛畦,這樣矛绘,既安全,又不影響別人工作刃永。
相比于Svn等工具货矮,Git創(chuàng)建、切換分支的開(kāi)銷是非常小的斯够,Git鼓勵(lì) 頻繁使用分支

分支的原理

要理解分支囚玫,需要繼續(xù)深入一下Git的工作原理

Git如何儲(chǔ)存數(shù)據(jù)

在Git中提交時(shí),會(huì)保存一個(gè)提交對(duì)象(commit object)读规,該對(duì)象包含一個(gè)指向暫存內(nèi)容快照的指針抓督,并同時(shí)包含本次提交的作者等相關(guān)附屬信息,包含零個(gè)或多個(gè)指向該提交對(duì)象的父對(duì)象指針(首次提交是沒(méi)有直接祖先的束亏,普通提交有一個(gè)祖先铃在,由兩個(gè)或多個(gè)分支合并產(chǎn)生的提交則有多個(gè)祖先)。

假設(shè)在工作目錄中有三個(gè)文件已經(jīng) 修改 過(guò),準(zhǔn)備將它們暫存后提交定铜。
git add暫存操作時(shí)阳液,會(huì)對(duì) 每一個(gè)文件 計(jì)算校驗(yàn)和,然后把當(dāng)前版本的文件快照使用 blog對(duì)象 保存到Git倉(cāng)庫(kù)中(為提高性能揣炕,若文件沒(méi)有變化帘皿,Git不會(huì)再次保存)。將它們的SHA-1校驗(yàn)和加入到暫存區(qū)域等待提交畸陡。
git commit提交操作鹰溜,時(shí),Git首先會(huì)計(jì)算 每一個(gè)子目錄 的校驗(yàn)和丁恭,然后將這些校驗(yàn)和保存為 tree對(duì)象 曹动。 然后Git會(huì)創(chuàng)建一個(gè) commit對(duì)象 ,它包含指向這個(gè)樹(shù)對(duì)象的指針及注釋牲览、提交人仁期、郵箱等信息。
現(xiàn)在竭恬,Git倉(cāng)庫(kù)中有五個(gè)對(duì)象:三個(gè)blob 對(duì)象(保存著文件快照);一個(gè)樹(shù)對(duì)象(記錄著目錄結(jié)構(gòu)和blob對(duì)象索引)以及一個(gè)提交對(duì)象(包含著指向前述樹(shù)對(duì)象的指針和所有提交信息)跛蛋。

單個(gè)提交對(duì)象在倉(cāng)庫(kù)中的數(shù)據(jù)結(jié)構(gòu):


多個(gè)提交對(duì)象之間的鏈接關(guān)系:

分支是什么

Git 中的分支,其實(shí)本質(zhì)上僅僅是個(gè)指向commit對(duì)象的可變指針痊硕。Git會(huì)使用master作為分支的默認(rèn)名字赊级。在若干次提交后,你其實(shí)已經(jīng)有了一個(gè)指向最后一次commit對(duì)象的master分支岔绸。它在每次提交的時(shí)候都會(huì)自動(dòng)向前移動(dòng)理逊。

創(chuàng)建名為testing的新的分支,本質(zhì)上就是創(chuàng)建一個(gè)指針盒揉,可以使用git branch命令:

$ git branch testing

當(dāng)前工作在哪個(gè)分支

Git 是如何知道你當(dāng)前在哪個(gè)分支上工作的呢晋被?其實(shí)答案也很簡(jiǎn)單,它還保存著一個(gè)名為HEAD的特別指針刚盈。它是一個(gè)指向你正在工作中的本地分支的指針羡洛。


切換分支時(shí)發(fā)生了什么

切換分支,本質(zhì)上就是移動(dòng)HEAD指針藕漱。
要切換到其他分支欲侮,可以執(zhí)行git checkout命令。我們現(xiàn)在轉(zhuǎn)換到剛才新建的testing分支:

$ git checkout testing

分支切換的實(shí)際操作

為了更好的理解分支肋联,我們接下來(lái)模擬實(shí)際工作中的場(chǎng)景威蕉,進(jìn)行一系列的切換操作。
現(xiàn)在我們已經(jīng)處于testing分支了橄仍,目前testing分支和master分支都是指向同一個(gè)commit韧涨,所以我們的工作區(qū)的內(nèi)容現(xiàn)在還沒(méi)有什么變化牍戚。
現(xiàn)在,我們要在testing分支上做一些文件修改虑粥,然后commit:

echo "testing branch">>readme.txt
git commit -a -m "modify on testing branch"


提交后如孝,產(chǎn)生了一個(gè)新的commit對(duì)象,并且HEAD隨著當(dāng)前testing分支一起向前移動(dòng)舀奶。而master分支則是停在原地不動(dòng)暑竟。

我們可以試著使用git checkout命令切回master分支斋射,看看發(fā)生了什么:

$ git checkout master


這條命令做了兩件事:

  1. 它把HEAD指針移回到 master 分支育勺。
  2. 把工作目錄中的文件換成了master分支所指向的快照內(nèi)容。

我們?cè)囍趍aster上再做一些改動(dòng)并commit:

echo "testing master">>readme.txt
git commit -a -m "modify on master branch"


現(xiàn)在分支變成了上圖所示罗岖,我們可以在master與testing間隨時(shí)切換涧至,并修改工作區(qū)的文件內(nèi)容。必要時(shí)再將這兩個(gè)分支合并桑包。

分支新建與合并的實(shí)際操作

接下來(lái)南蓬,再以一個(gè)比較長(zhǎng)的真實(shí)的工作場(chǎng)景進(jìn)行舉例

我們首先在master分支上進(jìn)行工作,并提交了幾次更新哑了,測(cè)試無(wú)誤后編譯發(fā)布至生產(chǎn)系統(tǒng)赘方。


之后我們決定要修補(bǔ)問(wèn)題追蹤系統(tǒng)上的53號(hào)問(wèn)題,這時(shí)可以使用git checkout -b命令快速創(chuàng)建一個(gè)分支并切換過(guò)去:

$ git checkout -b iss53

這相當(dāng)于執(zhí)行了下面這兩條命令:

$ git branch iss53
$ git checkout iss53

我們?cè)趇ss53分支上寫(xiě)了一些代碼弱左,并commit

$ vi index.html
$ git commit -a -m 'fixed the broken email address'

iss53上的工作還沒(méi)完成窄陡,突然接到通知,生產(chǎn)系統(tǒng)有一個(gè)緊急BUG需要立刻修復(fù)拆火。所以我們首先切回master分支跳夭,然后在master的基礎(chǔ)上,又新建出一個(gè)hotfix分支來(lái)修復(fù)BUG们镜。

$ git checkout master    #回到master分支
$ git checkout -b hotfix    #新建一個(gè)hotfix分支币叹,并切過(guò)去
$ vim index.html    #修改一些東西,修復(fù)BUG
$ git commit -a -m 'fixed the broken email address'    #提交hotfix

在hotfix分支上搞定BUG之后模狭,我們切回master分支颈抚,使用git merge把剛才的hotfix合并進(jìn)來(lái)

$ git checkout master  #切換回master分支
$ git merge hotfix    #將hotfix分支的修改,合并到當(dāng)前master分支來(lái)(注意merge的方向嚼鹉,是從其它分支邪意,合到當(dāng)前分支)。
Updating f42c576..3a0874c
Fast-forward
 README | 1 -
 1 file changed, 1 deletion(-)

備注:本次合并時(shí)出現(xiàn)了“Fast forward”的提示反砌。由于當(dāng)前 master 分支所在的提交對(duì)象是要并入的 hotfix 分支的直接上游雾鬼,Git 只需把 master 分支指針直接右移。換句話說(shuō)宴树,如果順著一個(gè)分支走下去可以到達(dá)另一個(gè)分支的話策菜,那么 Git在合并兩者時(shí),只會(huì)簡(jiǎn)單地把指針右移,因?yàn)檫@種單線的歷史分支不存在任何需要解決的分歧又憨,所以這種合并過(guò)程可以稱為快進(jìn)(Fast forward)翠霍。

這時(shí)hotfix分支已經(jīng)沒(méi)用了,可以刪掉了

$ git branch -d hotfix    #只是刪除了一個(gè)指針

現(xiàn)在回到之前未完成的53號(hào)問(wèn)題上蠢莺,繼續(xù)寫(xiě)一些代碼

$ git checkout iss53
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'

在問(wèn)題53相關(guān)的工作完成之后寒匙,可以合并回master分支。實(shí)際操作同前面合并hotfix分支差不多躏将,只需回到master分支锄弱,運(yùn)行g(shù)it merge命令指定要合并進(jìn)來(lái)的分支。

$ git checkout master
$ git merge iss53
Auto-merging README
Merge made by the 'recursive' strategy.
 README | 1 +
 1 file changed, 1 insertion(+)


請(qǐng)注意祸憋,這次合并操作的底層實(shí)現(xiàn)会宪,并不同于之前 hotfix 的并入方式。因?yàn)檫@次你的開(kāi)發(fā)歷史是從更早的地方開(kāi)始分叉的蚯窥。由于當(dāng)前 master 分支所指向的提交對(duì)象(C4)并不是 iss53 分支的直接祖先掸鹅,Git 不得不進(jìn)行一些額外處理。就此例而言拦赠,Git 會(huì)用兩個(gè)分支的末端(C4 和 C5)以及它們的共同祖先(C2)進(jìn)行一次簡(jiǎn)單的三方合并計(jì)算巍沙。


這次,Git 沒(méi)有簡(jiǎn)單地把分支指針右移荷鼠,而是對(duì)三方合并后的結(jié)果重新做一個(gè)新的快照句携,并自動(dòng)創(chuàng)建一個(gè)指向它的提交對(duì)象(C6)。這個(gè)提交對(duì)象比較特殊颊咬,它有兩個(gè)祖先(C4 和 C5)务甥。

有時(shí)候合并操作并不會(huì)如此順利。如果在不同的分支中都修改了同一個(gè)文件的同一部分喳篇,需要手工來(lái)處理沖突敞临。

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Git作了合并,但沒(méi)有提交麸澜,它會(huì)停下來(lái)等你解決沖突挺尿。

$ git status
On branch master
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:      index.html

no changes added to commit (use "git add" and/or "git commit -a")

任何包含未解決沖突的文件都會(huì)以未合并(unmerged)的狀態(tài)列出。Git 會(huì)在有沖突的文件里加入標(biāo)準(zhǔn)的沖突解決標(biāo)記炊邦。

$ vi index.html
<<<<<<< HEAD
<div id="footer">contact : email.support@github.com</div>
=======
<div id="footer">
  please contact us at support@github.com
</div>
>>>>>>> iss53

可以看到 ======= 隔開(kāi)的上半部分是 HEAD编矾,即master,下半部分是在iss53分支中的內(nèi)容馁害。
手工合并代碼后窄俏,把 <<<<<<<,======= 和 >>>>>>> 這些行也一并刪除碘菜。這時(shí)可以用git commit來(lái)提交了凹蜈。

分支策略

實(shí)際開(kāi)發(fā)中限寞,對(duì)于分支的管理,已經(jīng)有很多最佳實(shí)踐仰坦,大多數(shù)情況下履植,我們只需要遵守一些基本原則:

  • 首先,master分支應(yīng)該是非常穩(wěn)定的悄晃,也就是僅用來(lái)發(fā)布新版本玫霎,平時(shí)不能在上面工作。
  • 平時(shí)的開(kāi)發(fā)工作都放在dev分支上妈橄,也就是說(shuō)庶近,dev分支是不穩(wěn)定的。到某個(gè)時(shí)候眷细,比如測(cè)試通過(guò)拦盹,需要1.2版本發(fā)布時(shí)鹃祖,再把dev分支合并到master上溪椎,在master分支編譯發(fā)布1.2版本。
  • 針對(duì)新需求恬口、修復(fù)等具體的任務(wù)校读,每次都在dev分支上開(kāi)一個(gè)新的任務(wù)分支出來(lái),工作完成后祖能,再向dev分支上合并就可以了歉秫。名稱沒(méi)有特別的規(guī)范,可以是人名养铸,例如:zhangsan雁芙,也可以是任務(wù)名、需求編號(hào)等钞螟,例如:iss03兔甘、feature04、hotfix鳞滨。


遠(yuǎn)程分支

之前討論過(guò)遠(yuǎn)程倉(cāng)庫(kù)洞焙,接著又學(xué)習(xí)了分支,當(dāng)二者結(jié)合到一起時(shí)拯啦,又會(huì)產(chǎn)生一些有趣的東西澡匪。

遠(yuǎn)程分支的概念

遠(yuǎn)程分支(remote branch),即遠(yuǎn)程倉(cāng)庫(kù)中的分支。同步到本地后褒链,與本地分支不同的是唁情,它們 無(wú)法移動(dòng) ;且只有在Git進(jìn)行網(wǎng)絡(luò)交互時(shí)才會(huì)更新甫匹。遠(yuǎn)程分支就像是書(shū)簽甸鸟,提醒著你上次連接遠(yuǎn)程倉(cāng)庫(kù)時(shí)上面各分支的位置夯巷。我們用 (遠(yuǎn)程倉(cāng)庫(kù)名)/(分支名) 這樣的形式表示遠(yuǎn)程分支(例如origin/master)。

如果我們?cè)诒镜豰aster分支做了些改動(dòng)哀墓,與此同時(shí)趁餐,其他人向遠(yuǎn)程倉(cāng)庫(kù)推送了他們的更新,那么服務(wù)器上的master分支就會(huì)向前推進(jìn)篮绰,而于此同時(shí)后雷,我們?cè)诒镜氐奶峤粴v史正朝向不同方向發(fā)展。(不過(guò)只要你不和服務(wù)器通訊吠各,你的 origin/master 指針仍然保持原位不會(huì)移動(dòng)臀突。)

可以運(yùn)行git fetch origin來(lái)同步遠(yuǎn)程服務(wù)器上的數(shù)據(jù)到本地。該命令首先找到origin是哪個(gè)服務(wù)器贾漏,然后從上面獲取你尚未擁有的數(shù)據(jù)候学,更新你本地的數(shù)據(jù)庫(kù),然后把origin/master的指針移到它最新的位置上纵散。

可以使用git remote命令查看遠(yuǎn)程倉(cāng)庫(kù)的詳情

$ git remote -v    #列出遠(yuǎn)程服務(wù)器清單
origin  mobgit@134.32.51.60:learngit.git (fetch)
origin  mobgit@134.32.51.60:learngit.git (push)

$ git remote show origin   #查詢某一個(gè)遠(yuǎn)程服務(wù)器的詳情
* remote origin
  Fetch URL: mobgit@134.32.51.60:learngit.git
  Push  URL: mobgit@134.32.51.60:learngit.git
  HEAD branch (remote HEAD is ambiguous, may be one of the following):
    dev
    master
  Remote branches:
    dev    tracked
    master tracked
  Local branch configured for 'git pull':
    master merges with remote master
  Local ref configured for 'git push':
    master pushes to master (up to date)

跟蹤遠(yuǎn)程分支

從遠(yuǎn)程分支checkout出來(lái)的本地分支梳码,稱為跟蹤分支 (tracking branch)。跟蹤分支是一種和某個(gè)遠(yuǎn)程分支有直接聯(lián)系的本地分支伍掀。
在跟蹤分支里輸入 git push掰茶,Git 會(huì)自行推斷應(yīng)該向哪個(gè)服務(wù)器的哪個(gè)分支推送數(shù)據(jù)。同樣蜜笤,在這些分支里運(yùn)行 git pull 會(huì)獲取所有遠(yuǎn)程索引濒蒋,并把它們的數(shù)據(jù)都合并到本地分支中來(lái)。

在克隆倉(cāng)庫(kù)時(shí)把兔,Git 通常會(huì)自動(dòng)創(chuàng)建一個(gè)名為 master 的分支來(lái)跟蹤 origin/master沪伙。這正是 git push 和 git pull 一開(kāi)始就能正常工作的原因。

$ git checkout -b serverfix origin/serverfix
或簡(jiǎn)化為:
$ git checkout --track origin/serverfix

這會(huì)新建并切換到serverfix本地分支县好,其內(nèi)容同遠(yuǎn)程分支origin/serverfix一致围橡。

推送本地分支

要想和其他人分享某個(gè)本地分支,你需要把它推送到一個(gè)你擁有寫(xiě)權(quán)限的遠(yuǎn)程倉(cāng)庫(kù)聘惦。
例如本地有一個(gè)serverfix分支需要和他人一起開(kāi)發(fā)某饰,可以運(yùn)行 git push (遠(yuǎn)程倉(cāng)庫(kù)名) (分支名):

$ git push origin serverfix
Counting objects: 20, done.
Compressing objects: 100% (14/14), done.
Writing objects: 100% (15/15), 1.74 KiB, done.
Total 15 (delta 5), reused 0 (delta 0)
To git@github.com:schacon/simplegit.git
 * [new branch]      serverfix -> serverfix

或者加入--set-upstream設(shè)置跟蹤后,以后直接使用git push就可以推送了:

git push --set-upstream origin serverfix

GitHub

[GitHub](https://github.com)是一個(gè)面向開(kāi)源及私有軟件項(xiàng)目的托管平臺(tái)善绎,因?yàn)橹恢С諫it作為唯一的版本庫(kù)格式進(jìn)行托管黔漂,故名GitHub。


GitHub本身沒(méi)有什么好學(xué)的禀酱,隨便看就知道怎么用了 知乎:怎樣使用GitHub
重點(diǎn)是炬守,GitHub上有非常多優(yōu)秀的個(gè)人項(xiàng)目值得我們學(xué)習(xí),我們也可以將自已的代碼發(fā)布上去剂跟〖跬荆可以看成是程序員的博客吧酣藻,只貼代碼,不廢話鳍置。
在GitHub上發(fā)布開(kāi)源項(xiàng)目是免費(fèi)的辽剧,但是私有項(xiàng)目收費(fèi)。

GitLab

GitLab是一個(gè)用Ruby on Rails寫(xiě)的開(kāi)源的版本管理系統(tǒng)税产,實(shí)現(xiàn)一個(gè)自托管的Git項(xiàng)目倉(cāng)庫(kù)怕轿,可通過(guò)Web界面進(jìn)行訪問(wèn)公開(kāi)的或者私人項(xiàng)目。它擁有與Github類似的功能辟拷,能夠?yàn)g覽源代碼撞羽,管理缺陷和注釋怯屉。
可以管理團(tuán)隊(duì)對(duì)倉(cāng)庫(kù)的訪問(wèn)射众,它非常易于瀏覽提交過(guò)的版本并提供一個(gè)文件歷史庫(kù)。團(tuán)隊(duì)成員可以利用內(nèi)置的簡(jiǎn)單聊天程序(Wall)進(jìn)行交流沪哺。它還提供一個(gè)代碼片段收集功能可以輕松實(shí)現(xiàn)代碼復(fù)用隅俘,便于日后有需要的時(shí)候進(jìn)行查找邻奠。
GitLab是目前搭建內(nèi)部Git服務(wù)器的首選,當(dāng)然如果要求不高的話考赛,我們也可以直接使用SSH協(xié)議來(lái)快速搭建Git服務(wù)端惕澎。

常用Git命令清單


更多內(nèi)容請(qǐng)直接參考 阮一峰的網(wǎng)絡(luò)日志

推薦文檔

不要指忘2小時(shí)的培訓(xùn)能帶來(lái)多大的收益莉测,最簡(jiǎn)單高效的方式颜骤,還是要多看優(yōu)秀的文檔。
本文大量參(chao)考(xi)了以下兩部文檔:
廖雪峰的在線教程 適合快速上手
Pro Git中文版 中文第一版

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捣卤,一起剝皮案震驚了整個(gè)濱河市忍抽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌董朝,老刑警劉巖鸠项,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異子姜,居然都是意外死亡祟绊,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門哥捕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)牧抽,“玉大人,你說(shuō)我怎么就攤上這事遥赚⊙锸妫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵凫佛,是天一觀的道長(zhǎng)讲坎。 經(jīng)常有香客問(wèn)我孕惜,道長(zhǎng),這世上最難降的妖魔是什么晨炕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任衫画,我火速辦了婚禮,結(jié)果婚禮上瓮栗,老公的妹妹穿的比我還像新娘碧磅。我一直安慰自己,他們只是感情好遵馆,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布鲸郊。 她就那樣靜靜地躺著,像睡著了一般货邓。 火紅的嫁衣襯著肌膚如雪秆撮。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天换况,我揣著相機(jī)與錄音职辨,去河邊找鬼。 笑死戈二,一個(gè)胖子當(dāng)著我的面吹牛舒裤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播觉吭,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼腾供,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了鲜滩?” 一聲冷哼從身側(cè)響起伴鳖,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎徙硅,沒(méi)想到半個(gè)月后榜聂,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嗓蘑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年须肆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桩皿。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡豌汇,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出业簿,到底是詐尸還是另有隱情瘤礁,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布梅尤,位于F島的核電站柜思,受9級(jí)特大地震影響岩调,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赡盘,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一号枕、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧陨享,春花似錦葱淳、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至定硝,卻和暖如春皿桑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蔬啡。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工诲侮, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人箱蟆。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓沟绪,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親空猜。 傳聞我的和親對(duì)象是個(gè)殘疾皇子绽慈,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • Git是目前最流行的版本管理系統(tǒng),也是最先進(jìn)的分布式版本控制系統(tǒng)(distributed version cont...
    pro648閱讀 5,678評(píng)論 1 17
  • 1. 安裝 Github 查看是否安裝git: $ git config --global user.name "...
    Albert_Sun閱讀 13,632評(píng)論 9 163
  • 今天媽媽回老家抄肖,我一個(gè)人在家?guī)蓚€(gè)兒子久信,以前哥哥也是我自己一個(gè)人帶大的,沒(méi)覺(jué)得怎么辛苦漓摩,可是如今一個(gè)人帶弟弟,確感...
    守望撒哈拉閱讀 176評(píng)論 0 0
  • 目標(biāo):種出理想的伴侶 感恩冥想: 1入客、感恩今天的我又瘦了兩斤管毙,101斤了,雖然很開(kāi)心桌硫,但是身體還是不好夭咬。 2、感恩...
    小兔兔姐姐愛(ài)吃胡蘿卜閱讀 116評(píng)論 0 0