在 Day 19 的時候,我們提到可以使用 git push
及 git fetch
兩個指令把本地的 GIT 儲存庫狀態物件與遠端的共用儲存庫做 GIT 的物件狀態同步及更新,看起來也似乎很美好,但實務上的使用都這麼美好嗎?
讓我們回到 Day 18 的樂高製作手冊與共用儲存空間的故事。現在我們參與共用專案的夥伴有兩個人,分別是 A 與 B,今天 A 開始了這個共用專案的計畫,這是一個要打造樂高直升機的計畫,首先 A 先把直升機專案的部分製作手冊分享到共用儲存區上,B 也複製了一份手冊,並開始基於 A 提供的手冊版本,繼續根據自己的專長新增手冊的內容,而 A 也持續的在編修這本直升機專案的手冊。
這時候 B 先完成了新的功能需求,並且也更新了共用儲存區的樂高手冊;而 A 因為埋首於專案上,遲遲未到共用儲存區了解有沒有新的進度,這時候直接把基於上一次分享到共用儲存區的功能,又新增了新的功能,並且再次到共用儲存區分享,這時候看到 B 已經搶先一步有了更新了,那 A 該怎麼辦?
A 這時候首先要了解 B 提供的新功能需求做了什麼,而後評估自己目前完成的新功能,能不能接著從 B 目前提供,如果可以,那 A 就可以把 B 提供的新手冊內容,與自己的手冊直接合併在一起,也就完成這次的新手冊功能更新,等 B 再次來到共用儲存區查看時,就可以發現 A 也提供了同樣的功能,並且把 A 的新手冊取回。
有沒有覺得這劇情跟之前 Day 12、Day 13、Day 14 談到的 git merge
、git rebase
有點像?沒錯的,其實在 GIT 版本控制的環境下,與共用儲存中心的訊息同步、 GIT 物件更新等,最重要的指令不外乎 git push
及 git fetch
,物件同步完畢之後,其實就還是 git merge
、git rebase
的合併概念。
我們回到 GIT 的情境下,繼續看上面樂高手冊的例子,在 GIT 環境下會是怎麼一回事。
HASH C
,遠端有新的 HASH D
,這時候執行 git fetch
:這時候本地端跟遠端的共用儲存區更新狀態,發現遠端多了一個 HASH D
,且就接續在 HASH B
之後,這時候一樣還是會把 HASH D
複製到本地,並且更新 origin/master
這個分支貼紙,移動到 HASH D
的位置。
如果單看本地端的儲存庫分支標籤變化,就會是如下圖的動畫呈現:
在把物件更新到本地之後,其實就是 Day 12、Day 13 提到的 git merge
的內容範圍了,所以這時候,我們只需要執行以下的 GIT 指令 git merge origin/master
,就可以把遠端的 GIT 物件跟本地的物件合併在一起。
git pull
一定都要執行 git fetch
而後才能 git merge
嗎?如果我每次都信任遠端給我的新物件,那能不能直接有個指令可以一次完成這兩個指令?有,他叫做 git pull
,執行起來大概如下動畫:
從動畫中可以發現, git pull
也就是 git fetch
+ git merge origin/master
的連續技。
一般情況如果本地沒有新的 commit,其實 git pull
,會啟用 Day 13 提到的 ff
、fast-forward
,在畫面上的執行效果大概如下:
在同樣的情境下, git pull
在本地的儲存庫與分支的變化,看到的大概這樣子:
共用儲存庫通常會罵你,給你一個警告,並且不讓你把目前的這個 HASH C 推出,提醒你必須先解決遠端已經有新物件存在這件事情。動畫大致上如下:
而如果這邊以 apple
這個分支模擬,在 CLI 的畫面上,通常可以看到這個警告訊息:
可以執行 git push
,但必須要再加上一個參數也就是 git push -f
這個 -f
的概念其實也就是 --force
。
正常來說,會拜託不要這樣,如果你很肯定的這樣強制的更新共用儲存庫的 GIT 物件狀態,並不會造成其他一起使用這個儲存庫的人困擾,或者是在團隊可以承受,已知應該怎麼做、怎麼處理的狀況下才這樣做。而,目前大部分的 GIT Server 其實都有建立直接 push 某些分支,礙於權限設定,是會被阻擋的。
GIT 的本地與遠端操作,還有與遠端的物件合併,透過 Day 19 與今天的說明之後,希望可以讓有一起使用 GIT 共同開發的邦友們,不在害怕與團隊一同使用 GIT。其實 GIT 的本地和遠端同步,最重要的就 git push
和 git fetch
,當了解這兩個指令之後,其他都只是分支的合併操作而已。