Category Archives: Git

談 Git 的開發流程

很高興受邀參加『FED Party 10』GIT的develop與master 論壇成為與談人。其中「協同開發時,master 與 dev branch 如何規劃?」這個問題是我主要講述的部份,分享了團隊用 Git 的開發流程經驗。

2010 年的 GitFlow 是一個很好的開始,它提供了一個很清楚的開發流程,幾乎可說是目前用 Git 的「標準開發流程」。不過流程的目的是為了幫助軟體開發和釋出,而不同團隊有著不同的需求,也就不可能有 “One size fits all ” 的解法。

撇開 Gitflow 比較囉唆(或者你要說它比較嚴謹?)的流程,我認為最大的問題(或天性)是它比較適合搭配 Iteration-based 流程(一批功能完成才進行釋出、週期性佈署),而不是 Kanban 流程 (一個功能完成就進行釋出、每天多次佈署)。怎麼說呢?

假設團隊這次 iteration 同時在開發 A,B,C 三個 features。在 GitFlow 之中,我們通常不會一個 feature 寫好就開 release branch,而是會等到 A,B,C 都完成了,在一起開 release branch 跑 CI 上 staging server 一起測試。這時候問題就來了,如果 feature A 測試有問題,即使 B,C 沒問題,整個 release branch 也會卡住無法釋出。這一卡可能又拖了好幾天…

理想的 Kanban 流程會希望一個 feature 完成就能推上 production 釋出。這時候 release branch 的設計就顯得礙手礙腳了。那要怎麼達到一個 feature 可以單獨釋出呢? 首先你會需要多重 CI 和 staging servers 的環境。每新開一個 feature branch 就會有各自對應的 CI 和 staging server 可以進行測試,這樣只要該 feature branch 測試完成,就代表可以合併回主幹進行釋出動作。話說回來,這其實就是 GitHub Flow 流程。

實務上,你也可以預先開好數台 staging 機器,然後讓開發者可以佈署 feature branch 上去進行QA測試。這樣就不需要辦到隨時動態開 staging 機器的技術能力。

如果 staging 機器真的有限制只能開一台,另一個變形作法是有一個專門的 staging branch,需要上 staging 機器進行測試的 feature branch 就合併進 staging branch 進行佈署。但是注意到這個 staging branch 並不會合併回主幹,它是永遠平行的。也就是說 staging branch 上可能包含 A,B,C feature branchs,當 feature B 在 staging 上測試完成,就合併 feature B branch 回主幹,而不是 staging branch。這算是一個 workaround 的作法,我們公司就有團隊就採用這個作法,也非常實用。

總之,無論採用何種流程,我的重點在於必須一併考慮如何搭配 CI、Code Review、手動 QA 測試等等整套軟體釋出流程,才是通盤的考量。

參考資料

講個秘訣:加快 git pull 和 git push 速度

SSH 有個功能是可以沿用已經存在的 host 連線,如果再連一次就會比較快。首先編輯 ~/.ssh/config 加上:


ControlMaster auto
ControlPath /tmp/ssh_mux_%h_%p_%r

接著讓我們一直掛著 GitHub 的 SSH 連線……


ssh -N git@github.com

讓我們實驗看看效果如何:

使用前:


> time git pull

real	0m3.117s
user	0m0.055s
sys	0m0.045s

使用後:


> time git pull

real	0m0.765s
user	0m0.037s
sys	0m0.042s

嗯,效果非常好。

出處:GitHub hack: speed up git push and git pull

如何在本地端取出和送出 Github 的 Pull Requests

最近意識到 Github 上的 pull requests 其實也是 branches 參照,所以你也可以根據 pull request 編號在本地端直接取出。對於常用 pull request 功能來作 code review 的團隊來說,是蠻方便的小技巧。

