讓我們一起逐步分解來看看一個常見的小團(tuán)隊(duì)如何用這個工作流來協(xié)作的。有兩個開發(fā)者小明和小紅,看他們是如何開發(fā)自己的功能并提交到中央倉庫上的。
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-initialize.png" alt="" />
第一步,有人在服務(wù)器上創(chuàng)建好中央倉庫。如果是新項(xiàng)目,你可以初始化一個空倉庫;否則你要導(dǎo)入已有的 Git
或 SVN
倉庫。
中央倉庫應(yīng)該是個裸倉庫( bare repository
),即沒有工作目錄( working directory
)的倉庫??梢杂孟旅娴拿顒?chuàng)建:
ssh user@host
git init --bare /path/to/repo.git
確保寫上有效的 user
( SSH
的用戶名),host
(服務(wù)器的域名或IP地址),/path/to/repo.git
(你想存放倉庫的位置)。
注意,為了表示是一個裸倉庫,按照約定加上 .git
擴(kuò)展名到倉庫名上。
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-clone.png" alt="" />
下一步,各個開發(fā)者創(chuàng)建整個項(xiàng)目的本地拷貝。通過 git clone
命令完成:
git clone ssh://user@host/path/to/repo.git
基于你后續(xù)會持續(xù)和克隆的倉庫做交互的假設(shè),克隆倉庫時 Git
會自動添加遠(yuǎn)程別名 origin
指回『父』倉庫。
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-1.png" alt="" />
在小明的本地倉庫中,他使用標(biāo)準(zhǔn)的 Git
過程開發(fā)功能:編輯、暫存(Stage
)和提交。
如果你不熟悉暫存區(qū)(Staging Area
),這里說明一下:暫存區(qū)用來準(zhǔn)備一個提交,但可以不用把工作目錄中所有的修改內(nèi)容都包含進(jìn)來。
這樣你可以創(chuàng)建一個高度聚焦的提交,盡管你本地修改很多內(nèi)容。
git status # 查看本地倉庫的修改狀態(tài)
git add # 暫存文件
git commit # 提交文件
請記住,因?yàn)檫@些命令生成的是本地提交,小明可以按自己需求反復(fù)操作多次,而不用擔(dān)心中央倉庫上有了什么操作。 對需要多個更簡單更原子分塊的大功能,這個做法是很有用的。
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-2.png" alt="" />
與此同時,小紅在自己的本地倉庫中用相同的編輯、暫存和提交過程開發(fā)功能。和小明一樣,她也不關(guān)心中央倉庫有沒有新提交; 當(dāng)然更不關(guān)心小明在他的本地倉庫中的操作,因?yàn)樗斜镜貍}庫都是私有的。
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-3.png" alt="" />
一旦小明完成了他的功能開發(fā),會發(fā)布他的本地提交到中央倉庫中,這樣其它團(tuán)隊(duì)成員可以看到他的修改。他可以用下面的 git push
命令:
git push origin master
注意,origin
是在小明克隆倉庫時 Git
創(chuàng)建的遠(yuǎn)程中央倉庫別名。master
參數(shù)告訴 Git
推送的分支。
由于中央倉庫自從小明克隆以來還沒有被更新過,所以 push
操作不會有沖突,成功完成。
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-4.png" alt="" />
一起來看看在小明發(fā)布修改后,小紅 push
修改會怎么樣?她使用完全一樣的 push
命令:
git push origin master
但她的本地歷史已經(jīng)和中央倉庫有分岐了,Git
拒絕操作并給出下面很長的出錯消息:
error: failed to push some refs to '/path/to/repo.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.
這避免了小紅覆寫正式的提交。她要先 pull
小明的更新到她的本地倉庫合并上她的本地修改后,再重試。
rebase
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-5.png" alt="" />
小紅用 git pull
合并上游的修改到自己的倉庫中。
這條命令類似 svn update
——拉取所有上游提交命令到小紅的本地倉庫,并嘗試和她的本地修改合并:
git pull --rebase origin master
--rebase
選項(xiàng)告訴 Git
把小紅的提交移到同步了中央倉庫修改后的 master
分支的頂部,如下圖所示:
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-6.png" alt="" />
如果你忘加了這個選項(xiàng),pull
操作仍然可以完成,但每次 pull
操作要同步中央倉庫中別人修改時,提交歷史會以一個多余的『合并提交』結(jié)尾。
對于集中式工作流,最好是使用 rebase
而不是生成一個合并提交。
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-7.png" alt="" />
rebase
操作過程是把本地提交一次一個地遷移到更新了的中央倉庫master
分支之上。
這意味著可能要解決在遷移某個提交時出現(xiàn)的合并沖突,而不是解決包含了所有提交的大型合并時所出現(xiàn)的沖突。
這樣的方式讓你盡可能保持每個提交的聚焦和項(xiàng)目歷史的整潔。反過來,簡化了哪里引入 Bug
的分析,如果有必要,回滾修改也可以做到對項(xiàng)目影響最小。
如果小紅和小明的功能是不相關(guān)的,不大可能在 rebase
過程中有沖突。如果有,Git
在合并有沖突的提交處暫停 rebase
過程,輸出下面的信息并帶上相關(guān)的指令:
CONFLICT (content): Merge conflict in <some-file>
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-8.png" alt="" />
Git
很贊的一點(diǎn)是,任何人可以解決他自己的沖突。在這個例子中,小紅可以簡單的運(yùn)行 git status
命令來查看哪里有問題。
沖突文件列在 Unmerged paths
(未合并路徑)一節(jié)中:
# Unmerged paths:
# (use "git reset HEAD <some-file>..." to unstage)
# (use "git add/rm <some-file>..." as appropriate to mark resolution)
#
# both modified: <some-file>
接著小紅編輯這些文件。修改完成后,用老套路暫存這些文件,并讓 git rebase
完成剩下的事:
git add <some-file>
git rebase --continue
要做的就這些了。Git
會繼續(xù)一個一個地合并后面的提交,如其它的提交有沖突就重復(fù)這個過程。
如果你碰到了沖突,但發(fā)現(xiàn)搞不定,不要驚慌。只要執(zhí)行下面這條命令,就可以回到你執(zhí)行 git pull --rebase
命令前的樣子:
git rebase --abort
http://wiki.jikexueyuan.com/project/git-workflow-tutorial/images/git-workflow-svn-9.png" alt="" />
小紅完成和中央倉庫的同步后,就能成功發(fā)布她的修改了:
git push origin master
如你所見,僅使用幾個 Git
命令我們就可以模擬出傳統(tǒng) Subversion
開發(fā)環(huán)境。對于要從 SVN
遷移過來的團(tuán)隊(duì)來說這太好了,但沒有發(fā)揮出 Git
分布式本質(zhì)的優(yōu)勢。
如果你的團(tuán)隊(duì)適應(yīng)了集中式工作流,但想要更流暢的協(xié)作效果,絕對值得探索一下 功能分支工作流
的收益。
通過為一個功能分配一個專門的分支,能夠做到一個新增功能集成到正式項(xiàng)目之前對新功能進(jìn)行深入討論。