2017年10月10日星期二

GitHub 及 EGit ( PART 5 / 8 ) + Git Branch

接上回【GitHub 及 EGit ( PART 4 / 8 ) + Git Object Model

有沒有聽過 Open Office 這個辦公室軟件?那是跟 Microsoft Office 對著幹的軟件。為什麼會扯上這個?為了讓大家更好理解,先舉例一個近似的功能來說明 Branch 概念。

可以代替 MS OFFICE

這是 Open Office Writer 介面,主角是復原及取消復原 ( Redo and Undo ) 功能,快捷鍵是 Ctrl + Y 及 Ctrl + Z。

寫點什麼吧

首先,寫點什麼吧,例如把以下文字貼上︰

共享經濟(Sharing economy)
https://zh.wikipedia.org/wiki/%E5%85%B1%E4%BA%AB%E7%B6%93%E6%BF%9F

在貼上同時,【復原】圖示由灰色不能按的狀態,轉為藍色的能按狀態。

雪白﹗

現在去按【復原】看看,應該跟上圖一樣,會變回一張白紙。

復原後的畫面

按【取消復原】,回到貼上文字狀態。

———————————簡易的分隔線————————————

如果把這例套進 Git Branch 的話︰


抽象圖解

大約像這樣。

master 是 branch name,其實沒有指定,只是大家公認【master】這個 default 是主軸線。如果把【Git flow】這套分支概念算進去的話,還有 develop branch、xxx feature branche 等等,聽聽就好,不用太煩惱,把 branch 學好再想。註︰現在的 master branch 標籤在 1st Commit。

按復原的話

【HEAD】可說是 current working directory,有點抽象是不是?所以現在去按【復原】的話,在 Git 來說就上圖這樣,現在的狀態應該是復原到一張白紙,HEAD 移動到 Initial commit。

———————————概念置換 ( start )————————————

假如有學過 C++ 程式,又學過 Doubly Linked List 的話,應該對 branch 這種概念很快上手。
把 C++ 的 Pointer 或 Java 的 reference 偷換成 master 標籤,Doubly Linked List 偷換成 branch,很好想象吧?

Pointer (computer programming)
https://en.wikipedia.org/wiki/Pointer_(computer_programming)

Linked list
https://en.wikipedia.org/wiki/Linked_list

———————————概念置換 ( end )————————————

前置作業︰


只有兩個 commit 不能說明什麼,現在把難度提高,做多三個 commit。

移動浮標

在網址尾,拍 Enter 算做一個 commit。

Enter 換行

再拍 Enter 又一個 commit。

插入圖片

插入圖片是一個 commit。

模仿Git 完成

現在可以用 Ctrl + Y 或 Ctrl + Z 來試試復原及取消復原。

———————————簡易的分隔線————————————

套進 Git Branch︰


試用 Git 去模擬【復原及取消復原】這功能。為了用更好更實用的方法解釋 branch,這次就用網頁形式去做差不多的事。因動手做起來很麻煩的關係,所以給大家準備好,如果想親手做一次,可參考前幾回教學。

先到以下網址︰
https://github.com/IntegrityKnight/SharingEconomy


選 SSH,複製 URI…… 然後跟影片做。


———————————簡易的分隔線————————————

Branch 操作及測試︰


轉 Perspective

首先轉回 Git Perspective。

看一下 master branch

跟據影片,現在應該停在【Local/master 726caed】這個 Commit 上,旁邊會有個黑底白勾的小圖示。

Check Out 1st Commit

現在試一下【Check Out】,這動作很簡單,在【History】View,點選想要的 Commit 右鍵,按【Check Out】就能把現在的 Working Tree 改變。例如去【Check out】1st commit ……

按下去,不會爆炸的

溫馨提示,它說可以純粹檢視,但不建議做 commit,因為會蓋過之後那些 2nd、3rd、4th commit。無論如何都想修改的話,建一個新分支或【Check Out】local/master 分支才作修改及 commit。看完可按【OK】。

可以回頭,放心

【History】真的沒有了 2nd、3rd、4th commit,後悔了嗎?但不用怕,溫馨提示說過可以【Check Out】local 分支變回來,所以先把這種事放一邊去,先去看一下 Working Tree 有什麼變化。

【Check Out】1st commit 後,Working Tree 沒有 img 這個 folder 及 Sharing economy_1.png 檔案,把 index.html 開出來,也回到沒 </p> 這 tag 及沒圖片狀態,像 Open Office Writer 使用 Undo 這個功能。

History View 的詳解

