Git 使用指南

[TOC]

Git

@(24.1 Git)[git]

工作原理

直接記錄快照,而非差異比較
Git 只關(guān)心文件數(shù)據(jù)的整體是否發(fā)生變化钾虐,大多數(shù)其他系統(tǒng)則只關(guān)心文件內(nèi)容的具體差異噪窘,每次記錄有哪些文件作了更新,以及更新了什么內(nèi)容效扫,每個(gè)版本都是每個(gè)文件相對于上個(gè)版本更新了哪些內(nèi)容倔监。
Git 并不保存這些前后變化的差異數(shù)據(jù):實(shí)際上,Git 更像是把變化后的文件作快照菌仁,記錄在一個(gè)微型的文件系統(tǒng)中浩习。每次提交更新,都會縱覽一遍所有文件的指紋信息并對文件作一次快照济丘,然后保存一個(gè)指向這次快照的索引谱秽。為提高性能,若文件沒有變化摹迷,Git 不會再次保存快照怠苔,而只對上次保存的快照作一鏈接(指針)露氮。

git

Git 更像一個(gè)小型的文件系統(tǒng)偶房,同時(shí)提供許多以此為基礎(chǔ)的超強(qiáng)工具垃环。

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

Git 使用 SHA-1 算法計(jì)算數(shù)據(jù)的校驗(yàn)和,通過對文件的內(nèi)容或目錄的結(jié)構(gòu)計(jì)算出一個(gè) SHA-1 哈希值异赫,作為指紋字符串,Git 的工作完全依賴于這類指紋字串头岔,所有保存在 Git 數(shù)據(jù)庫中的東西都使用此哈希值作為索引塔拳,而不是靠文件名。

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

  1. 工作目錄
  2. 暫存區(qū)域
  3. 本地倉庫
    對于任何一個(gè)文件峡竣,在 Git 內(nèi)都只有三種狀態(tài):已提交(committed)靠抑,已修改(modified)和已暫存(staged)。已提交表示該文件已經(jīng)被安全地保存在本地?cái)?shù)據(jù)庫中了适掰;已修改表示修改了某個(gè)文件颂碧,但還沒有提交保存;已暫存表示把已修改的文件放在下次提交時(shí)要保存的清單中类浪。
    從項(xiàng)目中取出某個(gè)版本的所有文件和目錄载城,用以開始后續(xù)工作的叫做工作目錄。這些文件實(shí)際上都是從 Git 目錄中的壓縮對象數(shù)據(jù)庫中提取出來的费就,接下來就可以在工作目錄中對這些文件進(jìn)行編輯诉瓦。

所謂的暫存區(qū)域只不過是個(gè)簡單的文件,一般都放在 Git 目錄中。有時(shí)候人們會把這個(gè)文件叫做索引文件睬澡,不過標(biāo)準(zhǔn)說法還是叫暫存區(qū)域固额。

基本的 Git 工作流程如下:

  1. 在工作目錄中修改某些文件。
  2. 對修改后的文件進(jìn)行快照煞聪,然后保存到暫存區(qū)域斗躏。
  3. 提交更新,將保存在暫存區(qū)域的文件快照永久轉(zhuǎn)儲到 Git 目錄中昔脯。

配置

用戶信息

第一個(gè)要配置的是你個(gè)人的用戶名稱和電子郵件地址瑟捣。這兩條配置很重要,每次 Git 提交時(shí)都會引用這兩條信息栅干,說明是誰提交了更新迈套,所以會隨更新內(nèi)容一起被永久納入歷史記錄:

$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com

如果用了 --global 選項(xiàng),那么更改的配置文件就是位于你用戶主目錄下的那個(gè)碱鳞,以后你所有的項(xiàng)目都會默認(rèn)使用這里配置的用戶信息桑李。如果要在某個(gè)特定的項(xiàng)目中使用其他名字或者電郵,只要去掉 --global 選項(xiàng)重新配置即可窿给,新的設(shè)定保存在當(dāng)前項(xiàng)目的 .git/config 文件里贵白。

文本編輯器

接下來要設(shè)置的是默認(rèn)使用的文本編輯器。Git 需要你輸入一些額外消息的時(shí)候崩泡,會自動調(diào)用一個(gè)外部文本編輯器給你用禁荒。默認(rèn)會使用操作系統(tǒng)指定的默認(rèn)編輯器,一般可能會是 Vi 或者 Vim角撞。如果你有其他偏好呛伴,比如 Emacs 的話,可以重新設(shè)置:

$ git config --global core.editor emacs

差異分析工具

還有一個(gè)比較常用的是谒所,在解決合并沖突時(shí)使用哪種差異分析工具热康。比如要改用 vimdiff 的話:

$ git config --global merge.tool vimdiff

查看配置信息

要檢查已有的配置信息,可以使用 git config --list 命令

基礎(chǔ)

初始化倉庫:git init
從現(xiàn)有倉庫克铝恿臁:git clone [url]

工作目錄操作

工作目錄下面的所有文件只有兩種狀態(tài):已跟蹤或未跟蹤姐军。
初次克隆某個(gè)倉庫時(shí),工作目錄中的所有文件都屬于已跟蹤文件尖淘,且狀態(tài)為未修改奕锌。
在編輯過某些文件之后,Git 將這些文件標(biāo)為已修改村生。我們逐步把這些修改過的文件放到暫存區(qū)域惊暴,直到最后一次性提交所有這些暫存起來的文件,如此重復(fù)梆造。

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

git status

跟蹤新文件&暫存已修改文件

使用命令 git add 開始跟蹤一個(gè)新文件:
git add README
此時(shí)再運(yùn)行 git status 命令缴守,會看到 README 文件已被跟蹤葬毫,并處于暫存狀態(tài):

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)
        new file:   README

只要在 “Changes to be committed” 這行下面的,就說明是已暫存狀態(tài)屡穗。如果此時(shí)提交贴捡,那么該文件此時(shí)此刻的版本將被留存在歷史記錄中。
git add命令還可以將修改過的文件添加到暫存區(qū)村砂。

忽略某些文件

創(chuàng)建一個(gè)名為 .gitignore 的文件在根目錄下烂斋,在其中設(shè)置忽略文件的數(shù)據(jù):

  • 所有空行或者以注釋符號 # 開頭的行都會被 Git 忽略。
  • 可以使用標(biāo)準(zhǔn)的 glob 模式匹配础废。
  • 匹配模式最后跟反斜杠(/)說明要忽略的是目錄汛骂。
  • 要忽略指定模式以外的文件或目錄,可以在模式前加上驚嘆號(!)取反评腺。
# 此為注釋 – 將被 Git 忽略
# 忽略所有 .a 結(jié)尾的文件
*.a
# 但 lib.a 除外
!lib.a
# 僅僅忽略項(xiàng)目根目錄下的 TODO 文件帘瞭,不包括 subdir/TODO
/TODO
# 忽略 build/ 目錄下的所有文件
build/
# 會忽略 doc/notes.txt 但不包括 doc/server/arch.txt
doc/*.txt
# ignore all .txt files in the doc/ directory
doc/**/*.txt

所謂的 glob 模式是指 shell 所使用的簡化了的正則表達(dá)式。星號(*)匹配零個(gè)或多個(gè)任意字符蒿讥;[abc] 匹配任何一個(gè)列在方括號中的字符(這個(gè)例子要么匹配一個(gè) a蝶念,要么匹配一個(gè) b,要么匹配一個(gè) c)芋绸;問號(?)只匹配一個(gè)任意字符媒殉;如果在方括號中使用短劃線分隔兩個(gè)字符,表示所有在這兩個(gè)字符范圍內(nèi)的都可以匹配(比如 [0-9] 表示匹配所有 0 到 9 的數(shù)字)摔敛。

查看已暫存和未暫存的更新

git status的顯示比較簡單廷蓉,僅僅是列出了修改過的文件,如果要查看具體修改了什么地方马昙,可以用git diff命令桃犬。
此命令比較的是工作目錄中當(dāng)前文件和暫存區(qū)域快照之間的差異,也就是修改之后還沒有暫存起來的變化內(nèi)容给猾。
若要看已經(jīng)暫存起來的文件和上次提交時(shí)的快照之間的差異疫萤,可以用 git diff --cached命令。
請注意敢伸,單單git diff不過是顯示還沒有暫存起來的改動,而不是這次工作和上次提交之間的差異恒削。所以有時(shí)候你一下子暫存了所有更新過的文件后池颈,運(yùn)行git diff 后卻什么也沒有,就是這個(gè)原因钓丰。

提交更新

