git 入門教程之協同開發

雪之夢技術驛站發表於2019-03-24

前面我們已經介紹過遠端倉庫的相關概念,不過那時並沒有深入探討,只是講解了如何建立遠端倉庫以及推送最新工作成果到遠端倉庫,實際上遠端倉庫對於團隊協同開發很重要,不僅僅是團隊協同開發的基礎,也是程式碼備份的保障手段,現在我們先簡單回憶下相關概念,以便為接下來的協同開發做好鋪墊!

遠端倉庫和遠端分支

遠端倉庫

遠端倉庫其實並不複雜,實際上只是本地電腦上的本地倉庫在另一臺遠端電腦的備份而已.

相對本地倉庫來說遠端電腦上的版本庫自然就是遠端倉庫,遠端倉庫使得我們的版本庫更加安全,畢竟遠端電腦可不是一般的電腦,出錯的概率比我們平時工作所使用的電腦概率要小得多,這樣一來即使不小心丟失了本地倉庫的全部資料,只要遠端倉庫沒有丟失,那我們就可以通過遠端倉庫重新取回最新資料!

還有一點,遠端倉庫讓程式碼社交化,因為大家有了一致途徑來訪問遠端倉庫,團隊也好或者陌生人也罷,只有你願意,他們就可以獲取遠端倉庫的最新程式碼並參與開發,這也是 github 的一大亮點!

遠端分支

回顧好遠端倉庫的概念後,我們再來講一下本地倉庫的遠端分支是什麼意思?

當前你正在工作的電腦上儲存的是本地倉庫,如果沒有遠端倉庫的支援,只能一個人鼓搗,別人無法共享你的工作成果,現在加入了團隊開發流程,自然不再一個人獨自開發,需要和團隊其他人協同開發,共享開發成果.

所以本地倉庫必然儲存著遠端倉庫的基本資訊,只有區分好自己的工作成果公共成果,才能不亂套,又能做到資訊及時共享.

實際上,在專案初期剛剛拷貝遠端倉庫(git clone)時,git 已經預設在本地倉庫建立一個遠端分支(origin/master),本地修改提交首先都是在本地倉庫完成的,比如 git add,git commit 等命令,如果需要釋出你的工作成果,那麼就需要使用 git push origin <branch> 命令推送到遠端倉庫,這裡的 origin 指的就是遠端倉庫名稱(因為最初大家都是先從遠端倉庫克隆下來的,所以遠端倉庫儲存的專案相當於原始專案,故而叫origin).

git clone 命令幫助本地倉庫的 master 分支和遠端倉庫的 master 分支建立了關聯,一般稱遠端倉庫名稱為 origin.

git-clone.png

檢視遠端倉庫資訊 : git remotegit remote -v

# 檢視遠端倉庫名稱
$ git remote
origin

# 檢視遠端倉庫詳情 : 拉取和推送連結
$ git remote -v
origin  git@github.com:snowdreams1006/git-demo.git (fetch)
origin  git@github.com:snowdreams1006/git-demo.git (push)
$ 
複製程式碼

本地分支推送到遠端倉庫 : git push origin <branch>

本地倉庫和遠端倉庫的分支理論上應該一一對應,本地倉庫的主幹分支叫做 master ,而遠端倉庫也有相應的分支叫做 master ,這種對映關係是使用 git clone 命令時預設生成的,也是推薦的做法.

一般來說,本地倉庫的分支推送到遠端倉庫指的就是推送到遠端倉庫同名的分支上,例如 git push origin master 意思是: 推將本地倉庫的 master 分支推送到遠端倉庫的 master分支,當然你也可以推送其他分支到相應的遠端分支上.

按照之前約定的分支管理策略來說,master 分支用於生產環境部署,dev 分支用於收集開發成果,feature 分支用於開發具體功能分支,既然如此,那這些本地分支哪些需要同步推送到遠端倉庫就比較清晰了!

  • 推送本地 master 分支到遠端倉庫的 master 分支 : git push origin master
  • 推送本地 dev 分支到元層倉庫的 dev 分支 : git push origin dev
# 檢視當前分支 : `master` 主分支
$ git branch
  dev
* master
  snow