說了那麼多次【Check Out】,【Check Out】是什麼?簡單來說,就是【現在的工作點】。用 Open Office Writer 來解釋,就是 Redo 或 Undo 後看到的畫面,如果 Undo 到最初的一張白紙狀態的工作點,然後開始修改……就會掉失拍 Enter 兩下及加上圖片的改動,相對地,會增加修改後的改動。

還不太清楚【Check Out】是什麼,自己動手試試【Check Out】各個 Commit 或 Branches,看看 Working Tree 有什麼變化。不要怕,反正是 local Repo,玩壞了的話,刪了再重覆【套進 Git Branch】這一步就好。

註︰要看 index.html 改動,先把先前的 index.html 關閉,再雙點擊 index.html 開啟。要在 Web Browser 看,把 index.html 檔案拉過去網址列就可以檢視,上面影片有教。

New Branch︰


Local Repo 建立新分支

或許有試過【Check Out】origin/Another_Business 這個分支,這次就正式試建立【New Local Branch】。

Branch Name

本篇文章開始時有說過,Branch name 沒有特定,但最好還是跟原本那個,隨便亂改的話,沒有特別設定,做 PUSH 的時候會變成新分支。

Switch Branch︰


轉 Branch

現在 Local Branch 應該有兩個,一個是 master,另一個是剛剛新開的。要 Switch 很容易,在【Branches】右鍵,選【Switch to】,按想轉的 Branch 就可以。【Switch to】不是什麼特別的東西,只是改個名的【Check Out】,專門【Check Out】Branch 用的。

Git Reflog View

可以在這個 View 看到自己曾經做過什麼事,例如【Check Out】過什麼,【Switch to】什麼 Branch。

———————————簡易的分隔線————————————

設定 Remotes︰


設定 Remotes PUSH︰


用自己 GitHub 帳號吧

因為在【套進 Git Branch】這步驟中,全自動設定好的關係,沒有說明過 Remote 能做什麼,但或許試過 PUSH 吧? PUSH 失敗,沒有把寫入權限的 SSH key 放出來,當然無法寫入我的【Remote Git Repo】,對喔,是我的 Repo。

胖虎理論【你的東西就是我的東西,我的東西還是我的東西】,現在教大家如何變成【我的東西】。那怕有一天跟別人意見不合又好,原作者被和諧掉也好,都有方法另起爐灶。
  1. 你要有 GitHub 帳號
    https://javatoybox.blogspot.com/2017/07/github-egit-part-1.html

  2. 建立 Repositories (Repo, Git command)
    https://javatoybox.blogspot.com/2017/08/github-egit-part-2.html#Create_Repositories

  3. 設定 SSH 登入
    https://javatoybox.blogspot.com/2017/08/github-egit-part-2.html#Eclipse_Create_SSH_Key

  4. 設定 GitHub 的 SSH
    https://javatoybox.blogspot.com/2017/08/github-egit-part-2.html#Set_GitHub_SSH_Key
建立 Remote Push

在 Remotes 右鍵,選【Create Remote…】,給一個名字,叫【mySharingEconomy】好了。

設定 SSH 連線

跟著圖片步驟,URI 是你在 GitHub 的 Repo 複製下來的。不知道怎複製 SSH 的 URI,回去上幾回教學温習吧。

設定要 PUSH 的位置

不需要所有 Branch 都 Push 上自己的 Repo,把想要的 Branch 做設定就好,將原本 origin 的 Remote,改成自己。

試 PUSH 看看

右鍵 -->【Push Branch】 --> 【Next】

PUSH 成功!

成功的話會是這個畫面,不行的話,可能是 SSH 有問題。

——————————— PUSH 失敗的解決方法 (start) ————————————

push not permitted

push not permitted 這句很重要。

把 SSH 的 Private Key 都刪除

【Windows】 --> 【Preferences】,刪完重新開 Eclipse。

Auth fail

重新 PUSH 一次,Auth fail 這個失敗很重要,要先失敗一次才去改 config。

重新加回所有 Private Key

【Add Private Key】,把所有刪掉的 Key 重新加一次,重啟 Eclipse。

假如還是不行,只加上需要的 Key,再重啟 Eclipse。再不行就只能求 Google 救你。

——————————— PUSH 失敗的解決方法 (end) ————————————

 去 GitHub 看看

PUSH 成功,胖虎理論是個好東西。

設定 Remotes FETCH︰


另起爐灶後,不只自己在玩,還有其他人參與的話,除了 PUSH,還需要 FETCH 下載回 Local Repo,怎設定呢?

設定 FETCH

右鍵,選【Configure Fetch】。

