私有的小型團隊
我們從最簡單的情況開始,一個私有項目,與你一起協作的還有另外一到兩位開發者。這裏說私有,是指源代碼不公開,其他人無法訪問項目倉庫。而你和其他開發者則都具有推送數據到倉庫的權限。
這種情況下,你們可以用 Subversion 或其他集中式版本控制系統類似的工作流來協作。你仍然可以得到 Git 帶來的其他好處:離線提交,快速分支與合併等等,但工作流程還是差不多的。主要區別在於,合併操作發生在客戶端而非服務器上。讓我們來看看,兩個開發者一起使用同一個共享倉庫,會發生些什麼。第一個人,John,克隆了倉庫,作了些更新,在本地提交。(下面的例子中省略了常規提示,用 ...
代替以節約版面。)
# John's Machine
$ git clone john@githost:simplegit.git
Initialized empty Git repository in /home/john/simplegit/.git/
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'removed invalid default value'
[master 738ee87] removed invalid default value
1 files changed, 1 insertions(+), 1 deletions(-)
第二個開發者,Jessica,一樣這麼做:克隆倉庫,提交更新:
# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Initialized empty Git repository in /home/jessica/simplegit/.git/
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
1 files changed, 1 insertions(+), 0 deletions(-)
現在,Jessica 將她的工作推送到服務器上:
# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
1edee6b..fbff5bc master -> master
John 也嘗試推送自己的工作上去:
# John's Machine
$ git push origin master
To john@githost:simplegit.git
! [rejected] master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'
John 的推送操作被駁回,因爲 Jessica 已經推送了新的數據上去。請注意,特別是你用慣了 Subversion 的話,這裏其實修改的是兩個文件,而不是同一個文件的同一個地方。Subversion 會在服務器端自動合併提交上來的更新,而 Git 則必須先在本地合併後才能推送。於是,John 不得不先把 Jessica 的更新拉下來:
$ git fetch origin
...
From john@githost:simplegit
+ 049d078...fbff5bc master -> origin/master
此刻,John 的本地倉庫如圖 5-4 所示:
圖 5-4. John 的倉庫歷史
雖然 John 下載了 Jessica 推送到服務器的最近更新(fbff5),但目前只是 origin/master
指針指向它,而當前的本地分支 master
仍然指向自己的更新(738ee),所以需要先把她的提交合並過來,才能繼續推送數據:
$ git merge origin/master
Merge made by recursive.
TODO | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
還好,合併過程非常順利,沒有衝突,現在 John 的提交歷史如圖 5-5 所示:
圖 5-5. 合併 origin/master 後 John 的倉庫歷史
現在,John 應該再測試一下代碼是否仍然正常工作,然後將合併結果(72bbc)推送到服務器上:
$ git push origin master
...
To john@githost:simplegit.git
fbff5bc..72bbc59 master -> master
最終,John 的提交歷史變爲圖 5-6 所示:
圖 5-6. 推送後 John 的倉庫歷史
而在這段時間,Jessica 已經開始在另一個特性分支工作了。她創建了 issue54
並提交了三次更新。她還沒有下載
John 提交的合併結果,所以提交歷史如圖 5-7 所示:
圖 5-7. Jessica 的提交歷史
Jessica 想要先和服務器上的數據同步,所以先下載數據:
# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
fbff5bc..72bbc59 master -> origin/master
於是 Jessica 的本地倉庫歷史多出了 John 的兩次提交(738ee 和 72bbc),如圖 5-8 所示:
圖 5-8. 獲取 John 的更新之後 Jessica 的提交歷史
此時,Jessica 在特性分支上的工作已經完成,但她想在推送數據之前,先確認下要並進來的數據究竟是什麼,於是運行 git
log
查看:
$ git log --no-merges origin/master ^issue54
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date: Fri May 29 16:01:27 2009 -0700
removed invalid default value
現在,Jessica 可以將特性分支上的工作併到 master
分支,然後再併入 John 的工作(origin/master
)到自己的 master
分支,最後再推送回服務器。當然,得先切回主分支才能集成所有數據:
$ git checkout master
Switched to branch "master"
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.
要合併 origin/master
或 issue54
分支,誰先誰後都沒有關係,因爲它們都在上游(upstream)(譯註:想像分叉的更新像是匯流成河的源頭,所以上游
upstream 是指最新的提交),所以無所謂先後順序,最終合併後的內容快照都是一樣的,而僅是提交歷史看起來會有些先後差別。Jessica 選擇先合併 issue54
:
$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
README | 1 +
lib/simplegit.rb | 6 +++++-
2 files changed, 6 insertions(+), 1 deletions(-)
正如所見,沒有衝突發生,僅是一次簡單快進。現在 Jessica 開始合併 John 的工作(origin/master
):
$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by recursive.
lib/simplegit.rb | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
所有的合併都非常乾淨。現在 Jessica 的提交歷史如圖 5-9 所示:
圖 5-9. 合併 John 的更新後 Jessica 的提交歷史
現在 Jessica 已經可以在自己的 master
分支中訪問 origin/master
的最新改動了,所以她應該可以成功推送最後的合併結果到服務器上(假設
John 此時沒再推送新數據上來):
$ git push origin master
...
To jessica@githost:simplegit.git
72bbc59..8059c15 master -> master
至此,每個開發者都提交了若干次,且成功合併了對方的工作成果,最新的提交歷史如圖 5-10 所示:
圖 5-10. Jessica 推送數據後的提交歷史
以上就是最簡單的協作方式之一:先在自己的特性分支中工作一段時間,完成後合併到自己的 master
分支;然後下載合併 origin/master
上的更新(如果有的話),再推回遠程服務器。一般的協作流程如圖
5-11 所示:
圖 5-11. 多用戶共享倉庫協作方式的一般工作流程時序
git 在線學習地址:http://git.oschina.net/progit/5-%E5%88%86%E5%B8%83%E5%BC%8F-Git.html#5.2-%E4%B8%BA%E9%A1%B9%E7%9B%AE%E4%BD%9C%E8%B4%A1%E7%8C%AE