# 推送本地 `master` 分支到遠端倉庫 `origin` 上相應的 `master` 分支 
$ git push origin master
Counting objects: 15, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (15/15), done.
Writing objects: 100% (15/15), 1.31 KiB | 1.31 MiB/s, done.
Total 15 (delta 9), reused 0 (delta 0)
remote: Resolving deltas: 100% (9/9), completed with 3 local objects.
To github.com:snowdreams1006/git-demo.git
   e60c8ad..dcce09c  master -> master
$ 
複製程式碼

git-branch-remote-github.png

正常來說,本地倉庫的 master 分支應該領先遠端倉庫 origin 上的 master 分支若干個版本.

git-branch-remote-commit.png

一旦我們已經將本地分支上的工作成果推送到遠端倉庫上相應分支時,本地倉庫和遠端倉庫這時候就保持一致了.

$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean
$ 
複製程式碼

git-branch-remote-master.png

遠端倉庫下載到本地分支 : git fetch

遠端倉庫的操作可以簡單歸納為兩部分: 上傳和下載.

本地倉庫推送到遠端倉庫是上傳,而遠端倉庫拉取到本地倉庫就是下載.

團隊多人協作開發時,大家都會定期或不定期往 masterdev 等分支上推送各自的更改,相應的我們就需要下載別人的最新工作成果.

現在模擬其他夥伴正在往 master 分支上推送更改,最好在另一個電腦另一個賬戶,當然模擬的話也可以是同一個電腦下其他目錄,或者最簡單的方式,直接登入 github 更改 master 分支上某個檔案內容,簡單起見,我們採用最後一種方式.

其他夥伴已往遠端倉庫上的 master 分支提交了新的版本: 建立 git-remote.txt 檔案

git-branch-remote-new-commit.png

現在我們想要下載其他人的最新工作成果,接下來讓我們看看本地倉庫的 master 還能和遠端倉庫的 master 分支保持一致嗎?

git-branch-remote-fetch.png

# 下載遠端倉庫的 `master` 分支
$ git fetch origin master
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), done.
From github.com:snowdreams1006/git-demo
 * branch            master     -> FETCH_HEAD
   dcce09c..10942ff  master     -> origin/master
$ 
複製程式碼

git-branch-remote-fetch-master.png

執行 git fetch 命令後,遠端倉庫上的最新提交記錄已經下載到本地倉庫,同時更新了本地倉庫的遠端分支origin/master ,值得注意的是本地倉庫的 master 分支並沒有更新!

那你可能會有疑問了,我想要的結果是下載其他人的最新工作成果,怎麼我本地倉庫的 master 分支並沒有更新呢?

# 檢視工作區
$ ls
LICENSE     README.md   test.txt

# 檢視版本庫狀態
$ git status
On branch master
Your branch is behind 'origin/master' by 1 commit, and can be fast-forwarded.
  (use "git pull" to update your local branch)

nothing to commit, working tree clean
$ 
複製程式碼

既然 git fetch 並沒有更新本地倉庫的 master 分支,那它到底做了哪些工作呢?

git fetch 會做的事情

實際上, git fetch 完成了僅有的但是很重要的兩步操作:

  • 從遠端倉庫下載本地倉庫中缺失的提交記錄
  • 更新本地倉庫的遠端分支(比如origin/master)

通過上述兩步操作完成的效果是: 將本地倉庫中的遠端分支更新成了遠端倉庫相應分支最新的狀態.

遠端分支實際上是反映了遠端倉庫在你最後一次與它通訊時的狀態,而git fetch 就是你與遠端倉庫通訊的方式了!

git fetch 不會做的事情

git fetch 並不會改變你本地倉庫的狀態,所以也就不會更新你的 master分支,自然也不會修改你磁碟上的檔案.

理解這一點很重要,因為許多開發人員誤以為執行了 git fetch 以後,他們本地倉庫就與遠端倉庫同步了.

實際上它可能已經將進行這一操作所需的所有資料都下載了下來,但是並沒有修改你本地的檔案.

既然本地倉庫的遠端分支已更新,那麼想要更新本地倉庫的 master 分支該如何做呢?很簡單,可以 git merge 啊!

遠端倉庫更新到本地分支 : git pull

其實通過 git fetch 命令我們已經下載了遠端倉庫的最新版本,只不過還沒有合併到本地倉庫而已,如何合併分支相信大家已經輕車熟路了,有很多方法:

  • git merge origin/master
  • git rebase origin/master
  • git cherry-pick origin/master