設定 Reference

什麼是 non-fast-forward?放一邊去,現在還沒到解釋的時候,先打勾再算,說白了,其實是抄 Remote/origin 的設定。

PUSH 及 FETCH 組合起來,通常會叫作【upsteam】,人們說設定【upsteam】,就是設定PUSH 及 FETCH 。


偷偷跟你說,GitHub 本身就有個 Fork 的功能 ( GitHub 網頁登入後的右上角 ),以上的胖虎理論只是以防萬一,或許某些政治原因會連人帶 Repo 和諧掉,你懂的。

HTTP 451 Unavailable For Legal Reasons
https://zh.wikipedia.org/wiki/HTTP_451

———————————簡易的分隔線————————————

Git Repositories View 內容︰


Git Repository View

前幾回教學都是先理論後實作,本篇這順序反轉,在實作的時候不知道在作什麼吧?還有一堆沒看懂的名詞、例如【FETCH】、【PUSH】、【HEAD】、【FETCH_HEAD】之類,現在就補回這些名詞的說明。

Branch︰


如果玩過 ADV GALGAME、RPG 的宅宅,應該知道主線任務、分支任務,分支劇情、OO線、XX線等等的術語。Branch 也是一樣的東西。

為什麼要【New Branch】及【Switch Branch】?那是為了分開發展下,不互相影響,有目的地分支。以 ADV GALGAME 為例,故事有選項,每個選項都有可能影響結局,有共同線、分支線、OO結局線、XX結局等等,為了節省遊戲時間,會用上 Save And Load 大法,在重要的分歧點上 Save,以後 Load 回來進入其他路線。

想像 Save 的動作等於 Commit,Load 等於 Check Out 或 Switch Branch,不難想像吧?雖然這個例子只限套入單人模式,套不進多人共同協作模式,學習 Git 一步登天的難度有點高,有個概念後再修正就好。

【HEAD】 及 【FETCH_HEAD】︰


有沒有 PS4?有沒有 PSN 會籍?【HEAD】這個特殊 References,有點像本機遊戲 Save 的【最新進度】,而【FETCH_HEAD】就像 PSN 上的【遊戲進度】。所以人們說這是某某 Branch 的【HEAD】時,大家都有共識,這是某某 Branch【最新進度】,而【FETCH_HEAD】就是你在 PSN 的【遊戲進度】。有什麼不同?為什麼?

同步︰


最簡單的說法是進度不一樣,怎不一樣法?假設家中有兩台 PS4,都用同一個帳號玩同一個遊戲 ( 同一個帳號不能同時登入兩台 PS4,已試過 ),怎樣同步兩台 PS4 的遊戲進度?看一下 PSN Save 時間及本機 Save,誰的時間最新就知道。假設,本機 Save 不會自動上傳 ( 沒設定自動上傳的話 ),會不會有白忙一場,做了多餘工的問題發生呢?

假設 PS4_1 代表第一台,PS4_2 是第二台︰
  1. PS4_1 遊戲進度打敗了 7 個 BOSS,做了 5 個支線任務,但忘了上傳 PSN。
  2. 開 PS4_2 玩,比對過 PSN 跟 本機 ( PS4_2 ) 進度是一樣的,應該是最新進度吧,這次做了 10 個支線,沒打過 BOSS。
假如一個帳號是同一人在玩,在 PS4_2 讀 Save 的時候,應該發現 PS4_1 的進度沒上傳到 PSN,因為有記憶,自己做掉了 7 個 BOSS,肯定 PS4_1 Save 忘了上傳 PSN。

但一個帳號跟全家人分享的話會怎樣?只靠遊戲時間來做判斷,認為本機 Save 比 PSN 新,應該是最新的,再度開始遊戲,然後上傳回 PSN。

再度用 PS4_1 玩遊戲,這時候情況有兩個︰
  1. 知情的時候,那就要煩惱該不該用 PSN 完成 10 支線 Save 把本機的 Save 覆蓋。
  2. 不知情的時候,直接把 PSN 那個 Save ,蓋過去打了 7 Boss 的本機 Save,沒商討過就蓋過家人的 Save,或許會發生成家變的悲劇 …… 
如果 Save 不是【蓋過】而是【合併】的話,不是很美好嗎?完成 7 個 Boss 及 13 個支線的 Save。

合併︰


PS4 沒有合併這種功能,例如 PS4_1 跟 PS4_2 的 Save 合併,變成做掉 7 個 BOSS,13 個支線任務 ( 2 個重覆做,合併了 )。PS4 也沒有協作,例如指派妹妹用 PS4_1 做 1、2、3 支線任務,爺爺用 PS4_2 做掉 BOSS,並同時進行,沒可能的原因,是不能用同一帳號同時進行遊戲。

