(五)Git--分支管理

1. 創(chuàng)建與合并分支

在Git里每次提交會(huì)被串成一條時(shí)間線,這條時(shí)間線就是一個(gè)分支.而HEAD是指向當(dāng)前分支,當(dāng)前分支在指向最新一次提交;
例如:一開(kāi)始的時(shí)候,master分支是一條線,Git用master指向最新提交,在用HEAD指向master分支,就能確定當(dāng)前分支,以及當(dāng)前分支的提交點(diǎn);
當(dāng)我們創(chuàng)建新的分支,例如dev時(shí),Git新建了一個(gè)指針叫dev,指向master當(dāng)前相同的提交,再把HEAD指向dev,就表示當(dāng)前分支在dev上;


這時(shí),我們可以發(fā)現(xiàn).Git創(chuàng)建一個(gè)分支很快,因?yàn)槌嗽黾恿艘粋€(gè)dev指針,改改HEAD的指向,工作區(qū)的文件都沒(méi)有任何變化!
不過(guò),從現(xiàn)在開(kāi)始,對(duì)工作區(qū)的修改就是針對(duì)dev分支的了,比如再次進(jìn)行提交后,dev指針就會(huì)繼續(xù)向前移動(dòng)指向最新一次的提交.而master指針不變;


接下來(lái)我們看看合并操作,假如我們?cè)?code>dev上的工作完成了,就可以把dev合并到master上,Git怎么進(jìn)行合并呢?最簡(jiǎn)單的方法,就是直接把master指向dev的當(dāng)前提交,就完成了合并:


所以Git合并分支也很快!就改變了指針指向,工作區(qū)內(nèi)容也不變!
合并完分支后,也可以刪除分支,刪除dev分支想必你已經(jīng)可以想到,對(duì)的,就是把dev指針給刪掉,刪掉后我們就剩下了一條master分支:

接下來(lái)我們開(kāi)始進(jìn)行操練:

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

git checkout命令加上-b參數(shù)表示創(chuàng)建并切換,相當(dāng)于下面兩條命令:

$ git branch dev
$ git checkout dev
Switched to branch 'dev'

然后使用git branch命令查看當(dāng)前分支:

$ git branch
* dev
  master

git branch命令會(huì)列出所有分支,當(dāng)前分支前面會(huì)標(biāo)一個(gè)*號(hào).
然后,我們可以在dev分支上正常提交:

$ git commit -m "忽略不要的文件"
[dev fae4e76] 忽略不要的文件
 2 files changed, 12 insertions(+), 4 deletions(-)
 create mode 100644 .gitignore

現(xiàn)在,dev分支的工作完成,我們可以切換回master分支:

$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

切換回master分支后,發(fā)現(xiàn)剛才修改的內(nèi)容不見(jiàn)了!那是因?yàn)槟莻€(gè)提交是在dev分支上,而master分支此刻的提交點(diǎn)并沒(méi)有變:


現(xiàn)在我們把dev分支上的工作成果合并到master上:

$ git merge dev
Updating e151f7e..fae4e76
Fast-forward
 .gitignore          | 8 ++++++++
 .idea/workspace.xml | 8 ++++----
 2 files changed, 12 insertions(+), 4 deletions(-)
 create mode 100644 .gitignore

git merge命令用于合并指定分支到當(dāng)前分支.合并后在查看剛才修改的內(nèi)容,就可以看到,和dev分支最新提交的內(nèi)容是完全一樣的.
注意到上面的Fast-forward信息,Git告訴我們,這次合并是"快進(jìn)模式",也就是直接把master指向dev當(dāng)前的提交,所以合并速度非车涛玻快.
當(dāng)然,也有意外發(fā)生,不是每次合并都能Fast-forward的;
合并完成后,就可以放心地刪除dev分支了:

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

刪除后,查看branch,就只剩下master分支了:

$ git branch
* master
小結(jié)

查看分支:git branch
創(chuàng)建分支:git branch <name>
切換分支:git checkout <name>
創(chuàng)建+切換分支:git checkout -b <name>
合并某分支到當(dāng)前分支:git merge <name>
刪除分支:git branch -d <name>

2. 解決沖突

分支合并的過(guò)程往往并不是一帆風(fēng)順的,準(zhǔn)備新的feature1分支,我們?cè)谶@個(gè)分支上作出我們要修改的內(nèi)容,然后提交.然后在切換回master分支上時(shí),要將feature1分支上提交的內(nèi)容合并過(guò)來(lái),這時(shí)如果其他人已經(jīng)在master分支上也對(duì)相應(yīng)文件作出了修改,masterfeature1分支各自有了新的提交,變成了如下這個(gè)樣子:


這種情況下,Git無(wú)法執(zhí)行"快速合并",只能把各自的修改合并起來(lái),但這種合并就可能會(huì)有沖突,如下所示:

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

Git告訴我們,readme.txt文件沖突了,必須手動(dòng)解決沖突后再提交.git status也可以告訴我們沖突的文件:

$ git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
# Unmerged paths:
#   (use "git add/rm <file>..." as appropriate to mark resolution)
#
#       both modified:      readme.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

我們可以直接查看readme.txt的內(nèi)容:

Git is a distributed version control system.
Git is free software distributed under the GPL.
Git has a mutable index called stage.
Git tracks changes of files.
<<<<<<< HEAD
Creating a new branch is quick & simple.
=======
Creating a new branch is quick AND simple.
>>>>>>> feature

Git用<<<<<<<,=======,>>>>>>>標(biāo)記不同分支的內(nèi)容,其中HEAD表示當(dāng)前分支的內(nèi)容.
解決沖突后,在提交,現(xiàn)在masterfeature1分支變成了下圖所示:


git log --graph命令可以看到分支合并圖:

$ git log --graph --pretty
*   commit b95bbf0ac897b2d88fa4bcf0308913f624d566c7
|\  Merge: c2e47c0 89cdc59
| | Author: alan7c <chong_luo@kingdee.com>
| | Date:   Fri Mar 17 17:48:28 2017 +0800
| |
| |     conflict fixed
| |
| * commit 89cdc59631411c217e99b8c0b1a6c1ceee63d677
| | Author: alan7c <chong_luo@kingdee.com>
| | Date:   Fri Mar 17 17:40:45 2017 +0800
| |
| |     AND simple
| |
* | commit c2e47c06db550e03b2c19ee5247b03d949a10541
|/  Author: alan7c <chong_luo@kingdee.com>
|   Date:   Fri Mar 17 17:42:44 2017 +0800
|
|       & simple
|
* commit fae4e76e7b00741fd3894ebdfcf46cb5712b2db2
| Author: alan7c <chong_luo@kingdee.com>
| Date:   Fri Mar 17 15:34:00 2017 +0800
|
|     忽略不要的文件
|
* commit e151f7e1a74ca3eb4a466568dbac5de922b3e596
| Author: alan7c <chong_luo@kingdee.com>
| Date:   Mon Mar 13 21:19:10 2017 +0800
|
|     add README.md
|
* commit 3fafa4a18f01733d1347da2248775db29421ffaa
| Author: alan7c <chong_luo@kingdee.com>
| Date:   Mon Mar 13 11:32:54 2017 +0800

最后,我們可以刪除feature1分支:

$ git branch -d feature1
Deleted branch feature1 (was 89cdc59).

3.分支管理策略

通常合并分支時(shí),如果可能,Git會(huì)用Fast forward模式,但這種模式下,刪除分支后,會(huì)丟掉分支信息.如果強(qiáng)制禁用Fast forward模式,Git就會(huì)在merge時(shí)生成一個(gè)新的commit,這樣,從分支歷史上就可以看出分支信息.
那么如何禁用Fast forward模式呢,就要使用--no-ff參數(shù):
git merge --no-ff -m "merge with no-ff" dev
因?yàn)楸敬魏喜⒁獎(jiǎng)?chuàng)建一個(gè)新的commit,所以加上-m參數(shù),把commit描述寫進(jìn)去.
不使用Fast forward模式,merge后就像這樣:


分支策略
在實(shí)際開(kāi)發(fā)中,我們應(yīng)該按照幾個(gè)基本原則進(jìn)行分支管理:

  1. 首先要保證master分支應(yīng)該是非常穩(wěn)定的,也就是僅用來(lái)分布新版本,平時(shí)不能在上面干活;
  2. 干活都在dev分支,也就是說(shuō)dev分支是不穩(wěn)定的,到某個(gè)時(shí)候如版本發(fā)布時(shí),在把dev分支合并到master上,用master分支發(fā)布新版本.
    我們可以和小伙伴們每個(gè)人都在dev分支上干活,每個(gè)人都有自己的分支,時(shí)不時(shí)的往dev分支上合并就可以了.
    所以團(tuán)隊(duì)合作的分支看起來(lái)就像這樣:

    如果我們一個(gè)臨時(shí)分支上完成了開(kāi)發(fā)任務(wù),可是突然產(chǎn)品經(jīng)理說(shuō)不要這個(gè)功能了,所以我們沒(méi)有合并這個(gè)分支而且需要?jiǎng)h除它,使用git branch -d <name>時(shí),會(huì)銷毀失敗,Git會(huì)提示我們這個(gè)分支還沒(méi)有完成合并,如果刪除,將丟失修改,如果強(qiáng)行刪除,需要使用命令git branch -D <name>

