聊聊Unity項目管理的那些事:Git-flow和Unity

感謝原作者https://www.cnblogs.com/murongxiaopifu/p/6086849.html

0x00 前言


目前所在的團隊實行敏捷開發已經有了一段時間了。敏捷開發中重要的一個話題便是如何對項目進行恰當的版本管理。項目從最初使用svn到之後的Git One Track策略再到現在的GitFlow策略,中間有經驗也有教訓,所以記錄在本文,既是和各位朋友交流也供自己日後查閱。

0x01 基礎:Unity項目如何做版本管理?

爲什麼更喜歡git?

初來項目組到時候,項目還在使用SVN作爲版本管理的工具。作爲一個不喜歡SVN的人,自然而然想到了換用git來做版本管理。這裏當然並不是說svn不如git好,只是它們的思路的確是不一樣的。
與SVN相比,git是一個分佈式的版本管理工具。這一點可能是我喜歡git勝過svn的一個決定性原因。
當我們使用git從遠端版本庫/服務器上chect out代碼後,git會在自己的機器上克隆一個自己的本地版本庫。這樣我們在本地就實現了版本的管理,而不必像svn那樣必須和服務器連接。舉一個例子,當我們在本地開發自己的功能時一旦不小心有了錯誤的操作,我們只需要在本地進行版本回退即可。如果使用svn的話,這種問題的修改似乎就變得不那麼方便了。
喜歡git的另一個原因就是使用git的分支了。我們可以在本地的同一個工作目錄下快速的切換不同的分支,每個分支之間都是隔離的。當我們不想影響主分支的時候,可以十分輕鬆的利用git創建一個新的分支進行開發。
總之,使用git替換svn作爲團隊的新的版本管理工具之後,團隊的開發效率提高了很多。

git和Unity

既然項目組決定採用git作爲新的版本管理工具,那麼首先的一點就是我們要先確認哪些文件是需要納入版本管理的。同時,在確認需要管理的文件時,順便重新規整一下整個項目的目錄結構,不僅僅是爲了更加便於git進行版本管理,同時也可以更好的維護項目。

上圖便是一個典型的Unity項目的默認目錄。我們可以看到默認的Unity項目的目錄下就已經有很多文件和文件夾了。
但是,作爲版本管理,我們通常只需要關注兩個文件夾即可。即:Assets文件夾和ProjectSettings文件夾。
其中,Assets文件夾主要用來存放項目的資源,例如腳本文件、貼圖、材質、聲音資源等等。
而ProjectSettings文件夾則用來存放一些項目的設置,例如輸入設置、物理系統的設置、Player設置、Layer、Tags等等。我們可以在Unity的編輯器中的Edit->Project Settings菜單來調整這些設置信息。
默認目錄下的其餘文件或文件夾都可以由這兩個文件夾的內容生成出來。
例如,如果Assets文件夾中包括C#腳本文件,則Unity會在目錄生成C#工程文件Assembly-CSharp.csproj。

除此之外, Unity的一些特殊的文件夾也會生成一些工程文件。例如Editor文件夾內如果有C#腳本,則會生成一個Assembly-CSharp-Editor工程文件。
除了這些工程文件之外,Unity還會生成一些文件夾。例如Library、Temp、obj這三個文件夾。它們同樣是Unity自動生成的。

Library文件夾的內容主要是在項目中導入資源時產生的一些本地的緩存。
Temp和obj這兩個文件夾則是在項目構建時產生的臨時文件。
因此,我們可以通過git的.gitignore文件來將不需要被git管理的文件/文件夾添加到忽略列表。下面是github提供的一份適用於Unity項目的.gitignore文件列表。

/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/Assets/AssetStoreTools*

# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd


# Unity3D generated meta files
*.pidb.meta

# Unity3D Generated File On Crash Reports
sysinfo.txt

# Builds
*.apk
*.unitypackage

