git分支使用的壞習(xí)慣
最近使用git提交代碼發(fā)現(xiàn)大家的方式都不一樣模蜡,自己在使用中也遇到了一些問題吞滞,導(dǎo)致代碼危險佑菩。具體描述一下就是:
1.剛開始創(chuàng)建本地b_28分支與遠(yuǎn)程b_28對應(yīng)。在此基礎(chǔ)上冯吓,我自己改一個bug就基于這個又拉取了本地分支b_bug,一直在這個本地分支上修改倘待,這個b_bug也一直沒有關(guān)聯(lián)任何遠(yuǎn)程代碼疮跑。
2.后來遠(yuǎn)程b_featureA分支(原來是和b_28一樣的)做了些版本小修改组贺。
3.我不明就里的,本地又checkout了一個b_featureA祖娘,還把這些修改merge到了自己的b_bug失尖。
4.管理員讓我提交自己bug的修復(fù)啊奄。我將b_bug merge到本地b_28,然后先拉了origin b_28的更新掀潮,還好本地沒沖突菇夸,然后push到了遠(yuǎn)端origin b_28。
5.遠(yuǎn)端分支的話仪吧,管理員b_featureA開發(fā)完了庄新,要merge到b_28,并以后要在b_28基礎(chǔ)上開發(fā)
其實(shí)這就有問題了薯鼠,本來是用大家最新提交后的origin b_featureA去merge到origin b_28择诈,但是由于我之前push到上面的代碼包含了不必要的對origin b_featureA拉取,導(dǎo)致這個提交不安全出皇。(事實(shí)上由于我在第3步之后又將b_bug中一個文件K恢復(fù)到了b_28版本羞芍,導(dǎo)致這個更新丟失了。這次遠(yuǎn)端merge的時候郊艘,K竟然還是未改的荷科,b_featureA對它的改動并沒有merge成功,但也沒有提示纱注,還好最后檢查了畏浆。其實(shí)要是我沒有恢復(fù)過這個K也就沒事了)
因此,我犯了一個不必要的錯誤奈附,要保證本地分支的parent只有一個全度,不要隨便merge別的分支。
然后對于分支的使用原則斥滤,問了些人将鸵,大家習(xí)慣不一樣,這幾找了幾個列子佑颇,想分清楚集中使用方法顶掉。
大家怎么用
主要關(guān)注功能分支:
我覺得可能不同的項目或者不同習(xí)慣的人需要不同的分支策略,這些沒有必要非要按照某種規(guī)則去遵守挑胸。
一痒筒、阮一峰:Git分支管理策略 重點(diǎn)推薦,簡單全面
1.創(chuàng)建一個功能分支:
git checkout -b feature-x develop
2.開發(fā)完成后茬贵,將功能分支合并到develop分支:
git checkout develop
git merge --no-ff feature-x
3.刪除feature分支:
git branch -d feature-x
二簿透、這個跟上面的是一樣的方法,還有全面的命令解藻,總結(jié)的很好:git使用規(guī)范
三老充、 這個稍微有點(diǎn)不一樣:Git 問題, 一個 master, 多個新功能分支, 怎樣有序地合并和提交?
git支持很多種工作流程,我們采用的一般是這樣螟左,遠(yuǎn)程創(chuàng)建一個主分支啡浊,本地每人創(chuàng)建功能分支觅够,日常工作流程如下:
1.去自己的工作分支
$ git checkout work
2.工作
3.提交工作分支的修改
$ git commit -a
4.回到主分支
$ git checkout master
5.獲取遠(yuǎn)程最新的修改,此時不會產(chǎn)生沖突
$ git pull
6.回到工作分支
$ git checkout work
7.用rebase合并主干的修改巷嚣,如果有沖突在此時解決
$ git rebase master // 將改變當(dāng)前工作分支的提交歷史喘先,rebase使得master上的更改在work上重演一遍
8.回到主分支
$ git checkout master
9.合并工作分支的修改,此時不會產(chǎn)生沖突廷粒。
$ git merge work
10.提交到遠(yuǎn)程主干
$ git push
這樣做的好處是窘拯,遠(yuǎn)程主干上的歷史永遠(yuǎn)是線性的。每個人在本地分支解決沖突坝茎,不會在主干上產(chǎn)生沖突树枫。
注意衍合rebase的使用:分支的衍合
簡單介紹rebase的:git rebase簡介(基本篇)
Attention:一旦分支中的提交對象發(fā)布到公共倉庫,就千萬不要對該分支進(jìn)行衍合操作景东。
如果你遵循這條金科玉律砂轻,就不會出差錯。否則斤吐,人民群眾會仇恨你搔涝,你的朋友和家人也會嘲笑你,唾棄你
四和措、一個小團(tuán)隊的使用:請推薦一個適合4-6人小團(tuán)隊的git代碼管理模式庄呈?
整體項目分為master和develop兩個分支,master主要用來發(fā)布網(wǎng)站使用.develop主要是用來分開使用.
1.平時每個人開發(fā)的時候派阱,從develop中clone一下并創(chuàng)建一個開發(fā)者自己的分支诬留,如zhang.(再有新加入者的時候,類似同樣的方法分支另起一個名字li.).** Q:相當(dāng)于每個開發(fā)者有一個自己的遠(yuǎn)程分支贫母?按照人來確立分支而不是按照功能分支 **
2.當(dāng)開發(fā)工作完成后文兑,提交本地倉庫并git push到自己的分支.
3.最后先將develop合并到自己的分支(開發(fā)期間可能被開發(fā)者進(jìn)行過修改),以確保合并成功.
4.合并無誤后腺劣,再將當(dāng)前合并后的zhang分支合并到develop分支中.(注:這里的合并操作先是在本地分支合并.然后再合并到遠(yuǎn)程分支.有點(diǎn)多操作一步).
5.到最后一天工作結(jié)束后再將develop合并到master分支绿贞,通過master上線運(yùn)行.
另外對于線上環(huán)境有緊急bug要修改的時候.再從master里創(chuàng)建一個分支.獨(dú)立維護(hù).結(jié)束后,再分別同步master和develop兩個分支.
** 五橘原、我打算用這個方式了籍铁,感覺跟第三個很類似:3.2 Git 分支 - 分支的新建與合并**
讓我們來看一個簡單的分支新建與分支合并的例子,實(shí)際工作中你可能會用到類似的工作流趾断。 你將經(jīng)歷如下步驟:
1.開發(fā)某個網(wǎng)站拒名。
2.為實(shí)現(xiàn)某個新的需求,創(chuàng)建一個分支芋酌。
3.在這個分支上開展工作增显。
正在此時,你突然接到一個電話說有個很嚴(yán)重的問題需要緊急修補(bǔ)隔嫡。 你將按照如下方式來處理:
1.切換到你的線上分支(production branch)甸怕。
2.為這個緊急任務(wù)新建一個分支,并在其中修復(fù)它腮恩。
3.在測試通過之后梢杭,切換回線上分支,然后合并這個修補(bǔ)分支秸滴,最后將改動推送到線上分支武契。
4.切換回你最初工作的分支上,繼續(xù)工作荡含。
我認(rèn)為的使用方式咒唆,還沒有驗(yàn)證過不知道是不是好用:
比如有兩個相互獨(dú)立的任務(wù)featureA和featureB,簡單點(diǎn)释液,他們都是從origin/dev拉過來開發(fā)全释。
第一種:
- 分別建立本地分支
$ git branch b_featureA origin/dev //新建本地分支featureA --關(guān)聯(lián)遠(yuǎn)程分支dev
$ git branch b_featureB origin/dev //新建本地分支featureB --關(guān)聯(lián)遠(yuǎn)程分支dev
featureA和featureB在各自的分支上工作
最后修改完,先pull遠(yuǎn)端的代碼误债,可能會有沖突浸船,此時
$ git stash // 先暫存本地修改
$ git pull // 再拉取
$ git stash pop stash@{0} // 還原暫存區(qū)的內(nèi)容,并解決沖突
- 解決沖突后
$ git push origin dev
- 如果本地分支featureA和本地分支featureB沒用了寝蹈,可以刪除
這種方法沒有一個比較穩(wěn)定的本地分支李命。
第二種:
1.新建本地local_dev --關(guān)聯(lián)遠(yuǎn)程dev
$ git branch local_dev origin/dev
2.基于本地的開發(fā)分支local_dev 創(chuàng)建兩個功能分支,它們不關(guān)聯(lián)任何遠(yuǎn)程分支
$ git branch b_featureA
$ git branch b_featureB
3.分別在featureA和featureB在各自的分支上工作
4.featureA開發(fā)完畢箫老,切回到local_dev封字,它pull最新代碼,此時不會有沖突耍鬓。然后兩種情況:
方法一:將最新的更改merge到local_dev阔籽,有可能沖突,也有rebase的牲蜀,不熟悉先不用了仿耽。
沒有沖突工作區(qū)也干凈后,push到遠(yuǎn)端各薇。刪除本地featureA项贺。
如果有暫時不想提的,可以stash起來峭判,先不刪除开缎,然后進(jìn)行后續(xù)開發(fā)。
方法二:再復(fù)雜一點(diǎn)林螃,切回到featureA奕删,將local_dev的更新merge過來,沖突在此處解決疗认。
都提交后完残,切回到local_dev伏钠,將featureA的更新merge過來,此時不會再有沖突谨设。
local_dev推送到遠(yuǎn)端熟掂。
方法三:我沒想到,一個同事說的扎拣,切回到featureA赴肚,將origin/dev的更新merge過來,就是直接將遠(yuǎn)端分支的更改merge過來二蓝,有沖突就在此處解決誉券。然后都開發(fā)完畢后,切回到local_dev刊愚,將featureA的更新merge過來踊跟,然后將local_dev推送到遠(yuǎn)端。比方法二少一步merge鸥诽,然后好像也沒什么大的缺點(diǎn)琴锭。
不過還沒用過直接將遠(yuǎn)程分支merge到本地這種未對應(yīng)遠(yuǎn)程分支的分支上。而且衙传,經(jīng)尘鎏看到這樣的忠告:
不要用git pull,用git fetch和git merge代替它蓖捶。
5.featureB同上
我之前是用的最復(fù)雜的第二種的方法二地回。好處是沖突都是在本地最末端的分支上,和其他功能都不會相互影響俊鱼,就是操作太麻煩了刻像。
打算采用上面的三,期待有更好的方法并闲。
一些常用命令
基本命令
$ git remote add origin git@github.com:michaelliao/learngit.git // 將本地的git目錄和遠(yuǎn)程建好的git目錄關(guān)聯(lián)
$ git add . // 添加所有文件到git版本控制细睡,注意不是git stash
$ git commit -m "commit log" // 提交修改,必須要加注釋
$ git checkout -b story remotes/origin/story // 在本地創(chuàng)建story分支并track帝火,可以pull和push
//恢復(fù)版本
$ git checkout -- readme.txt // 把readme.txt文件在工作區(qū)的修改全部撤銷溜徙,還未添加到暫存區(qū)
$ git reset HEAD readme.txt // 已經(jīng)add,還沒有commit犀填,先用這句unstage蠢壹,在用上一句
// 如果已經(jīng)commit
$ git log // 查看提交記錄,確定恢復(fù)到哪個版本
$ git log -p // 查看詳細(xì)提交記錄
$ git reset --hard HEAD^ // 恢復(fù)到上一個版本九巡,因?yàn)镠EAD指的是當(dāng)期版本图贸,HEAD是上一個,HEAD^是上上個,其余的可以用版本編號的前幾位來恢復(fù)
$ git reset --hard 3628164 // 前幾位來恢復(fù),只要這個號碼能唯一確定一個版本就可以
$ git push -u origin b_28 // 將本地修改的b_28推送到遠(yuǎn)端b_28疏日,加上了-u參數(shù)偿洁,Git不但會把本地的分支內(nèi)容推送的遠(yuǎn)程新的分支,還會把本地的分支和遠(yuǎn)程的分支關(guān)聯(lián)起來沟优,在以后的推送或者拉取時就可以簡化命令涕滋。第一次推送分支的所有內(nèi)容,以后就可以用git push origin b_28了
$ git branch -d feature // 刪除feature分支
$ git branch -a // 加上-a參數(shù)可以查看遠(yuǎn)程分支净神,遠(yuǎn)程分支會用紅色表示出來
$ git branch -vv // git branch -vv(兩個v),就能夠看到本地分支跟蹤的遠(yuǎn)程分支溉委。
$ git merge --no-ff develop // 默認(rèn)情況下鹃唯,Git執(zhí)行"快進(jìn)式合并"(fast-farward merge)加上這個參數(shù)就是非快進(jìn)式合并
$ git push origin :branch_you_want_to_delete // 刪除遠(yuǎn)程的某個分支,注意冒號前面有個空格瓣喊,慎用
跟蹤遠(yuǎn)程分支
從遠(yuǎn)程分支 checkout 出來的本地分支坡慌,稱為 跟蹤分支 (tracking branch)。跟蹤分支是一種和某個遠(yuǎn)程分支有直接聯(lián)系的本地分支藻三。在跟蹤分支里輸入 git push洪橘,Git 會自行推斷應(yīng)該向哪個服務(wù)器的哪個分支推送數(shù)據(jù)。同樣棵帽,在這些分支里運(yùn)行 git pull 會獲取所有遠(yuǎn)程索引熄求,并把它們的數(shù)據(jù)都合并到本地分支中來。
在克隆倉庫時逗概,Git 通常會自動創(chuàng)建一個名為 master 的分支來跟蹤 origin/master弟晚。這正是 git push
和 git pull 一開始就能正常工作的原因。當(dāng)然逾苫,你可以隨心所欲地設(shè)定為其它跟蹤分支卿城,比如 origin
上除了 master 之外的其它分支。剛才我們已經(jīng)看到了這樣的一個例子:git checkout -b [分支名] [遠(yuǎn)程名]/[分支名]铅搓。如果你有 1.6.2 以上版本的 Git瑟押,還可以用 --track
選項簡化:
$ git checkout --track origin/serverfixBranch //serverfix set up to track remote branch serverfix from origin.Switched to a new branch 'serverfix'
要為本地分支設(shè)定不同于遠(yuǎn)程分支的名字,只需在第一個版本的命令里換個名字:
$ git checkout -b sf origin/serverfixBranch //sf set up to track remote branch serverfix from origin.Switched to a new branch 'sf'
git本地新建一個分支后星掰,如果沒有做遠(yuǎn)程分支關(guān)聯(lián)多望, git 會在git pull, git push操作中提示你顯示的添加關(guān)聯(lián)。你只要沒有顯示指定氢烘,git pull的時候就提示“no tracking information”便斥,則說明本地分支和遠(yuǎn)程分支的鏈接關(guān)系沒有創(chuàng)建。如果新建分支的時候沒有指定威始,隨后再指定本地dev分支與遠(yuǎn)程origin/dev分支的鏈接枢纠,可以用下面的命令
$ git branch --set-upstream dev origin/dev
工作區(qū)域暫存
$git stash
$ git stash list
$ git stash apply
$ git stash drop stash@{0}
$ git stash pop //來重新應(yīng)用儲藏,同時立刻將其從堆棧中移走。
學(xué)習(xí)參考資料:看了這些就夠了
1.Git常用操作和技巧
2.git - 簡明指南
3.Pro Git簡體中文版
4.廖雪峰 簡明git教程
5.Git Commands and Best Practices Cheat Sheet