git分支

什么是git分支?

什么是git分支织狐?首先讓我們回顧一下提交對(duì)象斑举,一個(gè)提交對(duì)象(commit objects)包括:

  • 一系列文件在某個(gè)時(shí)間的快照。
  • 一系列指向父提交對(duì)象的索引助泽。
  • 一個(gè)SHA-1名字,這個(gè)名字40個(gè)字符長(zhǎng)嚎京,是獨(dú)一無(wú)二的嗡贺。
  • 作者的姓名和郵箱,以及提交時(shí)對(duì)提交的描述鞍帝。

事實(shí)上诫睬,“一系列文件在某個(gè)時(shí)間的快照”并不是直接存在于提交對(duì)象。在git中帕涌,blob對(duì)象保存著文件的快照摄凡,樹(shù)對(duì)象保存著目錄結(jié)構(gòu)和blob對(duì)象的索引,而提交對(duì)象保存指向樹(shù)對(duì)象的指針蚓曼。下圖是一個(gè)這三者關(guān)系的示意圖:

三個(gè)對(duì)象及其關(guān)系

那么git中的分支是什么呢亲澡?

git中的分支就像是你的文件的一份副本,你可以在需要的時(shí)候拷貝一份出來(lái)纫版,這樣你就得到了一個(gè)“分支”床绪,你可以在上面修改,修改完成之后再合并回去其弊。在一些版本控制軟件中實(shí)際情況確實(shí)是這樣会涎,然而在git中并非如此

在git中瑞凑,對(duì)分支的操作大部分只是在修改指向提交對(duì)象的heads。我們知道概页,heads是一個(gè)指向提交對(duì)象的指針籽御,分支操作中的大部分操作只需要修改heads的指向,即向heads文件中寫(xiě)入41個(gè)字符即可(40個(gè)SHA-1字符串和1個(gè)換行符)。與其他一些版本控制軟件采用的復(fù)制文件策略相比較技掏,git分支操作與文件大小無(wú)關(guān)铃将,操作迅速快捷。

指向提交對(duì)象的heads

創(chuàng)建分支

現(xiàn)在先來(lái)看看我們?cè)谀膫€(gè)分支哑梳,使用git branch命令查看當(dāng)前分支劲阎,命令選項(xiàng)-v顯示分支指向提交對(duì)象的校驗(yàn)和及其描述:

$ git branch
* master
$ git branch -v
* master 57b75e6 Add GitHub description.

從結(jié)果中看到,現(xiàn)在只有一個(gè)分支鸠真,叫做master悯仙。*表示當(dāng)前所在的分支,即HEAD的指向吠卷。

用圖簡(jiǎn)略表示如下:

僅有master分支

現(xiàn)在創(chuàng)建一條dev分支锡垄,使用git branch <branchname>命令:

$ git branch dev
$ git branch
  dev
* master

現(xiàn)在有了兩條分支:masterdev,目前我們?cè)?code>master分支祭隔。圖示如下:

創(chuàng)建一條dev分支

可見(jiàn)货岭,事實(shí)上只是創(chuàng)建了一個(gè)指向圖中提交對(duì)象C3的指針,使用git log --decorate可以查看heads的指向:

$ git log --oneline --decorate -3
57b75e6 (HEAD -> master, origin/master, dev) Add GitHub description.
beac1f4 make README.md more friendly.
14bd627 add two wrong line to README.md

master疾渴、遠(yuǎn)程originmasterdev指向57b75e6提交對(duì)象千贯,HEAD指向master

切換分支

現(xiàn)在切換到dev分支搞坝,使用git checkout <branchname>命令搔谴,在切換前請(qǐng)確保你的工作目錄是干凈的:

$ git checkout dev
Switched to branch 'dev'

這樣就切換到了dev分支,查看一下:

$ git branch
* dev
  master
$ git log --oneline --decorate -3
57b75e6 (HEAD -> dev, origin/master, master) Add GitHub description.
beac1f4 make README.md more friendly.
14bd627 add two wrong line to README.md