git commit -m "..."
提交時(shí)記錄的是放在暫存區(qū)域的快照躯砰,任何還未暫存的仍然保持已修改狀態(tài),可以在下次提交時(shí)納入版本管理携丁。每一次運(yùn)行提交操作琢歇,都是對你項(xiàng)目作一次快照兰怠,以后可以回到這個(gè)狀態(tài),或者進(jìn)行比較李茫。

跳過使用暫存區(qū)域

盡管使用暫存區(qū)域的方式可以精心準(zhǔn)備要提交的細(xì)節(jié)揭保,但有時(shí)候這么做略顯繁瑣。Git 提供了一個(gè)跳過使用暫存區(qū)域的方式魄宏,只要在提交的時(shí)候秸侣,給 git commit 加上 -a 選項(xiàng),Git 就會自動把所有已經(jīng)跟蹤過的文件暫存起來一并提交宠互,從而跳過git add步驟:
git commit -a -m "..."

移除文件

要從 Git 中移除某個(gè)文件味榛,就必須要從已跟蹤文件清單中移除(確切地說,是從暫存區(qū)域移除)予跌,然后提交搏色。
先在文件系統(tǒng)中刪除該文件,然后在 Git 中移除 git rm log.txt券册。
如果刪除之前修改過并且已經(jīng)放到暫存區(qū)域的話频轿,則必須要用強(qiáng)制刪除選項(xiàng) -f(即 force 的首字母),以防誤刪除文件后丟失修改的內(nèi)容汁掠。
另外一種情況是略吨,我們想把文件從 Git 倉庫中刪除(亦即從暫存區(qū)域移除),但仍然希望保留在當(dāng)前工作目錄中考阱。換句話說翠忠,僅是從跟蹤清單中刪除。比如一些大型日志文件或者一堆 .a 編譯文件乞榨,不小心納入倉庫后秽之,要移除跟蹤但不刪除文件,以便稍后在 .gitignore 文件中補(bǔ)上吃既,用 --cached 選項(xiàng)即可:
$ git rm --cached readme.txt
后面可以列出文件或者目錄的名字考榨,也可以使用 glob 模式。比方說:
$ git rm log/\*.log
注意到星號 * 之前的反斜杠 \鹦倚,因?yàn)?Git 有它自己的文件模式擴(kuò)展匹配方式河质,所以我們不用 shell 來幫忙展開。
$ git rm \*~
會遞歸刪除當(dāng)前目錄及其子目錄中所有 ~ 結(jié)尾的文件震叙。

移動文件

$ git mv file_from file_to
其實(shí)掀鹅,運(yùn)行 git mv 就相當(dāng)于運(yùn)行了下面三條命令:

$ mv README.txt README
$ git rm README.txt
$ git add README

查看提交歷史

git log
git log 有許多選項(xiàng)可以幫助你搜尋感興趣的提交:
git log -p -2
-p 選項(xiàng)展開顯示每次提交的內(nèi)容差異,用 -2 則僅顯示最近的兩次更新媒楼。
單詞層面的對比:--word-diff
上下文( context )行數(shù)從默認(rèn)的 3 行乐尊,減為 1 行:-U1
僅顯示簡要的增改行數(shù)統(tǒng)計(jì):--stat
指定使用完全不同于默認(rèn)格式的方式展示提交歷史:-pretty=oneline 還有 short,full 和 fuller 參數(shù)可以用
用 oneline 或 format 時(shí)結(jié)合 --graph 選項(xiàng)划址,可以看到開頭多出一些 ASCII 字符串表示的簡單圖形扔嵌。

撤銷操作

任何時(shí)候限府,都有可能需要撤消剛才所做的某些操作。請注意痢缎,有些撤銷操作是不可逆的胁勺,所以請務(wù)必謹(jǐn)慎小心,一旦失誤牺弄,就有可能丟失部分工作成果姻几。

修改最后一次提交

可以使用 --amend 選項(xiàng)重新提交:

$ git commit --amend

實(shí)例,如果剛才提交時(shí)忘了暫存某些修改势告,可以先補(bǔ)上暫存操作蛇捌,然后再運(yùn)行 --amend 提交:

$ git commit -m 'initial commit'
$ git add forgotten_file
$ git commit --amend

上面的三條命令最終只是產(chǎn)生一個(gè)提交,第二個(gè)提交命令修正了第一個(gè)的提交內(nèi)容咱台。

取消已經(jīng)暫存的文件

