你可能不知道

git 指令

(ㄧ)

也大概用不到也不會想用到

bisect and worktree

FlyC

Outline

  • 場景連連看
  • git bisect
  • git worktree

場景連連看

請將對應的場景會使用到的git 指令做連連看

寫code寫到一半、還沒到適合commit 的時機點就要去hotfix;

hotfix 到一半、還沒到適合commit 的時機點又有超級hotfix,我不想切來切去

我的程式碼炸裂、關聯檔又太多,

不確定問題在哪隻檔案,我想知道是哪個commit 害他壞去

開發途中,我不確定我的feature 和master 有沒有衝突,

但我不想留下一直把master merge 回自已身上的commit

我不小心把遠端的分支和自己本地的分支全砍光後,

PM說剛剛的單還是上好了

候選名單:

rerere

bisect

reflog

worktree

git worktree

寫code寫到一半、還沒到適合commit 的時機點就要去hotfix;

hotfix 到一半、還沒到適合commit 的時機點又有超級hotfix,我不想切來切去

git bisect

我的程式碼炸裂、關聯檔又太多,

不確定問題在哪隻檔案,我想知道是哪個commit 害他壞去

git rerere

開發途中,我不確定我的feature 和master 有沒有衝突,

但我不想留下一直把master merge 回自已身上的commit

git reflog

我不小心把遠端的分支和自己本地的分支全砍光後,

PM說剛剛的單還是上好了

git bisect

google翻譯: bisect -> 對分

我的程式碼炸裂、關聯檔又太多,

不確定問題在哪隻檔案,我想知道是哪個commit 害他壞去

https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRK3rhqvLdYPoB2AW_xeeIvx5S8siTjrB5CcSFt2AmNdHhz_d5leQ

功能之前是好的、現在壞了

但短時間無法鎖定是哪裡的code 壞了

也不知道是什麼版本之後壞的

commit 又多到炸裂

 

這個時候就可以派上用場了 _b

 

在開始之前,

我們先來看看大家有沒有童年

有玩過 終極密碼 嗎?

撇除掉運氣成份、最有效率的做法是什麼呢?

當然就是從正中間開始猜啦

git bisect 也是一樣的喔

 

概念/步驟:

1. 跟git 說現在的版本是

2. 跟git 說 "起碼" 之前的哪個版本是

3. git 會在壞版本好版本正中間找一個commit

4. 執行專案,檢查是不是好的,如果是的話,把這正中間的      版本指定為 好版本、反之,壞版本

5. 重複 3 - 4

6. 得出一個commit, 這個commit 就是戰犯

 

接著來看程式碼吧

# 找一個空的資料夾,開始旅程吧!
mkdir git-rare-commit # 創一個主資料夾
cd git-rare-commit    # cd 進去
mkdir flyc            # 創一個子資料夾,後面會用到
cd flyc               # cd 進子資料夾
git init              # git 的初始化

# 打上最初始的commit
git commit --allow-empty -m "[add] init commit"

# 創一個測試分支
git checkout -b test-bisect/master
# 創一個代表程式碼功能是好的的檔案,裡面是correct codes
echo "correct codes" > test-bisect.txt;
git add test-bisect.txt; git commit -m "guess"
# 創造與功能無關的其他commit,代表後續的開發
for (( i = 0; i < 10; i++ )); do git commit --allow-empty -m "guess" ; done
# 故意弄壞檔案,裡面是wrong codes
echo "wrong codes" > test-bisect.txt
git add test-bisect.txt; git commit -m "guess"
# 創造與功能無關的其他commit,代表後續的開發
for (( i = 0; i < 10; i++ )); do git commit --allow-empty -m "guess" ; done

測試資料創完了

有人知道是從哪個commit 之後就一直是wrong codes 的嗎?

 

如果還真的知道的話..

http://puui.qpic.cn/qqvideo_ori/0/x07092lqwul_496_280/0