實際上,先抓取更新(git fetch)再合併(git merge)這個流程很常用,因此 git 是有專門的命令來完成這兩步操作的,這就是拉取更新**git pull** --- 剛好與推送更新 git push 相反!

# 拉取最新版本
$ git pull
Updating dcce09c..10942ff
Fast-forward
 git-remote.txt | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 git-remote.txt

# 檢視版本庫狀態
$ git status
On branch master
Your branch is up to date with 'origin/master'.

nothing to commit, working tree clean

# 檢視工作區內容: 檔案已更新
$ ls
LICENSE     README.md   git-remote.txt  test.txt
$ 
複製程式碼

git-branch-remote-pull.gif

團隊協作

掌握了遠端倉庫和遠端分支的相關概念後,現在開始真正模擬團隊協作開發了,為了簡單起見,仍然以直接操作 github 上的 master 分支為例說明如何協同開發.

(1). 其他人已往遠端倉庫推送2個版本

git-branch-remote-teamworks.png

(2). 你正在本地倉庫提交1個版本

$ echo "learn teamwork" >> test.txt
$ git commit -am "learn teamwork"
[master f971647] learn teamwork
 1 file changed, 1 insertion(+)
$ 
複製程式碼

git-branch-remote-teamwork-local-commit.png

(3). 你推送到遠端倉庫前先拉取最新版本

# 拉取最新版本,並嘗試合併
$ git pull
remote: Enumerating objects: 8, done.
remote: Counting objects: 100% (8/8), done.
remote: Compressing objects: 100% (5/5), done.
remote: Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), done.
From github.com:snowdreams1006/git-demo
   10942ff..612e08a  master     -> origin/master
Merge made by the 'recursive' strategy.
 git-remote.txt | 2 ++
 1 file changed, 2 insertions(+)

# 檢視版本庫狀態
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
  (use "git push" to publish your local commits)

nothing to commit, working tree clean

# 檢視其他人工作成果
$ cat git-remote.txt
git remote
git clone
git commit -am "fake second teamwork"

# 檢視自己即將推送的工作成果
$ cat test.txt
add test.txt
see https://snowdreams1006.github.io/git/usage/remote-repository.html
learn git branch
see https://snowdreams1006.github.io/git/usage/branch-overview.html
git commit c1
git commit c2 and c3
git checkout -b dev
fast forward not recommend
Happy coding
learn git stash
learn git rebase
learn teamwork
$ 
複製程式碼

git-branch-remote-teamwork-pull.png

(4). 你將本地倉庫更改內容推送到遠端倉庫

# 推送到遠端倉庫
$ git push origin master
Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 564 bytes | 564.00 KiB/s, done.
Total 5 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
To github.com:snowdreams1006/git-demo.git
   612e08a..8fe5aba  master -> master
$ 
複製程式碼

現在前往 github 網站確認我們已經推送成功,我們的工作成果和其他人的工作成果同時存在於遠端倉庫中,這樣就完成了一次團隊協同開發的案例.

git-branch-remote-teamwork-myself.png

git-branch-remote-teamwork-push.png

現在簡單回顧一下整個協同開發流程:

  1. 其他人先於我們提交2個版本
  2. 我們本地提交1個版本
  3. 本地版本推送前拉取遠端倉庫
  4. 本地倉庫推送到遠端倉庫

git-branch-remote-teamwork.gif

小結

  • 檢視遠端倉庫資訊: git remote -v
  • 本地倉庫推送到遠端倉庫: git push origin <branch>
  • 遠端倉庫抓取到本地倉庫: git fetch
  • 遠端倉庫拉取到本地倉庫: git pull 相當於 git fetchgit merge
  • 本地建立和遠端倉庫一致的分支: git checkout -b <branch> origin/<branch>,本地和遠端分支名稱最好一直,比如本地 master 和 遠端 origin/master,本地 dev 和遠端 origin/dev
  • 本地分支和遠端分支建立關聯: git branch --set-upstream <branch> origin/<branch> ,足夠任性的話,本地 dev 可以關聯遠端 remote-dev 等,不過建議名稱最好一致.
  • 團隊協同開發時,不僅平時要定期拉取(git pull),推送到遠端倉庫前更應先拉取(git pull)再推送(git push),如出現衝突,解決衝突後再推送.

相關文章