可以看到我們確實(shí)在dev分支瞄沙,HEAD確實(shí)指向了dev分支己沛。在切換分支時(shí),git會(huì)將分支所指向的提交對(duì)象的文件快照檢出到工作目錄距境,并且更改HEAD的指向申尼。目前分支情況圖示如下:

切換到dev分支

git checkout -b <branchname>可以創(chuàng)建<branchname>分支并且切換到它,相當(dāng)于執(zhí)行下面兩條命令:

$ git branch <branchname>
$ git checkout <branchname>

“快進(jìn)”合并

現(xiàn)在在dev分支垫桂,我們創(chuàng)建一個(gè)dev.md文件并且提交:

$ touch dev.md
$ git add dev.md
$ git commit -m "add dev.md"
[dev fd2e1cb] add dev.md
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 dev.md

查看一下各個(gè)分支所指:

$ git log --oneline --decorate -3
fd2e1cb (HEAD -> dev) add dev.md
57b75e6 (origin/master, master) Add GitHub description.
beac1f4 make README.md more friendly.

dev前進(jìn)了一個(gè)提交對(duì)象师幕,HEAD指向dev,其他分支并沒(méi)有更改诬滩,圖式如下:

dev新提交

現(xiàn)在切換到master霹粥,使用$ git checkout master命令,HEAD會(huì)指向master疼鸟,工作目錄中的文件將會(huì)被替換:

切換回master

合并分支使用git merge <branchname>命令后控,這個(gè)命令將<branchname>分支合并到當(dāng)前分支,現(xiàn)在我們?cè)?code>master分支空镜,執(zhí)行下面的命令將dev分支合并到master分支:

$ git merge dev
Updating 57b75e6..fd2e1cb
Fast-forward
 dev.md | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 dev.md

git告訴我們此次合并的方式是Fast-forward(快進(jìn))浩淘,此時(shí)分支情況如下:

合并dev分支

現(xiàn)在dev分支已經(jīng)被合并到master分支了捌朴。從上圖可以看出git僅僅是簡(jiǎn)單的更新了masterHEAD的指向,這是由于合并前master指向dev的直接上游张抄,這種合并方式叫做快進(jìn)(Fast-forward)砂蔽。

可以使用--no-ff選項(xiàng)避免使用“快進(jìn)”合并,這樣會(huì)形成一個(gè)新的合并提交署惯,類似下節(jié)講到的分之合并:

$ git merge --no-ff dev

現(xiàn)在dev分支已經(jīng)充分得發(fā)揮了自己的作用左驾,讓我們刪除它:

$ git branch -d dev
Deleted branch dev (was fd2e1cb).

如果一個(gè)分支沒(méi)有完全合并到當(dāng)前分支,那么git會(huì)阻止你刪除它极谊,如果確實(shí)要?jiǎng)h除它诡右,使用-D命令選項(xiàng):

$ git branch -D <branchname>

如果想要知道那些分支被合并了或者沒(méi)有合并,使用下面的命令:

$ git branch --merged       # 查看已經(jīng)被合并的分支
$ git branch --no-merged    # 查看還沒(méi)有被合并的分支

目前分支情況如下:

刪除dev分支

本文所講的例子整體過(guò)程圖示如下:

快進(jìn)合并

分支合并

現(xiàn)在創(chuàng)建一個(gè)testing分支并且切換到該分支:

$ git checkout -b testing
Switched to a new branch 'testing'

添加testing.md并提交怀酷,修改tesing.md并提交:

$ touch testing.md
$ git add testing.md
$ git commit -m "add testing.md"
[testing dd4555e] add testing.md
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 testing.md
$ echo "A file added in testing branch." > testing.md 
$ git commit -a -m "add description of testing.md"
[testing 40a00ae] add description of testing.md
 1 file changed, 1 insertion(+)

回到master分支并且修改dev.md