如果不知道的話沒關係

先讓我們來重溫一下剛剛的步驟吧!

 

概念/步驟:

1. 跟git 說現在的版本是

2. 跟git 說 "起碼" 之前的哪個版本是

3. git 會在壞版本好版本正中間找一個commit

4. 執行專案,檢查是不是好的,如果是的話,把這正中間的      版本指定為 好版本、反之,壞版本

5. 重複 3 - 4

6. 得出一個commit, 這個commit 就是戰犯

 

那麼,要開始囉

#bash
git bisect start    # 開始二分法除錯~!
git bisect bad      # 跟git 說現在在的commit 是錯的
git checkout master # 回到一個"起碼"是好的地方
git bisect good     # 跟git 說這裡是對的

會發現git 切換到壞的好的的commit 的正中間的commit

cat text-bisect.txt

檢查一下 text-bisect.txt

是好的呢

git bisect good # 跟git 說這個commit 是好的

繼續

git 切壞到了壞的、好的正中間的commit

cat test-bisect.txt # wrong codes, 這次壞掉囉

看看程式碼是好是壞

看來壞掉囉

git bisect bad # 跟git 說現在的程式碼是壞的

繼續

第一個壞的

壞的

好的

第一個好的

現在的位子

# 直接來看看是好是壞吧~!
cat test-bisect.txt # wrong codes, 看來是壞的呢
git bisect bad # 跟git 說是壞的

我們已經非常接近中間了!

# 繼續看看是好是壞吧~!
cat test-bisect.txt # wrong codes, 看來還是壞的呢
git bisect bad # 跟git 說是壞的

訊息變得不太一樣了..

 

這個commit 就是戰犯!

 

透過這種方式,我們就可以快速地找到到底是哪個commit 讓功能壞去的

\ 有沒有很潮很開心呀 /

臨時動議,我們來看一個東西!

git status

可以發現git 提示說現在處在一個bisecting 的狀態

所以記得要下 git bisect reset 結束這回合

git bisect reset

不然你的 git 會處在一個很奇怪的狀態喔!

一直一直下git bisect good/bad ,

其實也是一件相當惱人的事情

所以其實可以透過撰寫會根據狀態回傳 1, 0 的 .sh 檔

自動完成這件事情

 

那麼,就先介紹到這邊囉

 

限制: git vesion ^2.5

git worktree

"linked working tree" as opposed to the "main working tree"

寫code寫到一半、還沒到適合commit 的時機點就要去hotfix;

hotfix 到一半、還沒到適合commit 的時機點又有超級hotfix,我不想切來切去

https://life.tw/upload_file/44/content/00795922-59c2-ac8b-cb44-0b96ae5273e8.jpg

想在本地同一個專案上,同時開發兩個分支?

覺得時間久會忘記哪個stash 要從哪裡stash pop ?

做到一半還沒辦法存檔卻被要求先開發其他需求?

希望自己的專案像影分身一樣、可以同時存在很多獨立運作的實體?

 

 

 

 

你們的心聲

 

 

git worktree 都聽到了

同時開發兩個分支

忘記自己的stash key

果斷切換需求異動

獨立自主的運作實體

https://truth.bahamut.com.tw/s01/201608/871184c63aaefa0780b4964387ff6ea4.JPG

那麼,決鬥!

# 切到master
# 創建測試分支
git checkout master
git checkout -b test-worktree/master

# 從test-worktree/master 的commit 創建名為城之內的影分身!
# 且!該分身的名字為"真紅眼黑龍"!
git worktree add ../test-worktree-城之內 -b 真紅眼黑龍 test-worktree/master

結束這回合!

輪到我了,換我出牌!

# 從test-worktree/master 的commit 創建名為 遊戲Boy 的影分身!
# 且!該分身的名字為"黑魔導"!
git worktree add ../test-worktree-遊戲Boy -b 黑魔導 test-worktree/master

結束這回合!