$ git reset HEAD <file>
文件回到已修改未暫存狀態(tài)

取消對文件的修改

$ git checkout -- <file>

遠(yuǎn)程倉庫使用

查看當(dāng)前遠(yuǎn)程倉庫

$ git remote
在克隆完某個(gè)項(xiàng)目后络拌,至少可以看到一個(gè)名為 origin 的遠(yuǎn)程庫,Git 默認(rèn)使用這個(gè)名字來標(biāo)識你所克隆的原始倉庫:
也可以加上 -v 選項(xiàng)(此為 --verbose 的簡寫回溺,取首字母)春贸,顯示對應(yīng)的克隆地址:

$ git remote -v
origin  git://github.com/schacon/ticgit.git (fetch)
origin  git://github.com/schacon/ticgit.git (push)

添加遠(yuǎn)程倉庫

git remote add [shortname] [url]

$ git remote add pb git://github.com/paulboone/ticgit.git
$ git remote -v
origin  git://github.com/schacon/ticgit.git
pb  git://github.com/paulboone/ticgit.git

現(xiàn)在可以用字符串 pb 指代對應(yīng)的倉庫地址了。比如說遗遵,要抓取所有 Paul 有的萍恕,但本地倉庫沒有的信息,可以運(yùn)行 git fetch pb

$ git fetch pb
remote: Counting objects: 58, done.
remote: Compressing objects: 100% (41/41), done.
remote: Total 44 (delta 24), reused 1 (delta 0)
Unpacking objects: 100% (44/44), done.
From git://github.com/paulboone/ticgit
 * [new branch]      master     -> pb/master
 * [new branch]      ticgit     -> pb/ticgit

現(xiàn)在车要,Paul 的主干分支(master)已經(jīng)完全可以在本地訪問了允粤,對應(yīng)的名字是 pb/master,你可以將它合并到自己的某個(gè)分支翼岁,或者切換到這個(gè)分支类垫,看看有些什么有趣的更新。

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

$ git fetch [remote-name]
此命令會到遠(yuǎn)程倉庫中拉取所有你本地倉庫中還沒有的數(shù)據(jù)琅坡。運(yùn)行完成后悉患,你就可以在本地訪問該遠(yuǎn)程倉庫中的所有分支,將其中某個(gè)分支合并到本地榆俺,或者取出某個(gè)分支售躁,一探究竟。
如果是克隆了一個(gè)倉庫茴晋,此命令會自動將遠(yuǎn)程倉庫歸于 origin 名下迂求。所以,git fetch origin 會抓取從你上次克隆以來別人上傳到此遠(yuǎn)程倉庫中的所有更新(或是上次 fetch 以來別人提交的更新)晃跺。有一點(diǎn)很重要,需要記住毫玖,fetch 命令只是將遠(yuǎn)端的數(shù)據(jù)拉到本地倉庫掀虎,并不自動合并到當(dāng)前工作分支凌盯,只有當(dāng)你確實(shí)準(zhǔn)備好了,才能手工合并烹玉。
如果設(shè)置了某個(gè)分支用于跟蹤某個(gè)遠(yuǎn)端倉庫的分支(參見下節(jié)及第三章的內(nèi)容)驰怎,可以使用 git pull 命令自動抓取數(shù)據(jù)下來,然后將遠(yuǎn)端分支自動合并到本地倉庫中當(dāng)前分支二打。在日常工作中我們經(jīng)常這么用县忌,既快且好。實(shí)際上继效,默認(rèn)情況下 git clone 命令本質(zhì)上就是自動創(chuàng)建了本地的 master 分支用于跟蹤遠(yuǎn)程倉庫中的 master 分支(假設(shè)遠(yuǎn)程倉庫確實(shí)有 master 分支)症杏。所以一般我們運(yùn)行 git pull,目的都是要從原始克隆的遠(yuǎn)端倉庫中抓取數(shù)據(jù)后瑞信,合并到工作目錄中的當(dāng)前分支厉颤。

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

