2017年9月18日 星期一

[git]repo、branch和tag取名建議和注意事項 - 怎麼取名比較不會有問題

image
圖片來源:https://pixabay.com/en/key-tag-security-label-symbol-2114047/

最近在和同事協同開發的時候,發生了一件事情:

由於我們還沒啟用CD(自動部署)但是更新測試機器又不一定是同一個人,為了好管控目前程式碼和目前測試機器上面的版本,我們使用了一個標籤叫做TestServer來記錄。

不過當我同事更新的時候,他使用了testserver作為標籤,結果我這邊發生了雖然local只有一個tagtestserver,但是在remote上面其實有兩個標籤:TestServertestserver

為什麼會發生這個事情呢?如果不處理,未來在看的時候非常混亂,這讓我想起來一直想要寫的一篇文章,為git repo、tag和branch取名的時候應該要注意什麼比較不會有問題,因此兩篇一起寫,算是不好好naming會帶來什麼問題的use case範例。

搜索關鍵字:naming guidance for git repo, tag and branch.

解決方式 - TL;DR

如果remote出現了兩個一樣名字的標點,但是只是大小寫不同,那麼:

  • 建議保留小寫的版本
  • 用以下指令刪掉遠端有大寫的標籤

    git push --delete {tagName}

    例如:git push --delete TestServer

取名建議 - TL;DR

基本上對於取名,不管是repo、branch還是tag的時候,建議:

全部使用小寫

由於習慣寫.net code,因此很習慣會用Pascal Casing來取名,例如UnReleased。但是,由於repo、branch和tag都屬於url的一部分,而url理論上是會區分大小寫並且 作業系統檔名是否區分大小寫處理也不同(windows不區分,Linux會區分),因此為了抓下來不會有問題,建議全部使用小寫。因此應該使用unreleased

可是如果字太長要區分怎麼辦?參考下面分割字符

關於url應該區分大小寫,可以參考W3的HTML and URLS裡面提到:Users should always consider that URLs are case-sensitive
使用-(aka 減號、dash)作為文字切割

如果名字太長想要切割的話,可以使用-來區別,例如:my-name-is

有些會習慣使用_(下底線)。

使用-有幾個好處:

  • 輸入-不用加shift - 比較好輸入
  • -在regex不屬於word_屬於,因此用來切割符號比較明顯

當然有時候字太長了,所以會混合用。

/(斜線)來分類branch和tag
如果有在用git flow應該會很習慣,主要是用/(斜線)在工具像小烏龜可以簡單找到相關內容。
image
好區分範例 - 兩個feature,A和B
tag使用v做前戳,搭配SemVar
舉例來說,v1.0.1。加v的好處是如果要列出和版號有關的tag,可以先打v然後在按下tab

當然,上面都只是建議,沒有對錯,只是習慣或者避免一些小問題。

上面有些建議裡面已經有包含說明,如果對於一開始提到的問題發生原因有興趣的話,繼續往下看.....

重現問題

首先我們先來重現一下問題(這個重現方式和我實際發生的情境有點不同,因為我的情境需要兩個帳號交叉才看得到,不過local可以用以下方式重現,問題點是一樣)。

接下來,我們要:

  1. 建立一個repo
  2. 先打一個UnReleased的標籤
  3. push到remote
  4. 修改在打一個unreleased的標籤
  5. push到remote
  6. 檢查

建立一個repo

可以參考另外一篇該怎麼開專案的資料夾結構?每個專案應該要有的資料夾結構和檔案的Powershell語法來建立一個repo:

git clone https://github.com/alantsai/mhat-common-boilerplate-repo.git
cd mhat-common-boilerplate-repo
rm .git -Recurse -Force
git init
git add -A
git commit -m "init project"

這個時候,我們修改其中一些檔案。

先打一個UnReleased的標籤

做完修改commit之後我們打一個UnReleased的tag

image
打UnReleased的tag

push到remote

imageimage
push成功之後可以在github上面看到確認有上去

在修改之後打一個unreleased的標籤

注意這邊的大小寫應該是都小寫的unreleased

image
打一個unreleased的標籤

檢查

發現到,在本機只剩下全小寫的那個unreleased的標籤,有大寫的不見了,但是在remote,大小寫兩個標籤都在

image
image
local和remote比對
如果是從remote clone下來不會看到一樣的情況,這個下面會在做說明。

了解為什麼local變成一個而remote還是兩個

要了解這個發生的原因我們需要兩個前置的訊息:

  1. git tag是怎麼儲存
  2. 作業系統對待檔名大小寫的不同

git tag是怎麼儲存

git的資訊其實是存在.git\refs\tags裡面(好吧,這個說法其實不太精準,以下會在說明),以我這邊為例,可以看到有一個叫做unreleased的檔案,這個檔案的內容其實存的是一個hash值指向tag的位置。

image
tag如何儲存 - 看到在tags資料夾檔案裡面就是一個hash

了解這個之後搭配下面的資訊我們就知道為什麼了。

作業系統對待檔名大小寫的不同

Windows和Linux在處理很多事情上面其實不太一樣,這裡面有一個不同之處在於如何對待檔名大小寫:

  • Windows不區分大小寫
  • Linux區分大小寫

什麼意思呢?舉例來說,如果我有兩個檔案,一個叫做UnReleased另外一個叫做released

  • 在Windows,兩個檔案會互蓋,換句話說,在同一個資料夾,這兩個檔案只能留1個
  • 在Linux,因為區分大小寫,因此在同一個資料夾兩個檔案可以共存,換句話說不會互蓋

搭配上面的資訊,為什麼變成一個的原因就浮出水面了,當第一個tag建立的時候,會有個檔案叫做UnReleased出現,當第二個tag unreleased出現的時候,因為Windows不區分大小寫,直接就把 UnReleased蓋掉了,因此local變成只有一個

那remote為什麼還是兩個呢?因為我們push上去的地方時github,那github host在linux(應該是啦,這個我沒找到Reference,所以說錯和我說一下,不過大部分的host應該都是liunx),而linux 區分大小寫,所以保留了下來。

例外情況

假設從sample repo clone程式碼下來,會發現兩個tag都存在阿,沒有所謂互蓋的情況啊,這是為什麼呢?

     TortoiseGitProc_2017-09-18_00-13-05
clone下來的兩個tag都有看到

這個原因是因為,其實tag還有可能存在另外一個地方,那個地方是.git\packed-refs,這個檔案主要是為了如果refs很多,速度會比較慢,所以會把一些refs放到packed-refs 裡面好讓讀取的時候速度比較快。

當clone下來的git tag資訊是存在那個裡面,所以不會有檔名問題,因此兩個tag都出現了,不過如果開始建立tag可以重現上述的問題。

結語

其實這一篇混雜了兩個主題:

  • 建議的naming方式
  • 如何解決因為naming問題導致出現兩個標籤的問題

由於兩個主題有相關因此寫在了一起,算是為了建議naming的一個use case範例。

不過就像上面說的,這邊的是建議而不是一定要這麼做 - 也是結合了網路上大家的建議,當然大家有不同的想法,因此不一定都認同,也希望提出不同意見讓整個資訊更加豐富。

在追蹤問題的時候,會發現其實需要一些git和OS之間差異的資訊才有辦法發現實際的問題 - 告訴我們 學無止境阿.....

參考資料

網路上建議的取名方式
Tag命名的建議
Is there a standard naming convention for git tags? [closed]
pack-refs - 官方介紹作用
git-pack-refs

沒有留言 :

張貼留言