2015-11-25

Git repo 之間的 sync 操作步驟

這篇文章是 GitHub 作為 repo host,不過下列操作都沒有 depend on GitHub。或著說,就是不希望用 GitHub 的功能,所以才要有這些步驟,不然 pull request 應該可以解決大部分的狀況。

前情提要

假設 WTF 這個人有一個 foo 的 repo(以下寫作 WTF/foo),用 GitHub 的 fork 功能產生一個 MyName/foo 的 repo。接著在自己的電腦上對 MyName/foo 作 git clone 也會產生一個 repo,姑且稱之 LOCAL/foo

為了簡化起見,所有 branch 一律都是 master。另外,畫蛇添足補一句:master 只是慣用的 branch 名稱,一個 git repo 沒有 master branch 也不會怎麼樣。

同樣為了簡化起見,以下也不討論 conflict 的狀況。

remote 設定

LOCAL/foo 下列出所有 remote:

git remote -v

目前的前情提要,會得到

origin https://github.com/MyName/foo.git (fetch)
origin https://github.com/MyName/foo.git (push)

這個名為 origin 的 remote 是 git clone 時自動加上去的,後頭的 url 會隨著 git clone 時下的參數而有所改變(例如變成 git@github.com:MyName/foo.git)。

所以,要先把 WTF/foo 加到 remote,讓後續操作方便一些:

git remote add wtfRemote https://github.com/WTF/foo.git

之後再作 git remote -v 就會多 wtfRemote 這個 remote 了。

開始 sync

假設 WTF/foo 之後又加了 8 個 commit,在 MyName/foo 的 GitHub 網頁上會提示你

This branch is 8 commit behind WTF:foo. 

LOCAL/foo 要自己下 git status,而且得有設定過 upstream(在 git push 的時候加過一次 -u、而且該次 git push 成功)。

這時候就先把 LOCAL/fooWTF/foo 作 sync,我會這樣下指令:

git pull --rebase wtfRemote master

加上 --rebase 是不希望出現 dummy 的 merge commit,個人認為那還蠻討厭的。當然也有用 git config 來讓所有 git pull 行為都一併作 rebase 的方法,不過這裡按下不表。

如果順利做完 git pull,接下來就是讓 LOCAL/fooMyName/foo 作 sync,指令是:

git push origin master

如此一來,WTF/foo 增加的那 8 個 commit 內容就會出現在 MyName/fooLOCAL/foo

番外篇(?)

如果前情提要不是這樣子,而是在自己的電腦上對 WTF/foo 作 git clone,然後才 push 上 MyName/foo,要怎麼辦?

答案是:概念是一樣的,只不過變數名字對應的意義不一樣。

這個時候 LOCAL/fooorigin 會指向 WTF/foo。所以要新增的 remote 是 MyName/foo,其餘步驟都相同。

就跟 master 這個 branch 是約定成俗的道理是一樣的,origin 這個 remote 也是約定成俗地代表 clone 的來源,也就只有這樣。對於 git 的中心思想來講,repo / branch 都沒有主從關係,彼此之間的地位都是一樣的。就像 MyName/fooWTF/foo fork 出來,但是要把 MyName/foo 的東西 push 回去 WTF/foo 也完全沒什麼不對(基本上 pull request 就是在幹這件事情)。也就不要執著於 masterorigin 字面上的意思,只要搞清楚現在到底是要用哪一個東西、對哪一個目標作什麼事情就好。