$ git checkout master 
Switched to branch 'master'
$ echo "A dev file." > dev.md
$ ls
dev.md  README.md
$ git commit -a -m "add description of dev.md"
[master 1b63c87] add description of dev.md
 1 file changed, 1 insertion(+)

現(xiàn)在兩條分支在分叉后都有新的提交:testing有兩個(gè)新的提交论悴,master有一個(gè)新的提交猪杭。怎樣在命令行查看呢乏冀?

$ git log --oneline --decorate --graph --all
* 1b63c87 (HEAD -> master) add description of dev.md
| * 40a00ae (testing) add description of testing.md
| * dd4555e add testing.md
|/  
* fd2e1cb add dev.md
* 57b75e6 (origin/master) Add GitHub description.

# 省略

可以看到劫哼,在fd2e1cb分支分叉,testing之后進(jìn)行了兩次提交样眠,master進(jìn)行了一次提交友瘤,目前我們?cè)?code>master分支。圖示如下:

合并提交1

現(xiàn)在將testing分支合并到master分支:

$ git merge testing
Merge made by the 'recursive' strategy.
 testing.md | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 testing.md
$ git log --oneline --decorate --graph --all
*   8425ef2 (HEAD -> master) Merge branch 'testing'
|\  
| * 40a00ae (testing) add description of testing.md
| * dd4555e add testing.md
* | 1b63c87 add description of dev.md
|/  
* fd2e1cb add dev.md
* 57b75e6 (origin/master) Add GitHub description.

# 省略

現(xiàn)在git幫我們合并了mastertesting檐束,并且生成了一個(gè)新的提交(你可能需要填寫(xiě)提交描述)辫秧,這個(gè)新提交的SHA-1校驗(yàn)和前七位是8425ef2。

git能夠幫我們自動(dòng)合并被丧,而不會(huì)產(chǎn)生沖突的原因是我們?cè)诓煌姆种е行薷牧瞬煌奈募讼罚藭r(shí)git會(huì)參考兩個(gè)分支所指的快照(testing40a00aemaster1b63c87)和兩個(gè)分支的共同祖先(fd2e1cb),自動(dòng)合并甥桂。參考的三個(gè)快照分別相當(dāng)于下圖的C6柿究、C7和C4.

新生成的提交叫做合并提交,相當(dāng)于下圖的C8.這個(gè)新提交擁有兩個(gè)父提交黄选。

合并提交2

好了蝇摸,現(xiàn)在刪掉testing分支吧:

$ git branch -d testing 
Deleted branch testing (was 40a00ae).

本文所講的分支合并的整體過(guò)程圖示如下:

分之合并

沖突解決

如果在不同分支中同一個(gè)文件的同一個(gè)地方做了修改,git就無(wú)法干凈利落地合并它們办陷。

創(chuàng)建一個(gè)新的分支iss1貌夕,在iss1分支中將README.md修改如下并且提交:

$ git checkout -b iss1
Switched to a new branch 'iss1'
$ vim README.md 
$ cat README.md 
# Hi, Git!

This is my first git project and i use it to learn git.

Git is a free and open source distributed version control system.
$ git commit -a -m "change README.md in iss1"
[iss1 d6801d6] change README.md in iss1
 1 file changed, 6 deletions(-)

切換到master分支,將README.md修改如下并且提交:

$ git checkout master
Switched to branch 'master'
$ vim README.md 
$ cat README.md 
# Hi, Git!

This is my first git project and i use it to learn git.

I LOVE GIT.
$ git commit -a -m "change README.md in master."
[master 63172f9] change README.md in master.
 1 file changed, 1 insertion(+), 7 deletions(-)
 $ git log --oneline --decorate --graph --all
* 63172f9 (HEAD -> master) change README.md in master.
| * d6801d6 (iss1) change README.md in iss1
|/  
*   8425ef2 Merge branch 'testing'

# 省略

現(xiàn)在將iss1分支合并到master分支:

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

git告訴我們說(shuō)自動(dòng)合并失敗民镜,原因是在README.md文件中有沖突啡专,并且提醒我們解決沖突后提交結(jié)果。