項(xiàng)目進(jìn)行到一個(gè)階段,要同別人分享目前的成果凡简,可以將本地倉庫中的數(shù)據(jù)推送到遠(yuǎn)程倉庫逼友。實(shí)現(xiàn)這個(gè)任務(wù)的命令很簡單: git push [remote-name] [branch-name]。如果要把本地的 master 分支推送到 origin 服務(wù)器上(再次說明下秤涩,克隆操作會自動使用默認(rèn)的 master 和 origin 名字)帜乞,可以運(yùn)行下面的命令:
$ git push origin master
只有在所克隆的服務(wù)器上有寫權(quán)限,或者同一時(shí)刻沒有其他人在推數(shù)據(jù)筐眷,這條命令才會如期完成任務(wù)黎烈。如果在你推數(shù)據(jù)前,已經(jīng)有其他人推送了若干更新浊竟,那你的推送操作就會被駁回怨喘。必須先把他們的更新抓取到本地,合并到自己的項(xiàng)目中振定,然后才可以再次推送必怜。

查看遠(yuǎn)程倉庫信息

通過命令 git remote show [remote-name] 查看某個(gè)遠(yuǎn)程倉庫的詳細(xì)信息,比如要看所克隆的 origin 倉庫后频,可以運(yùn)行:

$ git remote show origin
* remote origin
  URL: git://github.com/schacon/ticgit.git
  Remote branch merged with 'git pull' while on branch master
    master
  Tracked remote branches
    master
    ticgit

除了對應(yīng)的克隆地址外梳庆,它還給出了許多額外的信息。它友善地告訴你如果是在 master 分支卑惜,就可以用 git pull 命令抓取數(shù)據(jù)合并到本地膏执。另外還列出了所有處于跟蹤狀態(tài)中的遠(yuǎn)端分支。

遠(yuǎn)程倉庫的刪除和重命名

git remote rename pb paul
git remote rm paul

Git 分支

為了理解 Git 分支的實(shí)現(xiàn)方式露久,我們需要理解 Git 是如何儲存數(shù)據(jù)的更米。
Git 保持的不是文件差異或者變化量,而是一系列文件快照
在 Git 中提交時(shí)毫痕,會保存一個(gè)提交(commit)對象征峦,該對象包含一個(gè)指向暫存內(nèi)容快照的指針迟几,包含本次提交的作者等相關(guān)附屬信息,包含零個(gè)或多個(gè)指向該提交對象的父對象指針:首次提交是沒有直接祖先的栏笆,普通提交有一個(gè)祖先类腮,由兩個(gè)或多個(gè)分支合并產(chǎn)生的提交則有多個(gè)祖先。
當(dāng)使用 git commit 新建一個(gè)提交對象時(shí)蛉加,Git 會先計(jì)算每一個(gè)子目錄的校驗(yàn)和蚜枢,然后在 Git 倉庫中將這些目錄保存為樹(tree)對象。之后 Git 創(chuàng)建的提交對象针饥,除了包含相關(guān)提交信息以外厂抽,還包含著指向這個(gè)樹對象(項(xiàng)目根目錄)的指針,如此它就可以在將來需要的時(shí)候打厘,重現(xiàn)此次快照的內(nèi)容了修肠。
單個(gè)提交對象在倉庫中的數(shù)據(jù)結(jié)構(gòu)
作些修改后再次提交,那么這次的提交對象會包含一個(gè)指向上次提交對象的指針户盯。

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

現(xiàn)在來談?wù)劮种妒珿it 中的分支,本質(zhì)上僅僅是個(gè)指向提交對象的可變指針莽鸭,默認(rèn)的分支名字為 master吗伤。
分支其實(shí)就是從某個(gè)提交對象往回看的歷史

創(chuàng)建分支

$ git branch testing

會在當(dāng)前提交對象上新建一個(gè)分支指針

Git 如何知道當(dāng)前在哪個(gè)分支上工作:很簡單,Git 內(nèi)部有個(gè)名為 HEAD 的特別指針硫眨,指向正在工作中的本地分支的指針足淆,也就是傳說中的指向指針的指針。

如何切換分支:
git checkout testing
這樣 HEAD 就指向了 testing 分支

在 testing 分支上的提交會創(chuàng)建一個(gè)新的提交對象礁阁,而 master 依舊指向原來的提交對象巧号。

