Alan Tsai 的學習筆記


學而不思則罔,思而不學則殆,不思不學則“網貸” 為現任微軟最有價值專家 (MVP)、微軟認證講師 (MCT) 、Blogger、Youtuber:記錄軟體開發的點點滴滴 著重於微軟技術、C#、ASP .NET、Azure、DevOps、Docker、AI、Chatbot、Data Science

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

2017-09-18 Monday
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

如果文章對您有幫助,就請我喝杯飲料吧
街口支付QR Code
街口支付QR Code
台灣 Pay QR Code
台灣 Pay QR Code
Line Pay 一卡通 QR Code
Line Pay 一卡通 QR Code
街口支付QR Code
支付寶QR Code
街口支付QR Code
微信支付QR Code
2017-09-18 Monday
comments powered by Disqus