除此之外,我們還需要將Unity爲導入資源生成的.meta文件也納入版本管理,和相應的資源一同維護。meta文件的重要性在於Unity會利用它來處理對應資源之間的引用關係。

爲了處理資源之間的引用關係,Unity在序列化時會通過兩個數據來保證正確的引用關係。即文件GUID和以及本地ID,其中文件GUID便保存在meta文件中。

fileFormatVersion: 2
guid: 437eb1afce72bb44ca24c6ac3fe90c1d
timeCreated: 1453720237
licenseType: Store
NativeFormatImporter:
  userData: 
  assetBundleName: 
  assetBundleVariant: 

只要使用文本工具打開meta文件即可以看到其內容。

另外還需要注意到的事情便是git版本管理時的文件衝突問題。通常當我們合併兩個相同的地方都有修改的分支時,都會產生衝突。

一旦git不知道如何自動合併,就需要我們來手動解決衝突了。如果文件是文本文件,git便會在有衝突的地方做上標記(如 <<<<<<< HEAD ==== >>>>>>> HASH_ID等),參考這些標記我們可以很方便的解決衝突問題。

但是,如果文件是二進制的文件,一旦發生衝突則很難查看git插入的衝突標識,解決起來是比較棘手的。因此Unity項目的資產序列化最好生成文本文件,而不是二進制文件。我們可以在設置中選擇序列化的策略。

這樣場景文件和prefab等文件就會被序列化爲yaml文本文件:

%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!29 &1
SceneSettings:
  m_ObjectHideFlags: 0
  m_PVSData: 
  m_PVSObjectsArray: []
  m_PVSPortalsArray: []
  m_OcclusionBakeSettings:
    smallestOccluder: 5
    smallestHole: 0.25
    backfaceThreshold: 100
--- !u!104 &2
RenderSettings:

智能合併場景和prefab文件

將場景文件和Prefab文件序列化爲yaml文本文件之後,仍然有可能會在合併時遇到產生衝突的情況。不過好在Unity在5.X版本之後已經提供了一個便於處理合並的工具,並且已經集成在Editor中。你可以在你的Unity安裝目錄下的Unity/Editor/Data/Tools文件夾中找到這個名爲YAML Merge的工具。

它的使用方法也十分簡單,以使用git作爲版本管理工具爲例。我們需要在.gitconfig文件中加上下面這幾行配置:

[merge]
tool = unityyamlmerge

[mergetool "unityyamlmerge"]
trustExitCode = false
cmd = '<path to UnityYAMLMerge>' merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"