首先編輯專案下的 .git/config,加上 fetch = +refs/pull/*/head:refs/remotes/origin/pr/* 這一行,例如:

[remote "origin"]
    fetch = +refs/heads/*:refs/remotes/origin/*
    url = git@github.com:ihower/sandbox.git
    fetch = +refs/pull/*/head:refs/remotes/origin/pr/*

接著打 git fetch origin 就會抓下來這些 remote branches:

From github.com:eduvo/keybridge
 * [new ref]         refs/pull/1/head -> origin/pr/1
 * [new ref]         refs/pull/2/head -> origin/pr/2
 * [new ref]         refs/pull/3/head -> origin/pr/3

接著用 checkout 取出,例如 git checkout pr/3 即可。

喜歡的話,也可以設成 git 全域設定,直接套用所有專案:

git config --global --add remote.origin.fetch "+refs/pull/*/head:refs/remotes/origin/pr/*"

參考資料: Checkout Pull Requests Locally

本地端送 Pull request

舉一反三,那要怎麼在本地端送 Github 的 Pull Request? 參考 HSATAC 的這篇:用 Commandline 發 Github Pull Request

首先安裝 github 的 hub 工具:

brew install hub # 或
gem install hub

編輯 ~/.bash_profile

# https://gist.github.com/hSATAC/5591270#file-gistfile1-sh
# Usage: pr (pull request current branch into develop)
# Usage 2: pr stable (pull request current branch into stable)
# Notice: replace "team" with your github team account.
 
function pr() {
    base=$1;
    if [ "$1" == "" ]; then
        base="develop"
    fi
    hub pull-request -b team:"$base" -h team:`git rev-parse --abbrev-ref HEAD`;
}

Yet another introduction to Git – from the bottom up 投影片

這是今年在 COSCUP 演講的投影片,Git 應該是近幾年最流行的版本控制系統,也有非常多的入門和教學資料。這次我則是從底層的原理和操作來介紹,探討 如何不用 git add 和 git commit 指令進行 commit 動作?

了解 Git 的資料結構之後,就會發現其實內部原理並沒有很複雜。對照發明人 Linus 的話,就會讚嘆版本控制系統就該這樣設計啊!

I will, in fact, claim that the difference between a bad programmer and a good one is whether he considers
his code or his data structures more important. Bad programmers worry about the code. Good programmers worry about data structures and their relationships. by Linus Torvalds

p.s. 會後有會眾問我關於 workflow 和 rebase 的問題,可以參考我之前的課程投影片

Git rebase 和 merge 合併操作示範錄影

昨天的 Git 教學投影片 還蠻多人按贊分享的,謝謝大家。不過其中少了重要的 live demo 覺得有點可惜,所以來把其中最有趣的一段錄下來好了。第一次錄影加聲音發現還蠻緊張的,獻醜哩。

這是先用 rebase 整理 commit history (包括修改訊息、修改內容、刪除、拆開、新增和調換commit順序),然後再進行 merge 的示範。但誠如我投影片 p117~p118 所說,這是一種追求完美潔癖龜毛的作法,但是看到最後的 commits 線圖這麼漂亮,就覺得值得啦,而且中間的過程很有趣不是嗎? XD (除非一直發生 rebase conflict 情況啦,那就不好玩了,請量力而為 :p)

情境是我們想把 feature/forum 這個 branch 合併進主幹 master,這是合併前:

以下是直接在 master branch 做 merge feature/forum 的合併結果。你會發現 feature/forum 與 feature/chatroom 這兩個分支出現交疊的情況,當合併的分支一多,線圖就容易變得雜亂:

以下是改成用 rebase 整理之後再 merge 的方式,做出漂亮的合併線圖:

ps. 如果有人想練習的話,可以 fork sandbox 這個專案(純粹練習git,是個亂寫的rails專案)。

Git 教育訓練課程投影片

Update(7/21): 我把 p117 rebase 和 merge 操作的示範 錄成影片啦 :)

這是最近準備的 Git 教育訓練課程,加上 live demo (一般操作、merge、reset、rebase等等示範) 時間大概是三個小時。其內容主要基於去年的演講,新增了Git內部原理(p36~51)、分支模式(p143)和更多 Tips(p168)內容等等,總頁數從117成長到198… XD

再次感謝 schacon 公開的 OmniGraffle Diagrams 圖檔讓我可以改來用 :>