由于 Git 中的分支實(shí)際上僅是一個(gè)包含所指對象校驗(yàn)和(40 個(gè)字符長度 SHA-1 字串)的文件,所以創(chuàng)建和銷毀一個(gè)分支就變得非常廉價(jià)姥闭。說白了丹鸿,新建一個(gè)分支就是向一個(gè)文件寫入 41 個(gè)字節(jié)(外加一個(gè)換行符)那么簡單,當(dāng)然也就很快了棚品。
這和大多數(shù)版本控制系統(tǒng)形成了鮮明對比靠欢,它們管理分支大多采取備份所有項(xiàng)目文件到特定目錄的方式,所以根據(jù)項(xiàng)目文件數(shù)量和大小不同铜跑,可能花費(fèi)的時(shí)間也會有相當(dāng)大的差別门怪,快則幾秒,慢則數(shù)分鐘锅纺。而 Git 的實(shí)現(xiàn)與項(xiàng)目復(fù)雜度無關(guān)掷空,它永遠(yuǎn)可以在幾毫秒的時(shí)間內(nèi)完成分支的創(chuàng)建和切換。同時(shí),因?yàn)槊看翁峤粫r(shí)都記錄了祖先信息(parent 指針)拣帽,將來要合并分支時(shí)疼电,尋找恰當(dāng)?shù)暮喜⒒A(chǔ)(共同祖先)的工作其實(shí)已經(jīng)自然而然地?cái)[在那里了,所以實(shí)現(xiàn)起來非常容易减拭。Git 鼓勵(lì)開發(fā)者頻繁使用分支,正是因?yàn)橛兄@些特性作保障区丑。

合并分支

一個(gè)簡單的分支與合并的例子拧粪,實(shí)際工作中也會用到這樣的工作流程:

  1. 開發(fā)某個(gè)網(wǎng)站;
  2. 為實(shí)現(xiàn)某個(gè)新需求沧侥,創(chuàng)建一個(gè)分支可霎;
  3. 在這個(gè)分支上開展工作。
    假設(shè)此時(shí)宴杀,你突然接到一個(gè)電話說有個(gè)很嚴(yán)重的問題需要緊急修補(bǔ)癣朗,那么可以按照下面的方式處理:
  4. 返回到原先已經(jīng)發(fā)布到生產(chǎn)服務(wù)器上到分支;
  5. 為這次緊急修補(bǔ)創(chuàng)建一個(gè)新分支旺罢,并在其中修復(fù)問題旷余;
  6. 通過測試后,回到生產(chǎn)服務(wù)器所在的分支扁达,將修補(bǔ)分支合并進(jìn)來正卧,然后再推送到生產(chǎn)服務(wù)器上;
  7. 切換到之前實(shí)現(xiàn)新需求的分支跪解,繼續(xù)工作炉旷。
$ git checkout -b iss53
相當(dāng)于執(zhí)行下面這兩條命令:
$ git branch iss53
$ git checkout iss53

$ git checkout master
切換到生產(chǎn)服務(wù)器分支
$ git checkout -b hotfix

$ git checkout master
回到master分支
$ git merge hotfix
合并進(jìn)來
Updating f42c576..3a0874c
Fast-forward
 README | 1 -
 1 file changed, 1 deletion(-)

合并時(shí)出現(xiàn)了“Fast forward”的提示。由于當(dāng)前 master 分支所在的提交對象是要并入的 hotfix 分支的直接上游叉讥,Git 只需把 master 分支指針直接右移窘行。換句話說,如果順著一個(gè)分支走下去可以到達(dá)另一個(gè)分支的話图仓,那么 Git 在合并兩者時(shí)罐盔,只會簡單地把指針右移,因?yàn)檫@種單線的歷史分支不存在任何需要解決的分歧透绩,所以這種合并過程可以稱為快進(jìn)(Fast forward)翘骂。
現(xiàn)在最新的修改已經(jīng)在當(dāng)前 master 分支所指向的提交對象中了,可以部署到生產(chǎn)服務(wù)器上去了

master 分支和 hotfix 分支指向同一位置
在那個(gè)超級重要的修補(bǔ)發(fā)布以后帚豪,你想要回到被打擾之前的工作碳竟。由于當(dāng)前 hotfix 分支和 master 都指向相同的提交對象,所以 hotfix 已經(jīng)完成了歷史使命狸臣,可以刪掉了莹桅。

$ git branch -d hotfix
Deleted branch hotfix (was 3a0874c).

現(xiàn)在回到之前未完成的 iss53 問題修復(fù)分支上繼續(xù)工作

$ git checkout iss53
Switched to branch 'iss53'
$ vim index.html
$ git commit -a -m 'finished the new footer [issue 53]'
[iss53 ad82d7a] finished the new footer [issue 53]
 1 file changed, 1 insertion(+)