小結(jié)
合并分支時(shí),加上--no-ff參數(shù)就可以用普通模式合并,合并后的歷史有分支記錄,而Fast forward合并就看不出來(lái)曾經(jīng)做過(guò)合并.

4.Bug分支

在軟件開(kāi)發(fā)過(guò)程中,bug是普遍存在的.既然會(huì)出現(xiàn)bug,當(dāng)然就要去修復(fù),在Git中分支系統(tǒng)是什么強(qiáng)大的,所以每個(gè)bug都可以通過(guò)一個(gè)新的臨時(shí)分支來(lái)修復(fù),修復(fù)后在刪除這個(gè)臨時(shí)分支,當(dāng)我們接到一個(gè)編號(hào)110的bug時(shí),想當(dāng)然我們會(huì)創(chuàng)建一個(gè)issue-110來(lái)修復(fù)它,但是等等,當(dāng)前正在dev分支上進(jìn)行的工作還沒(méi)有提交,可是這個(gè)時(shí)候并不是你不想提交而是工作只進(jìn)行了一半,還沒(méi)法提交,預(yù)計(jì)完成還需要一天時(shí)間,但是,bug必須在兩個(gè)小時(shí)內(nèi)修復(fù),怎么辦呢?
不怕,Git還提供了一個(gè)stash功能,可以把當(dāng)前工作現(xiàn)場(chǎng)"儲(chǔ)藏起來(lái)",等以后恢復(fù)現(xiàn)場(chǎng)后繼續(xù)工作:

git stash
Saved working directory and index state WIP on dev: 6224937 add merge
HEAD is now at 6224937 add merge

現(xiàn)在,用git status查看工作區(qū),就是干凈的,因此就可以放開(kāi)手腳來(lái)修復(fù)bug了.
假如我們要從master分支上修復(fù)bug,就從master創(chuàng)建臨時(shí)分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 6 commits.
$ git checkout -b issue-101
Switched to a new branch 'issue-110'

等到bug修復(fù)后,然后提交:

git add .
git commit -m "fix bug 110"
[issue-110 cc17032] fix bug 110
 1 file changed, 1 insertion(+), 1 deletion(-)

修復(fù)完成后,切換到master分支,并完成合并,最后刪除issue-110分支:

$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 2 commits.
$ git merge --no-ff -m "merged bug fix 110" issue-110
Merge made by the 'recursive' strategy.
 readme.txt |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git branch -d issue-110
Deleted branch issue-101 (was cc17032).

太棒了,修復(fù)完bug后,是時(shí)候接著回到dev分支干活了!

$ git checkout dev
Switched to branch 'dev'
$ git status
# On branch dev
nothing to commit (working directory clean)

工作區(qū)是干凈的,剛才的工作現(xiàn)場(chǎng)存到哪里去了?用git stash list命令查看:

$ git stash list
stash@{0}: WIP on dev: 6224937 add merge

工作現(xiàn)場(chǎng)顯然還在,這時(shí)需要使用恢復(fù)命令來(lái)恢復(fù)現(xiàn)場(chǎng):
一是用git stash apply恢復(fù),但是恢復(fù)后,stash內(nèi)容并不刪除,你需要用git stash drop來(lái)刪除;
二是用git stash pop,恢復(fù)的同時(shí)把stash內(nèi)容也刪了;
小貼士:
你可以多次stash,恢復(fù)的時(shí)候,先用git stash list查看,然后恢復(fù)指定的stash,用命令:
git stash apply stash@{0}

5.多人協(xié)作

當(dāng)你從遠(yuǎn)程倉(cāng)庫(kù)克隆時(shí),實(shí)際上Git自動(dòng)把本地的master分支和遠(yuǎn)程的master分支對(duì)應(yīng)起來(lái)了,并且遠(yuǎn)程倉(cāng)庫(kù)默認(rèn)名稱是origin.
要查看遠(yuǎn)程庫(kù)的信息,用git remote:

$ git remote
origin

或者git remote -v顯示更詳細(xì)的信息:

$ git remote -v
origin  git@github.com:Alanluochong/strman-java.git (fetch)
origin  git@github.com:Alanluochong/strman-java.git (push)

上面顯示了可以抓取和推送的origin的地址,如果沒(méi)有推送權(quán)限,就看不到push地址.

推送分支

推送時(shí),要指定本地分支,這樣,Git就會(huì)把該分支推送到遠(yuǎn)程倉(cāng)庫(kù)所對(duì)應(yīng)的遠(yuǎn)程分支上:
$ git push origin master

抓取分支

$ git clone git@github.com:Alanluochong/strman-java.git
默認(rèn)情況下,拉取后只能看到本地有一個(gè)master分支,如果要在其他分支上開(kāi)發(fā),就必須創(chuàng)建遠(yuǎn)程origin的相應(yīng)分支到本地,于是可以用這個(gè)命令創(chuàng)建本地分支:
$ git checkout -b dev origin/dev
向遠(yuǎn)程推送本地的提交,有可能推送失敗,因?yàn)槟愕男』锇榈淖钚绿峤缓湍阍噲D推送的提交有沖突,這時(shí)需要使用git pull把最新的提交從origin/dev抓下來(lái),然后,在本地合并,解決沖突在推送:

$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0)
Unpacking objects: 100% (3/3), done.
From github.com:alanluochong/Java
   fc38031..291bea8  dev        -> origin/dev
There is no tracking information for the current branch.
Please specify which branch you want to merge with.
See git-pull(1) for details

    git pull <remote> <branch>

If you wish to set tracking information for this branch you can do so with:

    git branch --set-upstream dev origin/<branch>

git pull也失敗了,原因是沒(méi)有指定本地dev分支與遠(yuǎn)程origin/dev分支的連接,根據(jù)提示,設(shè)置dev與遠(yuǎn)程origin/dev的連接:

$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.

小結(jié)
多人協(xié)作的工作模式通常是這樣:

  1. 首先,在本地創(chuàng)建和遠(yuǎn)程對(duì)應(yīng)的分支,使用git branch -b branch-name origin/branch-name,本地分支最好與遠(yuǎn)程名稱一致;
  2. 完成開(kāi)發(fā)后,可以試圖使用git push origin branch-name推送自己的修改;
  3. 如果推送失敗,則因?yàn)檫h(yuǎn)程分支比你的本地有新的提交,需要使用git pull試圖合并;
  4. 如果合并有沖突,則解決沖突,并在本地提交;
  5. 沒(méi)有沖突或者解決沖突后,再用git push origin branch-name推送就能成功!
    如果git pull提示"no tracking information",則說(shuō)明本地分支和遠(yuǎn)程分支的連接關(guān)系沒(méi)有創(chuàng)建,用命令git branch --set-upstream branch-name origin/branch-name.
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肝劲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子郭宝,更是在濱河造成了極大的恐慌辞槐,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件粘室,死亡現(xiàn)場(chǎng)離奇詭異榄檬,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)衔统,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門鹿榜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人锦爵,你說(shuō)我怎么就攤上這事舱殿。” “怎么了棉浸?”我有些...
    開(kāi)封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵怀薛,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我迷郑,道長(zhǎng)枝恋,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任嗡害,我火速辦了婚禮焚碌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘霸妹。我一直安慰自己十电,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鹃骂,像睡著了一般台盯。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上畏线,一...
    開(kāi)封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天静盅,我揣著相機(jī)與錄音,去河邊找鬼寝殴。 笑死蒿叠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蚣常。 我是一名探鬼主播市咽,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼抵蚊!你這毒婦竟也來(lái)了施绎?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤泌射,失蹤者是張志新(化名)和其女友劉穎粘姜,沒(méi)想到半個(gè)月后鬓照,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體熔酷,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年豺裆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拒秘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡臭猜,死狀恐怖躺酒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蔑歌,我是刑警寧澤羹应,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站次屠,受9級(jí)特大地震影響园匹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜劫灶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一裸违、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧本昏,春花似錦供汛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)雀久。三九已至,卻和暖如春趁舀,著一層夾襖步出監(jiān)牢的瞬間岸啡,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工赫编, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留巡蘸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓擂送,卻偏偏與公主長(zhǎng)得像悦荒,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘹吨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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