2017-05-14

使用 Git Attributes 的合併策略(Merge Strategy) 避免特定檔案被變更

公司專案在經由 CI - Continuous integration (Jenkins) 成功 build 後會將 build 結果全部 commit 回 SVN,以確保最後的 production code 是有被版控的,如果有退版需求時也可以快速完成。

最近公司正在如火如荼地將 SCM 從 SVN 改為 GIT,在之前的文章裡也有提到,過程中難免遇到一些問題需要克服,其中一個狀況是公司政策 - production code 需要版控這件事不會因為 SVN 或是 Git 而有不同,以前在 SVN 的做法是會先將 repository 的內容全部刪除,再將最新結果全部 commit,確保最新結果完整被版控不會因為 conflict 造成版控有遺漏,加上現在程式更版都是自動化 CD - Continouous Deployment 作業,如果出現 conflict 會造成部署錯誤程式,影響很大,因此需要調整 git 的合併策略,就來看看可以怎麼使用 git attribute 達到目的吧


關於 Git Attributes

透過在專案目錄下的 .gitattributes 來設定該專案專屬的特性及行為,其中包含:

  1. Binary Files (二進位檔案的處理方式)

    • 指定特定附檔名的檔案為 binary,讓 git 使用 binary 的方式來比較檔案

      *.jpg binary

    • 將特定的 binary 轉為文字來比對

      *.doc diff=word

  2. Keyword Expansion(關鍵字擴充)

    可以自訂關鍵字置換的規則,用來避免特定關鍵字被 commit or checkout

    • smudge
      • checkout 時觸發

        smudge

    • clean
      • staged(commit 前將變更納入修改清單中的步驟)時觸發

        clean

  3. Exporting Your Repository(匯出 git 儲存庫)

    將 repository 匯出壓縮檔時可以忽略特定目錄或是執行文字取代

    • export-ignore(特定資料夾,正常版控但匯出時忽略)

      testdata/ export-ignore -->匯出時略過 testdata

    • export-subst
      echo 'Last commit date: $Format:%cd$' > LAST_COMMIT.txt
      echo "LAST_COMMIT export-subst" >> .gitattributes
      git add LAST_COMMIT.txt .gitattributes
      git commit -am 'adding LAST_COMMIT.txt file for archives'
      

      會將 $Format:%cd$ 取代為最後 commit 的時間

  4. Merge Strategies(合併策略)

    可以用來針對特定檔案設定不同的合併策略

    web.config merge=ours -->出現衝突時永遠使用我的版本

合併策略(Merge Strategies)

  1. resolve

    使用 3-way merge 演算法來解決 merge 兩個 head (當前 branch 及另一個 branch)的情境,較快速且安全,但對於交叉合併效能較差

  2. recursive

    pull 及 merge 時的預設做法

    使用 3-way merge 演算法來解決 merge 兩個 head 的情境,可有效減少合併衝突

    • ours

      衝突時使用 ours 版本,binary 就都使用 ours

    • theirs

      衝突時使用 theirs 版本,binary 就都使用 theirs

    • patience

      較耗時,會忽略像是符號造成的衝突

    • diff-algorithm=[patience|minimal|histogram|myers]

      指定 diff 的演算法,避免符號造成的衝突,依不同算法耗時也會不同

    • ignore-space-change|ignore-all-space|ignore-space-at-eol

      指定對於空白字元的處理方式

    • renormalize

      忽略行末比對

    • no-renormalize

      開啟行末比對

    • no-renames

      停用 rename 的檢查

    • find-renames[=]

      開啟 rename 檢查,可指定相似性門檻值,預設是開啟的

    • rename-threshold=

      排除 rename 相似性檢查的同義詞

    • subtree[=]

      指定排除路徑來進行子目錄比對

  3. octopus

    適用於多個 head 合併,但不能有衝突,是 pull or merge 二個以上 branch 的預設策略

  4. ours

    會使用 ours 做為最終版本

  5. subtree

    將 branch 指定為子目錄的方式來合併

設定合併策略(Merge Strategies)

依同事的描述:永遠使用最新版本,那可以使用下列設定

  1. 開啟合併策略功能
    • 檢查是否開啟
      git config --global -l
      

      1check

    • 如果沒有merge.ours.driver=true則需開啟功能
      git config --global merge.ours.driver true
      

      2addconfig

  2. 加入 .gitattributes 檔案並將合併策略加入 .gitattributes 內容中
    echo "1.txt merge=ours" >.gitattributes
    
  3. 設定前後比較
    • 設定前
      • 出現衝突

        3conflict

      • 需要手動解決

        4munual

    • 設定後
      • 永遠使用本地版本

        5automerge

      • 檔案以 head branch 為主,不受其他 branch 影響

        6ours

注意事項

  1. 設定 ours 會永遠使用 head branch 來當做最終版本,無論是否有衝突,其他 branch 的變更都會被捨棄
  2. 測試結果只有 ours 可以直接使用,其他合併策略都需要配合自訂 script

參考資訊

  1. 8.2 Customizing Git - Git Attributes
  2. 【Git】attribute, 合併後保留原本的設定檔
  3. merge strategy in .gitattributes not working

沒有留言:

張貼留言