那麼,到底發生了什麼事呢?

git status 沒什麼改變

ls -al 也沒有多什麼檔案...

總算在git branch 發現點端倪了!

不過這個branch 好像怪怪的,切不過去

來看看他完整的錯誤訊息..

好像在上個目錄發生了什麼事

我們 cd .. 去瞧瞧

總算發現我的影分身在哪裡了w

進去看看吧

...嗯

...大家都長得一樣嘛|||

你說的一點都沒錯

git worktree 創出來的所有資料夾

 

git 的狀態都是同步的

 

也就是說,

如果我在其中一個同步的資料夾創了一個分支

 

所有的同步資料夾都會創出那個分支

 

不用push 上去再pull 下來也可以即時同步

也就是減去了如果用git clone 會要有的 fetchpullcheckout 等等的同步指令

而且也因為是在不同的資料夾、

所以就全屬同一個git repository

檔案的異動也全都是獨立的

像是我在真紅眼黑龍創了一個 孔雀舞.png 檔案

檔案的路徑理所當然

是在城之內底下

我在黑魔導創了一個 海馬Boy.jpg 檔案

檔案的路徑理所當然

會在遊戲Boy 底下

透過這種獨立操作的特性,你可以..

誰都別想阻止我同時開發五個專案再做出黑暗大法師

想停就停

想切就切

那麼,要怎麼斷開魂結呢?

在那之前,先把城之內遊戲Boy 的異動commit 起來吧

# 回到原專案的父層
cd ..
# 1. 直接rm -rf 再prune
rm -rf test-worktree-城之內
rm -rf test-worktree-遊戲Boy
cd {原專案路徑}
git worktree prune

# 2. 用worktree 原湯化原石
cd {原專案路徑}
git worktree remove ../test-worktree-A
# 先把剛剛的孔雀舞和海馬boy commit 起來吧!
cd {原專案路徑}
cd ../test-worktree-城之內
git add 孔雀舞.png
git commit -m "[add] add 孔雀舞.png"
cd ../test-worktree-遊戲Boy
git add 海馬Boy.jpg
git commit -m "[add] add 海馬Boy.jpg"

要斷開連結,有兩個方法:

斷開連結後,讓我們回到原專案路徑看看現在的情況

# 回到原專案
cd {原專案路徑}
# 來看看城之內和遊戲Boy 的分支怎麼了
git branch

嘿,他們的分支都還在耶w

不僅如此

# 來看看log
git log --graph --oneline --all

連commit 的log 都還在喔

就把他們合進主線吧

# 合進測試用的主線
git merge 真紅眼黑龍 黑魔導 --no-ff -m "Merge 真紅眼黑龍 和 黑魔導"

來看看 log 

我們就達成同時開發兩個功能的成就囉(1/1)

http://i.imgur.com/D4PEA70.jpg

http://img3.ph.126.net/e23PNmgYXy9Zkp1Nt7hVZQ==/2592384535522656623.jpg

透過 worktree 即可創建一個極為乾淨的git 同步專案

可以做到同時在多個branches 上操作的神奇事情

也可以確保分出去後包出來的檔案不會被其他執行緒異動

 

缺點是

 

由於是同步出來的,所以.gitignore 的部分會被忽略

像是node_modules 等等的東西都會消失

在使用上必須做些取捨

也因為在停留branch 上不可重複的關係、

branch 和資料夾的命名也會是學問

而且

就算不自己去刪除同步資料夾,

三個月後會自己被git 刪除RRRRRRR

因此worktree 僅能當作暫時性的、快速做分身的一種手段

就像是鳴人的影分身還是會消失一樣,就像雖然看得到卻是無形的東西一樣

因此要如何應用在什麼場景上、

會是個相當有趣的課題

QA

THX

參考資料

你可能不知道的git 指令 (ㄧ)

By flyc

你可能不知道的git 指令 (ㄧ)

  • 222