值得注意的是之前 hotfix 分支的修改內(nèi)容尚未包含到 iss53 中來。如果需要納入此次修補(bǔ),可以用 git merge master 把 master 分支合并到 iss53诈泼;或者等 iss53 完成之后懂拾,再將 iss53 分支中的更新并入 master。

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

這次合并操作的底層實(shí)現(xiàn)铐达,并不同于之前 hotfix 的并入方式岖赋。因?yàn)檫@次你的開發(fā)歷史是從更早的地方開始分叉的。由于當(dāng)前 master 分支所指向的提交對象(C4)并不是 iss53 分支的直接祖先瓮孙,Git 不得不進(jìn)行一些額外處理唐断。就此例而言,Git 會用兩個(gè)分支的末端(C4 和 C5)以及它們的共同祖先(C2)進(jìn)行一次簡單的三方合并計(jì)算杭抠。

Git 為分支合并自動識別出最佳的同源合并點(diǎn)脸甘。

這次,Git 沒有簡單地把分支指針右移偏灿,而是對三方合并后的結(jié)果重新做一個(gè)新的快照丹诀,并自動創(chuàng)建一個(gè)指向它的提交對象(C6)。這個(gè)提交對象比較特殊翁垂,它有兩個(gè)祖先(C4 和 C5)铆遭。

既然之前的工作成果已經(jīng)合并到 master 了,那么 iss53 也就沒用了沮峡。你可以就此刪除它疚脐,并在問題追蹤系統(tǒng)里關(guān)閉該問題。
$ git branch -d iss53

遇到?jīng)_突時(shí)到分支合并

有時(shí)候合并操作并不會如此順利邢疙。如果在不同的分支中都修改了同一個(gè)文件的同一部分棍弄,Git 就無法干凈地把兩者合到一起。如果你在解決問題 #53 的過程中修改了 hotfix 中修改的部分疟游,將得到類似下面的結(jié)果:

$ 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 作了合并呼畸,但沒有提交,它會停下來等你解決沖突颁虐。要看看哪些文件在合并時(shí)發(fā)生沖突蛮原,可以用 git status 查閱:

$ 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")

任何包含未解決沖突的文件都會以未合并(unmerged)的狀態(tài)列出。Git 會在有沖突的文件里加入標(biāo)準(zhǔn)的沖突解決標(biāo)記另绩,可以通過它們來手工定位并解決這些沖突儒陨。可以看到此文件包含類似下面這樣的部分:

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

可以看到 ======= 隔開的上半部分笋籽,是 HEAD(即 master 分支蹦漠,在運(yùn)行 merge 命令時(shí)所切換到的分支)中的內(nèi)容,下半部分是在 iss53 分支中的內(nèi)容车海。解決沖突的辦法無非是二者選其一或者由你親自整合到一起笛园。比如你可以通過把這段內(nèi)容替換為下面這樣來解決:

<div id="footer">
please contact us at email.support@github.com
</div>

這個(gè)解決方案各采納了兩個(gè)分支中的一部分內(nèi)容,而且還刪除了 <<<<<<<,======= 和 >>>>>>> 這些行研铆。在解決了所有文件里的所有沖突后埋同,運(yùn)行 git add 將把它們標(biāo)記為已解決狀態(tài)(譯注:實(shí)際上就是來一次快照保存到暫存區(qū)域。)棵红。因?yàn)橐坏捍嫘琢蓿捅硎緵_突已經(jīng)解決。如果你想用一個(gè)有圖形界面的工具來解決這些問題窄赋,不妨運(yùn)行 git mergetool哟冬,它會調(diào)用一個(gè)可視化的合并工具并引導(dǎo)你解決所有沖突,再運(yùn)行一次 git status 來確認(rèn)所有沖突都已解決:

$ git status
On branch master
Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

        modified:   index.html

如果覺得滿意了忆绰,并且確認(rèn)所有沖突都已解決,也就是進(jìn)入了暫存區(qū)可岂,就可以用 git commit 來完成這次合并提交错敢。
如果想給將來看這次合并的人一些方便,可以修改該信息缕粹,提供更多合并細(xì)節(jié)稚茅。比如你都作了哪些改動,以及這么做的原因平斩。有時(shí)候裁決沖突的理由并不直接或明顯亚享,有必要略加注解。

管理分支

