一春叫、常用命令介紹
1.1 命令行介紹
1.1.1 Git 全局設置
$ git config --global user.name "knight"
$ git config --global user.email "knight@dayuan.com"
1.1.2 創(chuàng)建一個新倉庫(本地)
$ git clone http://git.dayuan.cc/practice/git-exmple.git
cd git-exmple
$ touch README.md
$ git add README.md
$ git commit -m "add README"
$ git push -u origin master
1.1.3 在已存在的目錄中創(chuàng)建倉庫
cd existing_folder
$ git init
$ git remote add origin http://git.dayuan.cc/practice/git-exmple.git
$ git add .
$ git commit -m "Initial commit"
$ git push -u origin master
1.1.4 將本地已存在的倉庫推送到遠程倉庫
cd existing_repo
$ git remote rename origin old-origin
$ git remote add origin http://git.dayuan.cc/practice/git-exmple.git
$ git push -u origin --all
$ git push -u origin --tags
1.1.5 查看分支相關命令
$ git branch -r; //查看遠程分支
$ git branch; //查看本地分支
$ git branch -a; //查看所有分支
1.1.6 拉取遠程分支并創(chuàng)建本地分支
// dev2為遠程分支,dev1為本地分支
$ git checkout -b dev1 origin/dev2;
從遠程分支dev拉取到本地并且創(chuàng)建本地分支dev,且倆者之間建立映射關系,同時當前分支會切換到dev1
//dev2為遠程分支,dev1為本地分支
$ git fetch origin dev2:dev1;
使用該方式會在本地新建分支dev1泣港,但是不會自動切換到該本地分支dev1暂殖,需要手動checkout。采用此種方法建立的本地分支不會和遠程分支建立映射關系当纱。
1.1.7 建立本地分支與遠程分支的映射關系(或者為跟蹤關系track)
- 這樣使用git pull或者git push時就不必每次都要指定從遠程的哪個分支拉取合并和推送到遠程的哪個分支了呛每。
$ git branch -vv
輸出映射關系
// dev為遠程分支名
$ git branch -u origin/dev
將當前本地分支與遠程分支建立映射關系
$ git branch --unset-upstream
撤銷當前本地分支與遠程分支的映射關系
1.1.8 切換當前本地分支
// dev為本地分支名
$ git checkout dev;
1.1.9 拉取遠程分支代碼
$ git pull
使用的前提是當前分支需要與遠程分支之間建立映射關系
1.1.10 推送本地分支代碼到遠程分支
$ git push
使用的前提是當前分支需要與遠程分支之間建立映射關系
1.1.11 合并分支
- 場景:現(xiàn)在有dev本地分支與遠程分支,master本地分支與遠程分支
現(xiàn)在將dev的分支代碼合并到master主干上 - 思路步驟 :
1.切換到本地分支dev上坡氯,并且pull拉取一下遠程dev分支上的改動地方
2.將所有本地修改進行commit并且push到遠程dev分支上晨横,保證沒有遺漏的,確保當前本地dev與遠程dev是一致的
3.將當前本地分支切換到本地master上
4.將本地分支dev合并到本地master上
5.將本地已經(jīng)合并了dev分支的master進行push到遠程master上 大概思路就是這樣箫柳。需要注意的是在進行merge(合并)的時候需要禁用fast-forward模式
- 具體的合并命令:
git merge --no-ff dev (dev為本地被合并的分支名字)
二手形、Gitflow總覽
從上圖可以看到主要包含下面幾個分支:
master
: 主分支,主要用來版本發(fā)布悯恍。
develop
:日常開發(fā)分支库糠,該分支正常保存了開發(fā)的最新代碼。
feature
:具體的功能開發(fā)分支坪稽,只與 develop 分支交互。
release
:release
分支可以認為是master
分支的未測試版鳞骤。比如說某一期的功能全部開發(fā)完成窒百,那么就將 develop
分支合并到 release
分支,測試沒有問題并且到了發(fā)布日期就合并到master
分支豫尽,進行發(fā)布篙梢。
hotfix
:線上 bug 修復分支。
除此之后還可以有 fast-track
等分支美旧。
2.1 主分支
主分支包括 master
分支和 develop
分支渤滞。master
分支用來發(fā)布贬墩,HEAD
就是當前線上的運行代碼。develop
分支就是我們的日常開發(fā)妄呕。使用這兩個分支就具有了最簡單的開發(fā)模式:develop
分支用來開發(fā)功能陶舞,開發(fā)完成并且測試沒有問題則將 develop
分支的代碼合并到 master
分支并發(fā)布。
這引入了幾個問題:
develop
分支只有發(fā)布完了才能進行下一個版本開發(fā)绪励,開發(fā)會比較緩慢肿孵。
線上代碼出現(xiàn) bug 如何進行 bug 修復。
帶著這兩個問題往下看疏魏。
2.2 輔助分支
主要介紹的輔助分支如下:
feature
分支
release
分支
hotfix
分支
通過這些分支停做,我們可以做到:團隊成員之間并行開發(fā),feature track
更加容易大莫,開發(fā)和發(fā)布并行以及線上問題修復蛉腌。
2.2.1 Feature 分支
feature
分支用來開發(fā)具體的功能,一般 fork 自 develop
分支只厘,最終可能會合并到develop
分支烙丛。比如我們要在下一個版本增加功能1
、功能2
懈凹、功能3
蜀变。那么我們就可以起三個feature
分支:feature1
,feature2
介评,feature3
库北。(feature
分支命名最好能夠自解釋,這并不是一種好的命名们陆。)隨著我們開發(fā)寒瓦,功能1
和功能2
都被完成了,而功能3
因為某些原因完成不了坪仇,那么最終 feature1
和 feature2
分支將被合并到 develop
分支杂腰,而 feature3
分支將被干掉。
我們來看幾個相關的命令椅文。
2.2.1.1 新建feature分支
從 develop
分支建一個 feature
分支喂很,并切換到 feature
分支
$ git checkout -b myfeature develop
Switched to a new branch "myfeature"
2.2.1.2 合并feature 分支到 develop
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature
$ git push origin develop
上面我們 merge 分支的時候使用了參數(shù) --no-ff
,ff 是fast-forward
的意思皆刺,--no-ff
就是禁用fast-forward
少辣。關于這兩種模式的區(qū)別如下圖。(可以使用 sourceTree 或者命令git log --graph查看羡蛾。)
看了上面的圖漓帅,那么使用非fast-forward
模式來 merge 的好處就不言而喻了:我們知道哪些commit
是某些feature
相關的。雖然 git merge
的時候會自動判斷是否使用fast-farward
模式,但是有時候為了更明確忙干,我們還是要加參數(shù)--no-ff
或者--ff
器予。
2.2.2 Release 分支
release
分支在我看來是 pre-master
。release
分支從 develop
分支 fork
出來捐迫,最終會合并到 develop
分支和 master
分支乾翔。合并到 master
分支上就是可以發(fā)布的代碼了。有人可能會問那為什么合并回 develop
分支呢弓乙?很簡單末融,有了 release
分支,那么相關的代碼修復就只會在 release
分支上改動了暇韧,最后必然要合并到 develop
分支勾习。下面細說。
我們最初所有的開發(fā)工作都在 develop
分支上懈玻,當我們這一期的功能開發(fā)完畢的時候巧婶,我們基于 develop
分支開一個新的release
分支。這個時候我們就可以對 release
分支做統(tǒng)一的測試了涂乌,另外做一些發(fā)布準備工作:比如版本號之類的艺栈。
如果測試工作或者發(fā)布準備工作和具體的開發(fā)工作由不同人來做,比如國內(nèi)的 RD 和 QA湾盒,這個 RD 就可以繼續(xù)基于develop
分支繼續(xù)開發(fā)了湿右。再或者說公司對于發(fā)布有嚴格的時間控制,開發(fā)工作提前并且完美的完成了罚勾,這個時候我們就可以在develop
分支上繼續(xù)我們下一期的開發(fā)了毅人。同時如果測試有問題的話,我們將直接在release
分支上修改尖殃,然后將修改合并到develop
分支上丈莺。
待所有的測試和準備工作做完之后,我們就可以將 release
分支合并到master
分支上送丰,并進行發(fā)布了缔俄。
一些相關命令如下。
新建 release 分支
$ git checkout -b release-1.2 develop
Switched to a new branch "release-1.2"
$ ./bump-version.sh 1.2
File modified successfully, version bumped to 1.2.
$ git commit -a -m "Bumped version number to 1.2"
[release-1.2 74d9424] Bumped version number to 1.2
1 files changed, 1 insertions(+), 1 deletions(-)
2.2.2.1 release 分支合并到 master 分支
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2
2.2.2.2 release 分支合并到 develop 分支
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff release-1.2
Merge made by recursive.
(Summary of changes)
2.2.2.3 最后器躏,刪除 release 分支
$ git branch -d release-1.2
Deleted branch release-1.2 (was ff452fe).
2.2.3 Hotfix 分支
顧名思義俐载,hotfix
分支用來修復線上 bug。當線上代碼出現(xiàn) bug 時登失,我們基于 master
分支開一個 hotfix
分支遏佣,修復 bug 之后再將 hotfix
分支合并到master
分支并進行發(fā)布,同時 develop
分支作為最新最全的代碼分支壁畸,hotfix
分支也需要合并到 develop
分支上去贼急。仔細想一想,其實 hotfix
分支和 release
分支功能類似捏萍。hotfix
的好處是不打斷develop
分支正常進行太抓,同時對于生產(chǎn)代碼的修復貌似也沒有更好的方法了(總不能直接修改 master
代碼吧)。
一些相關的命令令杈。
2.2.3.1 新建 hotfix 分支
$ git checkout -b hotfix-1.2.1 master
Switched to a new branch "hotfix-1.2.1"
$ ./bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ git commit -a -m "Bumped version number to 1.2.1"
[hotfix-1.2.1 41e61bb] Bumped version number to 1.2.1
1 files changed, 1 insertions(+), 1 deletions(-)
2.2.3.2 Fix bug
$ git commit -m "Fixed severe production problem"
[hotfix-1.2.1 abbe5d6] Fixed severe production problem
5 files changed, 32 insertions(+), 17 deletions(-)
2.2.3.3 buffix 之后走敌,hotfix 合并到 master
$ git checkout master
Switched to branch 'master'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ git tag -a 1.2.1
2.2.3.4 hotfix 合并到 develop 分支
$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
2.2.3.5 刪除 hotfix 分支
$ git branch -d hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6).
三、Git 分支管理和沖突解決
3.1 合并分支間的修改 Merge
合并操作將兩條或多條分支合并到一起逗噩,實際上有好幾種分支合并方法掉丽,下面介紹主要的三種:
3.1.1 直接合并(straight merge):
把兩條分支上的歷史軌跡合并,交匯到一起异雁。比如要把dev分支上的所有東東合并到master分支:
- 首先先到master分支:git checkout master
- 然后把dev給合并過來:git merge dev
- 注意沒參數(shù)的情況下merge是fast-forward的捶障,即Git將master分支的指針直接移到dev的最前方。
- 換句話說纲刀,如果順著一個分支走下去可以到達另一個分支的話项炼,那么Git在合并兩者時,只會簡單移動指針示绊,所以這種合并成為
快進式(Fast-forward)
锭部。
3.1.2 壓合合并(squashed commits):
將一條分支上的若干個提交條目壓合成一個提交條目,提交到另一條分支的末梢面褐。
把dev分支上的所有提交壓合成主分支上的一個提交拌禾,即壓合提交:
$ git checkout master
$ git merge --squash dev
此時,dev上的所有提交已經(jīng)合并到當前工作區(qū)并暫存展哭,但還沒有作為一個提交湃窍,可以像其他提交一樣,把這個改動提交到版本庫中:
$ git commit –m “something from dev”
3.1.3 揀選合并(cherry-picking):
揀選另一條分支上的某個提交條目的改動帶到當前分支上摄杂。每一次提交都會產(chǎn)生一個全局唯一的提交名稱坝咐,利用這個名稱就可以進行揀選提交。
比如在dev上的某個提交叫:321d76f
把它合并到master中:
$ git checkout master
$ git cherry-pick 321d76f
要揀選多個提交析恢,可以給git cherry-pick命令傳遞-n選項墨坚,比如:
$ git cherry-pick –n 321d76f
這樣在揀選了這個改動之后,進行暫存而不立即提交映挂,接著可以進行下一個揀選操作泽篮,一旦揀選完需要的各個提交,就可以一并提交柑船。
3.2 沖突處理
當兩條分支對同一個文件的同一個文本塊進行了不同的修改帽撑,并試圖合并時,Git不能自動合并的鞍时,稱之為沖突(conflict)
亏拉。解決沖突需要人工處理扣蜻。
比如當前在master
分支,想把dev
分支merge
過來及塘,結(jié)果產(chǎn)生了一個沖突莽使,打開文件內(nèi)容可以看到這么一個沖突:
<<<<<<< HEAD
test in master
=======
test in dev
>>>>>>> dev
<<<<<<<
標記沖突開始,后面跟的是當前分支中的內(nèi)容笙僚。
HEAD指向當前分支末梢的提交芳肌。
=======
之后,>>>>>>>
之前是要merge過來的另一條分支上的代碼肋层。
>>>>>>>
之后的dev是該分支的名字亿笤。
對于簡單的合并,手工編輯栋猖,然后去掉這些標記净薛,最后像往常的提交一樣先add再commit即可。
3.3 刪除分支
有些分支沒有必要長期保存蒲拉,比如分支中的代碼已經(jīng)打了標簽并已發(fā)布罕拂,或者實驗分支已經(jīng)成功完成工作或中途廢棄等等。
注意:打了標簽的分支全陨,Git在刪除該分支時爆班,從版本樹起始到此標簽間的全部歷史軌跡均會保留,此時刪除分支操作只是刪除分支本身的名稱辱姨,因此可以說該分支沒有必要長期保存柿菩。
而在其他版本控制工具中,刪除分支通常意味著刪除分支上的所有歷史軌跡雨涛,所以不能因為打了標簽就認為其沒有必要保存枢舶。
刪除一個分支dev2:
$ git branch –d dev2
注意不能刪除當前所在分支,需要轉(zhuǎn)到別的分支上替久。
如果要刪除的分支已經(jīng)成功合并到當前分支凉泄,刪除分支的操作會直接成功。
如果要刪除的分支沒有合并到當前所在分支蚯根,則會出現(xiàn)提示后众,如果確定無須合并而要直接刪除,則執(zhí)行命令:
$ git branch –D dev2
進行強刪颅拦。
四蒂誉、Git 版本回退
在版本迭代開發(fā)過程中,相信很多人都會有過錯誤提交的時候距帅。這種情況下右锨,菜鳥程序員可能就會虎驅(qū)一震,緊張得不知所措碌秸。而資深程序員就會微微一笑绍移,摸一摸锃亮的腦門悄窃,然后默默的進行版本回退。
對于版本的回退蹂窖,我們經(jīng)常會用到兩個命令:
$ git reset
$ git revert
那這兩個命令有何區(qū)別呢广匙?先不急,我們后文詳細介紹恼策。
4.1 git reset
假如我們的系統(tǒng)現(xiàn)在有如下幾個提交:
其中:A 和 B 是正常提交,而 C 和 D 是錯誤提交〕奔簦現(xiàn)在涣楷,我們想把 C 和 D 回退掉。而此時抗碰,HEAD 指針指向 D 提交(5lk4er)狮斗。我們只需將 HEAD 指針移動到 B 提交(a0fvf8),就可以達到目的弧蝇。
只要有 git 基礎的朋友碳褒,一定會想到 git reset 命令。完整命令如下:
$ git reset --hard a0fvf8
命令運行之后看疗,HEAD 指針就會移動到 B 提交下沙峻,如下圖示:
而這個時候,遠程倉庫的 HEAD 指針依然不變两芳,仍在 D 提交上摔寨。所以,如果直接使用
git push
命令的話怖辆,將無法將更改推到遠程倉庫是复。此時,只能使用-f
選項將提交強制推到遠程倉庫:
$ git push -f
采用這種方式回退代碼的弊端顯而易見竖螃,那就是會使 HEAD 指針往回移動淑廊,從而會失去之后的提交信息。將來如果突然發(fā)現(xiàn)特咆,C 和 D 是多么絕妙的想法季惩,可它們已經(jīng)早就消失在歷史的長河里了。
而且腻格,有些公司明令禁止使用 git reset
命令去回退代碼蜀备,原因與上述一樣。所以荒叶,我們需要找到一個命令碾阁,既可以回退代碼,又可以保存錯誤的提交些楣。這時脂凶,git revert
命令就派上用場了宪睹。
4.2 git revert
git revert
的作用通過反做創(chuàng)建一個新的版本,這個版本的內(nèi)容與我們要回退到的目標版本一樣蚕钦,但是HEAD指針是指向這個新生成的版本亭病,而不是目標版本。
使用 git revert
命令來實現(xiàn)上述例子的話嘶居,我們可以這樣做:先 revert D罪帖,再 revert C (有多個提交需要回退的話需要由新到舊進行 revert):
$ git revert 5lk4er
$ git revert 76sdeb
這里只有兩個提交需要 revert,我們可以一個個回退邮屁。但如果有幾十個呢整袁?一個個回退肯定效率太低而且容易出錯。我們可以使用以下方法進行批量回退:
$ git revert OLDER_COMMIT^..NEWER_COMMIT
這時佑吝,錯誤的提交 C 和 D 依然保留坐昙,將來進行甩鍋的時候也有依可循。而且芋忿,這樣操作的話 HEAD 指針是往后移動的炸客,可以直接使用 git push
命令推送到遠程倉庫里。而這種做法戈钢,正是企業(yè)所鼓勵的痹仙。
我們再舉個更難一點的例子。
假如現(xiàn)在有三個提交殉了,但很不巧的是蝶溶,那個錯誤的提交剛好位于中間。如下圖示:
這時宣渗,直接使用 git reset命令將 HEAD 指針重置到 A 提交顯然是不行的抖所,因為 C 提交是正確的,需要保留的痕囱。先把 C 提交 及 B 提交全部回退田轧,再使用 cherry-pick 命令將 C 提交重新再生成一個新的提交 C’’,這樣就實現(xiàn)了將 B提交回退的需求鞍恢。完整的過程如下:
通過以上對比可以發(fā)現(xiàn)傻粘,
git reset
與 git revert
最大的差別就在于,git reset
會失去后面的提交帮掉,而git revert
是通過反做的方式重新創(chuàng)建一個新的提交弦悉,而保留原有的提交。在企業(yè)里蟆炊,應盡量使用 git revert
命令稽莉,能不用 git reset
命令盡量不用。
五涩搓、命名規(guī)范
5.1 主版本
.次版本
.修訂號
1.0.0
版本號主要有3部分構(gòu)成(由兩個.
分割成三部分)主版本
污秆、次版本
劈猪、修訂號
:
主版本:程序的主版本號,除非系統(tǒng)做整體重構(gòu)良拼,一般不變化
次版本:功能版本號战得,一般為功能迭代的版本號,每次版本號為上一次正常按迭代計劃發(fā)版的次版本
+ 1;主版本
發(fā)生變更庸推,次版本
需重置為0
比如:上次按正常按迭代計劃發(fā)版的版本號為v1.9.0常侦,本次版本號為 v1.(9+1)
.0,即 v1.10.0
修訂號:每次線上BUG修復贬媒,該版本號相對上次修訂號
+1 (前提:相同主版本
以及次版本
);主版本
和次版本
發(fā)生變更聋亡,修訂號
需重置為0
比如:上次修訂號為v1.9.3,本次版本號為 v1.9.(3+1)
掖蛤,即 v1.9.4
5.2 分支命名規(guī)范
5.2.1 主分支:
master:master 分支就叫 master 分支
develop:develop 分支就叫 develop 分支
5.2.2 輔助分支:
5.2.2.1 Feature 分支
feature/v1.16.0_xxx
feature/v1.16.0_yyy
feature/v1.16.0_zzz
v1.16.0
表示當前迭代的版本號,xxx
井厌、yyy
蚓庭、zzz
表示當前迭代的功能或業(yè)務單元的名稱
5.2.2.2 Release 分支
release/v1.17.0
release/v1.18.0
v1.17.0
、v1.18.0
根據(jù)上線需求和系統(tǒng)上線計劃仅仆,合理規(guī)劃版本號器赞,每個大版本號表示一次上線正常上線過程。
5.2.2.3 Hotfix 分支
hotfix/v1.17.1
hotfix/v1.17.2
v1.17.1
墓拜、v1.17.2
表示v1.17.0 這個版本做了2次線上問題熱修復港柜。
六、總結(jié)
并行開發(fā):依據(jù)迭代的發(fā)版計劃和任務分解咳榜,創(chuàng)建feature(不同迭代需通過版本號隔離夏醉,同一個迭代內(nèi)要上線的功能需要通過feature隔離)
保持迭代內(nèi)代碼的可預見性&可控制性:
迭代內(nèi),只允許主迭代的feature代碼提交到develop分支哪里有問題改哪里涌韩,改完后及時合并到主分支:
release(fit)環(huán)境的問題修復:應從release分支拉出分支進行問題修復畔柔,修復后及時合并到develop主分支
master環(huán)境的問題修復:應從生產(chǎn)環(huán)境對應的tag(一般為最新的版本號)拉出分支進行問題修復,問題修復后及時合并代碼至develop主分支和master主分支