前些時間,公司產(chǎn)品經(jīng)理針對司機端提出一個微信及支付寶二維碼掃碼支付需求,需求不急,但也是剛性任務(wù),于是我在會后便火急火燎開干,期間碰到一些問題獲取了一些經(jīng)驗,想分享給各位。
第一個問題,期間,或許因為公司反復(fù)修網(wǎng)造成GitLab地址變動,管理GitLab的后臺并沒有多余的時間來維護,所以短時間內(nèi),并不能將本地的修改 push
到遠程。這種情況下,我將每次的修改 commit
到本地,等GitLab好了再 push
,對此我深刻感受到Git的好處。
第二個問題,在公司我負責(zé)iOS移動端的獨立開發(fā)與維護。由于是獨立開發(fā),使用Git時,我一般在 dev
上 fix bug
或者改需求。此次,我需求完成一半,測試那邊給出反饋,我放下手頭需求,緊急 fix bug
,commit
到本地后,在無法 push
到遠程的情況下,我需要緊急提交一個新版本。問題來了,由于GitLab未修復(fù),我無法clone
上個版本到本地來fix bug
,又因為我dev分支上同時fix bug
和迭代需求,本地也不是上一個版本。
創(chuàng)建與合并分支
在Git里,每次提交,Git把提交串成一個分支,這個分支是主分支,即 master
分支。HEAD
不是指向提交,而是指向 master
,master
才指向提交,所以,HEAD
指向的是當(dāng)前分支。
Git創(chuàng)建一個 dev
分支時很快,因為除了需要增加一個 dev
指針,改變 HEAD
的指向,工作區(qū)的文件沒有變。
Git合并 dev
分支到 master
分支也很快,在 dev
上完成工作后,直接把 master
指向 dev
當(dāng)前的提交,就完成了合并。合并過程中,指針指向改變,工作區(qū)內(nèi)容同樣沒有變。
- 創(chuàng)建
dev
分支,然后切換到dev
分支
git checkout -b dev
- 創(chuàng)建分支
git branch <name>
- 切換分支
git checkout <name>
- 用
git branch
查看當(dāng)前分支
$ git branch
* dev
master
-
git merge
命令用于合并指定分支到當(dāng)前分支
git merge <name>
- 刪除分支
git branch -d <name>
解決沖突
- 創(chuàng)建并切換
feature
分支
$ git checkout -b feature
Switched to a new branch feature
- 修改工作區(qū)內(nèi)容后,在
feature
分支上提交修改并且將暫存區(qū)的修改commit
到當(dāng)前分支
$ git add readme.txt
$ git commit -m "and simple"
[feature 75a857c] and simple
1 file changed, 1 insertion(+), 1 deletion(-)
- 切換到
master
分支,系統(tǒng)將會提示當(dāng)前master
分支彼遠程的master
分支要超前一個提交
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit
- 在
master
分支上把工作區(qū)內(nèi)容進行修改,并且提交
$ git add readme.txt
$ git commit -m "& simple"
[master 400b400] & simple
1 file changed, 1 insertion(+), 1 deletion(-)
- 此刻在master分支和feature分支都要提交的情況下,Git無法進行快速合并,如果試圖把各自的修改合并,將會造成沖突。
$ git merge feature
Auto-merging readme.txt
CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.
- Git將會提示,readme.txt文件存在沖突,必須手動解決沖突后再提交,我們一般使用
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用
<<<<<<<
,=======
,>>>>>>>
標記出不同分支的內(nèi)容,我們修改文件夾下內(nèi)容使feature
分支和master
分支保持一致后,再提交。使用帶參數(shù)的
git log
也可以看到分支的合并情況
$ git log --graph --pretty=oneline --abbrev-commit
* 59bc1cb conflict fixed
|\
| * 75a857c AND simple
* | 400b400 & simple
|/
* fec145a branch test
...
- 最后刪除分支
$ git branch -d feature
Deleted branch feature (was 75a857c).
- 所以說,當(dāng)Git無法自動合并分支時,就必須首先解決沖突,解決沖突后,再提交,合并完成。使用
git log --graph
命令可以查看分支合并圖
分支管理策略
在解決沖突時,我們提到了快速合并,通常,我們在合并分支時,Git會使用 Fast forward
模式,在 Fast forward
模式下,刪除分支后,會丟失分支信息。
所以,我們會強制禁用 Fast forward
模式,Git會在 merge
時生成一個新的 commit
,這樣我們可以在分支歷史上查看分支信息。
--no-ff方式的git merge
- 首先,創(chuàng)建并切換
dev
分支
$ git checkout -b dev
Switched to a new branch dev
- 修改工作區(qū)readme.txt文件,并提交一個新的
commit
$ git add readme.txt
$ git commit -m "add merge"
[dev 6224937] add merge
1 file changed, 1 insertion(+)
- 切換回
master
$ git checkout master
Switched to branch 'master'
- 合并
dev
分支時,注意使用--no-ff
參數(shù),表示禁用Fast forward
$ git merge --no-ff -m "merge with --no-ff" dev
Merge made by the 'recursive' strategy.
readme.txt | 1 +
1 file changed, 1 insertion(+)
- 合并后我們使用
git log
查看分支歷史
$ git log --graph --pretty=oneline --abbrev-commit
* 7825a50 merge with no-ff
|\
| * 6224937 add merge
|/
* 59bc1cb conflict fixed
...
分支策略
其實,我們在實際開發(fā)中,應(yīng)該按照幾個基本原則進行分支管理:
首先,
master
分支應(yīng)該是最穩(wěn)定的,也就是說,我們平時不能在master
上干活,master
分支僅用來發(fā)布版本使用。如果要干活,我們應(yīng)該創(chuàng)建并切換一個分支,這個分支就是
dev
分支。也就是說,dev
分支是不穩(wěn)定的,平時我們各自在dev
分支上干活,每個人有自己的分支,不斷往dev
分支上合并,等到版本發(fā)布時,再把dev
分支合并到master
上。
Bug分支
當(dāng)前,正在 dev
上的工作還沒提交,我們需要經(jīng)緊急修復(fù)一個bug,很自然地,需要創(chuàng)建一個 bug
分支來修復(fù)這個bug。有人會有疑問,為什么不把 dev
上工作區(qū)的修改先進行提交,其實我們并不是不想提交,而是工作進行到一半無法提交。那么,Git為我們提供一個 stash
功能,先把當(dāng)前工作現(xiàn)場“儲藏”起來,等恢復(fù)現(xiàn)場后繼續(xù)工作。
$ git stash
Saved working directory and index state WIP on dev: 6224937 add merge
HEAD is now at 6224937 add merge
git stash
后,我們用git status
查看工作區(qū),工作區(qū)是干凈的,我們可以放心創(chuàng)建分支修復(fù)bug。確定在那個分支上修復(fù)bug,就在那個分支上創(chuàng)建bug分支。此次我們在
master
上修復(fù),就從master
上創(chuàng)建臨時分支。由于創(chuàng)建的bug
分支是臨時分支,修復(fù)bug后,切換到master
分支,完成合并,最后刪除bug
分支。接著我們回到
dev
干活,使用git status
查看工作區(qū)狀態(tài),發(fā)現(xiàn)工作區(qū)是干凈的,這是我們需要使用git stash list
查看存的工作現(xiàn)場。
$ git stash list
stash@{0}: WIP on dev: 6224937 add merge
使用
git stash apply
恢復(fù),但是恢復(fù)后,stash內(nèi)容不會刪除,需要使用git stash drop
刪除stash內(nèi)容。或者,使用
git stash pop
,恢復(fù)的同時把stash內(nèi)容也刪除了。
$ git stash pop
# On branch dev
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# new file: hello.py
#
# 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.txt
#
Dropped refs/stash@{0} (f624f8e5f082f2df2bed8a4e09c12fd2943bdd40)
- 使用
git stash pop
后,使用git stash list
查看,就看不到stash內(nèi)容了。
Feature分支
一般情況下,添加一個新功能,需要創(chuàng)建一個 feature
分支,feature
分支作為臨時開發(fā)新功能的分支最終要合并到 dev
分支,也就是說,我們添加一個新功能,并不是在 dev
上進行開發(fā),而是要創(chuàng)建一個 feature
分支,而這個 feature
分支用于臨時開發(fā)一個新功能,是一個臨時分支。
其實,
feature
分支和bug
分支類似,創(chuàng)建切換,合并,然后刪除。取消新功能時,使用
git branch -d <name>
刪除分支,但是會提示銷毀失敗,這時需要強行刪除分支,使用命令git branch -D <name>
。
$ git branch -D feature-vulcan
Deleted branch feature-vulcan (was 756d4af).
- 所以,如果要丟棄一個沒有被合并的分支,可以通過
git branch -D <name>
強行刪除這個分支。
多人協(xié)作
真正意義上,Git的價值還是體現(xiàn)在團隊協(xié)作作用上,而那些命令其實僅僅起到輔助協(xié)作的作用,如果是獨立開發(fā)并不能深刻體會到這種協(xié)作的作用,但是如果進入純技術(shù)公司團隊,可能Git的這種協(xié)作價值才能真正的體現(xiàn)出來。
從遠程倉庫
clone
時,實際上Git自動把本地master
分支和遠程master
分支對應(yīng)起來了,并且,遠程倉庫默認的名稱是origin
。所以說,我們使用
git remote
查看遠程倉庫的信息
$ git remote
origin
- 或者,用
git remote -v
查看遠程庫詳細信息
$ git remote -v
origin git@github.com:michaelliao/learngit.git (fetch)
origin git@github.com:michaelliao/learngit.git (push)
推送分支
master
分支在本地作為主分支,要時刻與遠程倉庫同步。dev
分支是開發(fā)分支,團隊所有成員都需要在dev
分支上工作,所以dev
分支同樣需要與遠程同步。bug
分支作為臨時分支,只在本地修復(fù)bug,沒有必要推送到遠程,可能一周推送一次。feature
分支同樣是臨時分支,但是,feature
分支是否推送到分支,取決于是否團隊協(xié)作,如果是獨立開發(fā),feature
分支沒有必要推送到遠程,如果協(xié)作開發(fā),需要推送到遠程,與遠程保持同步。
抓取分支
- 從遠程庫
clone
時默認只能看到本地的master
分支,我們可以使用git stauts
查看。
$ git branch
* master
- 要在
dev
分支上開發(fā),必須創(chuàng)建遠程origin
的dev
分支到本地,可以使用git checkout -b dev origin/dev
命令創(chuàng)建本地dev
分支。
$ git checkout -b dev origin/dev
- 可以在本地創(chuàng)建的這個
dev
分支上修改,并且把修改commit
到dev
分支,然后把dev
分支push
到遠程。
$ git commit -m "add /usr/bin/env"
[dev 291bea8] add /usr/bin/env
1 file changed, 1 insertion(+)
$ git push origin dev
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 349 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
fc38031..291bea8 dev -> dev
- 由于你已經(jīng)向
origin/dev分支
推送了提交,而devB碰巧對同樣的文件做了修改,并且試圖推送,由于我的最新提交和devB試圖推送的提交有沖突,所以,推送失敗。
$ git add hello.py
$ git commit -m "add coding: utf-8"
[dev bd6ae48] add coding: utf-8
1 file changed, 1 insertion(+)
$ git push origin dev
To git@github.com:michaelliao/learngit.git
! [rejected] dev -> dev (non-fast-forward)
error: failed to push some refs to 'git@github.com:michaelliao/learngit.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
- 這時,Git提醒,先用
git pull
把最新的提交從origin/dev
抓取下來,然后,在本地合并,先解決沖突,然后再推送到遠程。
$ 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:michaelliao/learngit
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
失敗,因為未指定本地dev
分支和遠程origin/dev
分支鏈接,所以,設(shè)置dev
和遠程origin/dev
的鏈接。
$ git branch --set-upstream dev origin/dev
Branch dev set up to track remote branch dev from origin.
-
git pull
成功后,git merge
合并存在沖突,先手動解決沖突,然后提交,最后push
到遠程。
$ git commit -m "merge & fix hello.py"
[dev adca45d] merge & fix hello.py
$ git push origin dev
Counting objects: 10, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (6/6), 747 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
To git@github.com:michaelliao/learngit.git
291bea8..adca45d dev -> dev
- 請記住,如果
git pull
提示“no tracking information“,則說明本地分支和遠程分支的鏈接關(guān)系沒有創(chuàng)建,使用命令git branch --set-upstream branch-name origin/branch-name
,以上就是多人協(xié)作的工作模式。