Git 有上述兩種功能,以協作來說「你做你的,我做我的,不拖對方後腿,不需等對方完成工作才動手,可以同時進行」,因各自各做,或許會同時做同一件事而遇上衝突 (conflict ),透過協商溝通後然手動把「成果」合併( Merge ) 。

【HEAD】 及 【FETCH_HEAD】 與 【Merge 】關係︰


或許聽過 CVS 及 SVN 這些 version control system,跟著就會說 Git 怎樣怎樣好,就算沒有網絡的情況下還能繼續工作,有沒有想過這是怎樣做到的?能做到什麼地步?

為什麼斷網也能工作?簡單來說,Git 分開三部份 —— Working Tree、Local Repo 及 Remote Repo,圖中粉紅、綠色及紫色 HighLight,同樣地 Git Repositories View 是與手繪圖對應的。

斷網下工作,要有一定準備才能實現,首先用【FETCH】,把 Remote Repo 的東西下載到 Local Repo,Remote Repo 可以消失了,即是斷網。

因為是斷網狀態,現在只餘下 Working Tree 及 Local Repo,所以兩邊的互動就是全部。Git 不能直接與 Remote Repo 互動就是這個原因,是設計上的限制,只能間接透過 Local Repo 跟 Remote Repo 互動。現在狀態多數會做的動作就是 Add / Remove Index 及 commit,不明白是什麼的,請回去温習。

網路恢復,Remote Repo 再次出現,同步 Local Repo 及 Remote Repo 是 Git 的工作 (就是你按 【PUSH】的時候),自動 Merge 不能發揮作用的話,就要動口跟別人討論及動手去做調整。【Merge】是什麼?下一回再說。

Local Repo 可以想像成一個暫存區,Working Tree 是工作區,用【FETCH_HEAD】表示 Remote Repo,【HEAD】表示 Working Tree,只要同時比對【FETCH_HEAD】及【HEAD】的差異,再推出一個合併版本,透過談判,達成共識,就能解決不同步的問題,又能保留同時作業的好處。

———————————大贈送的資訊 ( start )————————————

Version control 與 Redo and Undo 的分別︰


既然有 Redo and Undo 為什麼要有 Version control ( Git )?再進一步,既然有 Backup System,為什麼還要 Version control?

  • Redo and Undo 只要關了程式,所有記錄都會消失,再開的時候會沒了所有 Redo and Undo 記錄。
  • Redo and Undo 也是有限制,不能 Undo 一百步前的動作,能 Undo 20 步左右就很利害了 (別笑,notepad 只能 Undo 一步 )。
  • Redo and Undo 沒有 Branches 這回事,要模仿的話,只能複製一份出來做。要比喻的話,就像只有 master branche 的偽 Version control。

Backup System 也不能成為 Version control,因為 Backup 只為 Backup,沒有提供任何修改訊息,如 Commit message,總不能每次都開來看看 Backup 什麼吧?太沒效率,而且到現在都沒提到的多人協作,Backup System 根本就沒有多人協作這回事,它根本不會記錄誰作過什麼改動。

———————————大贈送的資訊 ( end )————————————

總結︰


簡潔地列出現在提到的名詞解釋︰

  • 【FETCH】—— 把 Remote Repo 的東西下載到 Local Repo

  • 【Check Out】—— 把 Local Repo 的東西放到 Working Tree

  • 【HEAD】—— 在 Working Tree 修改中的 Commit

  • 【FETCH_HEAD】—— Remote Repo 的最新 Commit

  • 【UPSTEAM】—— 連結 Remote Repo 的 FETCH 及 PUSH

  • 【PULL】——【FETCH】後自動做【Check Out】,預設用【Merge】做合併。

  • 【Add / Remote Index】—— 管理由 Working Tree 預定 Commit 到 Local Repo 的檔案

  • 【Commit】—— 把檔案交到 Local Repo

  • 【PUSH】—— 把 Local Repo 的東西推上 Remote Repo

本篇教學到這裡完成,之後就到【Merge】、【Rebase】、【Fast forward】等等。懂得【Merge】後,就差不多把單人模式的 Git 學完,然後就是多人模式的 GitHub 使用。

下一回【GitHub 及 EGit ( PART 6 / 8 ) + Git Conflict

沒有留言:

發佈留言

設有留言驗證及審查,檢閱後,才會顯示留言。
本人惰性很高,留言或許會石沉大海。