這樣當兩個人同時修改同一個場景,並且進行合併時,之前的git會報告這個衝突,讓我們來手動解決該衝突。但是配置了YAML Merge工具之後的git會調用YAML Merge工具,並自動解決衝突。
更多相關的內容,各位可以去參考Unity官方的手冊(https://docs.unity3d.com/Manual/SmartMerge.html)。

0x02 問題:大文件如何處理?

遊戲開發,特別是3D遊戲開發時會使用到很多美術資源、音頻視頻資源等等。如何把這些大型的二進制文件集成到git工作流中就成爲了一個需要思考的問題。

由於git在處理二進制文件時默認會壓縮並存儲二進制文件的所有完整版本,如果二進制文件很多,這種做法顯然不是最優,換句話說git在存儲二進制文件時的效率不高。

針對這個問題,github開源了一個git的拓展,即Git Large File Storage(簡稱LFS),git大文件存儲。規避了git傳統的處理方法,Git LFS處理大型二進制文件的方式是用“文本指針”替換它們。

這些文本指針實際上是包含二進制文件信息的文本文件。文本指針存儲在Git中,而大文件本身通過HTTPS託管在Git LFS服務器上。Git LFS 使用引用小文本文件指針指向存儲在服務器的大型文件。

從git lfs的官網下載並安裝好之後,我們就可以在項目中使用lfs來管理我們的大型二進制文件了。相關操作也很簡單:

git lfs track "*.<file_extensions>"

例如我們要管理png文件,只需要輸入git lfs track "*.png"就好了。

當然,我們也可以直接修改項目目錄下的.gitattributes文件。

*.png filter=lfs diff=lfs merge=lfs -text

需要說明的是,很多公司使用的gitlab也已經宣佈支持Git LFS了。所以項目的管理沒有必要美術用svn、程序用git了。

0x03 策略:Git One Track 和 GitFlow

使用版本工具,除了要能正確合理的使用它之外,作爲項目的管理者,還需要清楚一些和版本管理相關的策略。

因此,在本文的最後我們再聊聊使用git作爲版本管理工具的管理策略吧。

簡單的說,git的管理策略目前有兩大流派。平時和同事聊天或和別的公司的朋友交流時也能夠感覺的到,即Git One Track和Git-flow。

One Track

One Track簡單的說,就是整個團隊在開發項目時都在同一個分支上進行。這也就意味着開發階段的所有工作都集中在同一個分支,例如新功能開發、bug的修復。當然,One Track策略並不意味着只有一個分支,而是隻有一個開發分支。當達到團隊設定的里程碑時,可以開一個新的分支用來維護這個基本穩定的版本,這個維護分支只進行維護的工作,而不進行開發的工作。同時,開發分支繼續進行最新的開發工作。

使用這種策略的最大特點就是大家都在同一個分支上工作,因此每次提交代碼都有可能會有衝突。爲了減少衝突,團隊也常常會提高提交的頻率,同時每次提交的顆粒度都比較小。同時,管理成本比較低,整個團隊的學習成本也比較低。

在我之前的項目中,參與過一個剛從svn切換到git的團隊,我們使用過一段時間One Track的工作方式,可以看到這種策略對整個團隊接觸和適應git還是很有好處的。

但是我相信更多的人還是更推崇另外一種策略,即Git-Flow策略。

GitFlow

首先我相信很多人一定在哪裏會見過下面這張圖:

這張圖已經能很好的說明了gitflow了。即任何變更都是一個分支。

可以看到,這張圖中的分支雖然很多,但是大體上可以分爲兩類。即主要分支和輔助分支。

主要分支

主要分支即git默認的mater分支以及一個主開發分支develop。

master分支是git默認的主分支,平時團隊不在該分支上進行開發。而主開發分支develop則管理着開發人員提交的代碼,當代碼穩定時或固定一個週期,將develop分支上的代碼合併到主分支。

輔助分支

輔助分支是團隊每個開發人員都能接觸到的,常見的輔助分支包括:

  • 功能分支
  • 發佈分支
  • 修復分支

這三類分支都有其對應的使用場景。

開發新的功能時,需要從主開發分支上創建一個新的功能分支,待該分支上的功能開發完畢之後,再合併會主功能分支。

發佈分支則是在版本發佈時創建的分支, 按照產品里程碑的需求包括應該完成的功能。

修復分支則是當出現bug時,爲了不影響開發分支,因此創建出一個新的分支來修改bug,之後再合併回開發分支。

因此我們可以看到,GitFlow的策略無論是開發功能還是修復bug都是以分支的方式來進行。這樣做的好處當然是管理上十分乾淨。但是由於功能開發時間相對要長、代碼提交的粒度相對較大,因此在分支合併的時候有可能會出現衝突的問題,另外一個問題是對整個團隊的要求要比One Track策略大。

不過,並沒有最完美的方案,有的也僅僅是更適合團隊的方案。例如很多團隊包括我現在都更喜歡將兩種方式混合使用,例如針對One Track都在同一個分支上開發,可能不夠乾淨,我們就可以適當的開一個新的分支也用來開發。針對GitFlow提交合並時代碼粒度大、衝突多,我們就每天都同步一次代碼而不必等整個功能都完成再合併到主開發分支。

最後也希望大家也一起來聊聊項目管理,特別時遊戲項目管理的一些經驗吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章