也就是說(shuō)制圈,git在遇到?jīng)_突時(shí)植旧,并不會(huì)創(chuàng)建一個(gè)合并提交辱揭,而是暫停下來(lái),等用戶解決沖突之后病附,由用戶提交。

含有沖突的文件被標(biāo)記為“未合并”(unmerged)狀態(tài)亥鬓,隨時(shí)可以使用git status來(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:   README.md

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

現(xiàn)在讓我們解決README.md中的沖突完沪,首先來(lái)看一看git剛剛所做的工作:

$ cat README.md 
# Hi, Git!

This is my first git project and i use it to learn git.

<<<<<<< HEAD
I LOVE GIT.
=======
Git is a free and open source distributed version control system.
>>>>>>> iss1

其中的一部分是git為我們標(biāo)記的沖突的部分:

<<<<<<< HEAD
I LOVE GIT.
=======
Git is a free and open source distributed version control system.
>>>>>>> iss1

=======的上半部分的是HEAD分支中的文件內(nèi)容,在其下半部分的是iss1分支中文件的內(nèi)容嵌戈。

現(xiàn)在讓我們將這部分修改如下:

I LOVE GIT.

這表示將丟棄iss1中的修改覆积,當(dāng)然你可以根據(jù)自己的喜好更改,你可以改成任意你需要的內(nèi)容熟呛。

現(xiàn)在將文件添加到暫存區(qū)宽档,并且查看狀態(tài):

$ git add README.md 
$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

nothing to commit, working directory clean

可見(jiàn),一旦沖突文件被添加到暫存區(qū)庵朝,它的“未合并”狀態(tài)就會(huì)被解除吗冤,即表示沖突已經(jīng)解決。

現(xiàn)在提交即可:

$ git commit -m "merge iss1"
[master 11f0f7a] merge iss1
$ git log --oneline --decorate --graph --all
*   11f0f7a (HEAD -> master) merge iss1
|\  
| * d6801d6 (iss1) change README.md in iss1
* | 63172f9 change README.md in master.
|/  
*   8425ef2 Merge branch 'testing'

# 省略

最后刪除iss1分支:

$ git branch -d iss1
Deleted branch iss1 (was d6801d6).

儲(chǔ)藏與清理

git在切換分支時(shí)必須保證當(dāng)前工作目錄是干凈的九府,如果現(xiàn)在做了一點(diǎn)更改椎瘟,不至于提交一次新的更新,但是卻必須更換到另一條分支上侄旬,怎么辦呢肺蔚?

git為我們提供了stash(儲(chǔ)藏)工具。

現(xiàn)在在master分支上對(duì)README.md作一些更改儡羔,并且將它儲(chǔ)藏起來(lái):

$ git status -s
 M README.md
$ git stash 
Saved working directory and index state WIP on master: 11f0f7a merge iss1
HEAD is now at 11f0f7a merge iss1
$ git status -s
$ 

在運(yùn)行git stash之后工作目錄就變干凈了宣羊,現(xiàn)在就可以切換到其他分支工作啦。

在其他分支工作完之后汰蜘,又回到master仇冯,怎樣繼續(xù)工作呢?

使用git stash list命令可以查看儲(chǔ)藏的列表:

$ git stash list
stash@{0}: WIP on master: 11f0f7a merge iss1

使用git stash apply <stashname>即可應(yīng)用鉴扫,如果<stashname>為空赞枕,則會(huì)應(yīng)用最新的儲(chǔ)藏:

$ git stash apply
$ git stash list
stash@{0}: WIP on master: 11f0f7a merge iss1
$ git stash apply
On branch master
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.md

no changes added to commit (use "git add" and/or "git commit -a")
$ git status -s
 M README.md

我們的更改又回來(lái)了,使用git stash drop <stashname>刪除相應(yīng)的儲(chǔ)藏坪创,如果<stashname>為空炕婶,則會(huì)刪除最新的儲(chǔ)藏:

$ git stash drop
Dropped refs/stash@{0} (939ab1d7c4f88fe2dd9b3420d0cf919a668eff23)
$ git stash list
$ 

可以使用git stash pop直接應(yīng)用最新的儲(chǔ)藏,同時(shí)刪除該儲(chǔ)藏莱预。

在git中柠掂,可以進(jìn)行多次儲(chǔ)藏,也可以在不同的分支應(yīng)用儲(chǔ)藏依沮。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末涯贞,一起剝皮案震驚了整個(gè)濱河市枪狂,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌宋渔,老刑警劉巖州疾,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異皇拣,居然都是意外死亡严蓖,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)氧急,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)颗胡,“玉大人,你說(shuō)我怎么就攤上這事吩坝《疽蹋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵钉寝,是天一觀的道長(zhǎng)弧呐。 經(jīng)常有香客問(wèn)我,道長(zhǎng)瘩蚪,這世上最難降的妖魔是什么泉懦? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮疹瘦,結(jié)果婚禮上崩哩,老公的妹妹穿的比我還像新娘。我一直安慰自己言沐,他們只是感情好邓嘹,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著险胰,像睡著了一般汹押。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上起便,一...
    開(kāi)封第一講書(shū)人閱讀 49,760評(píng)論 1 289
  • 那天棚贾,我揣著相機(jī)與錄音,去河邊找鬼榆综。 笑死妙痹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的鼻疮。 我是一名探鬼主播怯伊,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼判沟!你這毒婦竟也來(lái)了耿芹?” 一聲冷哼從身側(cè)響起崭篡,我...
    開(kāi)封第一講書(shū)人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎吧秕,沒(méi)想到半個(gè)月后琉闪,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡砸彬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年塘偎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拿霉。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖咱扣,靈堂內(nèi)的尸體忽然破棺而出绽淘,到底是詐尸還是另有隱情,我是刑警寧澤闹伪,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布沪铭,位于F島的核電站,受9級(jí)特大地震影響偏瓤,放射性物質(zhì)發(fā)生泄漏杀怠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一厅克、第九天 我趴在偏房一處隱蔽的房頂上張望赔退。 院中可真熱鬧,春花似錦证舟、人聲如沸硕旗。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)漆枚。三九已至,卻和暖如春抵知,著一層夾襖步出監(jiān)牢的瞬間墙基,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工刷喜, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留残制,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓吱肌,卻偏偏與公主長(zhǎng)得像痘拆,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子氮墨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • 純手工打造每一篇開(kāi)源資訊與技術(shù)干貨,數(shù)十萬(wàn)程序員和Linuxer已經(jīng)關(guān)注 1 Git 分支 - 分支簡(jiǎn)介 有人把 ...
    塵世不擾閱讀 701評(píng)論 0 3
  • 一桥氏、 Git 分支簡(jiǎn)介 幾乎所有的版本控制系統(tǒng)都以某種形式支持分支温峭。 使用分支意味著你可以把你的工作從開(kāi)發(fā)主線上分...
    常大鵬閱讀 2,941評(píng)論 2 41
  • 1. 創(chuàng)建與合并分支 在Git里每次提交會(huì)被串成一條時(shí)間線,這條時(shí)間線就是一個(gè)分支.而HEAD是指向當(dāng)前分支,當(dāng)前...
    程序員七哥閱讀 539評(píng)論 0 5
  • 四、 分支開(kāi)發(fā)工作流 現(xiàn)在你已經(jīng)學(xué)會(huì)新建和合并分支字支,那么你可以或者應(yīng)該用它來(lái)做些什么呢凤藏? 在本節(jié),我們會(huì)介紹一些常...
    常大鵬閱讀 2,092評(píng)論 3 24
  • 這周禮拜一早晨六點(diǎn)半左右,我對(duì)吃早餐的兒子說(shuō):“你把昨天聽(tīng)的《這樣的祝福掌聲會(huì)多》再講一遍”欠雌,誰(shuí)知他講的...
    長(zhǎng)翅膀的豬_8051閱讀 135評(píng)論 0 0