列出當(dāng)前分支清單:git branch
查看各個(gè)分支最后一個(gè)提交對象的信息:git branch -v
查看哪些分支已被并入當(dāng)前分支:git branch --merged

分布式工作流程

一般這種情況有個(gè)官方發(fā)布的項(xiàng)目倉庫绘面,開發(fā)者由此倉庫克隆出一個(gè)自己的公共倉庫欺税,然后將自己的提交推送上去,請求官方倉庫的維護(hù)者拉取更新合并到主項(xiàng)目揭璃。維護(hù)者在自己本地也有個(gè)克隆倉庫晚凿,可以將你的公共倉庫作為遠(yuǎn)程倉庫添加進(jìn)來,經(jīng)過測試無誤后合并到主干分支瘦馍,在推送到官方倉庫歼秽。

  1. 項(xiàng)目維護(hù)者可以推送數(shù)據(jù)到公共倉庫 blessed repository。
  2. 貢獻(xiàn)者克隆此倉庫情组,修訂或編寫新代碼燥筷。
  3. 貢獻(xiàn)者推送數(shù)據(jù)到自己的公共倉庫 developer public。
  4. 貢獻(xiàn)者給維護(hù)者發(fā)送郵件院崇,請求拉取自己的最新修訂肆氓。
  5. 維護(hù)者在自己本地的 integration manger 倉庫中,將貢獻(xiàn)者的倉庫加為遠(yuǎn)程倉庫亚脆,合并更新并做測試做院。
  6. 維護(hù)者將合并后的更新推送到主倉庫 blessed repository。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市键耕,隨后出現(xiàn)的幾起案子寺滚,更是在濱河造成了極大的恐慌,老刑警劉巖屈雄,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件村视,死亡現(xiàn)場離奇詭異,居然都是意外死亡酒奶,警方通過查閱死者的電腦和手機(jī)蚁孔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惋嚎,“玉大人杠氢,你說我怎么就攤上這事×砦椋” “怎么了鼻百?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長摆尝。 經(jīng)常有香客問我温艇,道長,這世上最難降的妖魔是什么堕汞? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任勺爱,我火速辦了婚禮,結(jié)果婚禮上讯检,老公的妹妹穿的比我還像新娘琐鲁。我一直安慰自己,他們只是感情好视哑,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布绣否。 她就那樣靜靜地躺著,像睡著了一般挡毅。 火紅的嫁衣襯著肌膚如雪蒜撮。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天跪呈,我揣著相機(jī)與錄音段磨,去河邊找鬼。 笑死耗绿,一個(gè)胖子當(dāng)著我的面吹牛苹支,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播误阻,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼债蜜,長吁一口氣:“原來是場噩夢啊……” “哼晴埂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起寻定,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤儒洛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后狼速,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琅锻,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年向胡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恼蓬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡僵芹,死狀恐怖处硬,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情拇派,我是刑警寧澤郁油,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站攀痊,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏拄显。R本人自食惡果不足惜苟径,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望躬审。 院中可真熱鬧棘街,春花似錦、人聲如沸承边。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽博助。三九已至险污,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間富岳,已是汗流浹背蛔糯。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窖式,地道東北人蚁飒。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像萝喘,于是被迫代替她去往敵國和親淮逻。 傳聞我的和親對象是個(gè)殘疾皇子琼懊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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

  • 1.git的安裝 1.1 在Windows上安裝Git msysgit是Windows版的Git,從https:/...
    落魂灬閱讀 12,652評論 4 54
  • Git是目前最流行的版本管理系統(tǒng)爬早,也是最先進(jìn)的分布式版本控制系統(tǒng)(distributed version cont...
    pro648閱讀 5,682評論 1 17
  • 1. 安裝 Github 查看是否安裝git: $ git config --global user.name "...
    Albert_Sun閱讀 13,644評論 9 163
  • 上午進(jìn)行語文第三單元測試哼丈,中午看班時(shí)將試卷批改出來。午寫時(shí)凸椿,發(fā)了試卷削祈,孫逸歌考了100分,她很開心脑漫,對我說...
    呵媽閱讀 246評論 0 1
  • 1髓抑、 月色如水,皎潔明亮的月光散落地面上优幸,帶來的寒意消散在盛夏酷暑中吨拍。 一條小路將地面綠色灌木分成兩塊,象蛇一樣蜿...
    老港閱讀 685評論 8 9