1. 程式人生 > >正確的 Git 提交記錄和分支模型

正確的 Git 提交記錄和分支模型

兩年前編寫的文章 Git Style,是參考業界實踐對 Git 提交記錄格式和分支模型所做的總結。本文在 Git Style 基礎上,再次描述提交記錄的格式和分支模型,並介紹兩個工具 commitizen 和 gitflow,分別處理維護提交記錄格式和分支切換的工作

Commit Message

在 Git Style 中已經介紹了提交記錄(Commit Message)的格式,但是沒有說明為什麼要遵循這樣的約定。事實上,這個格式參考了 AngularJS’s commit message convention,而 AngularJS 制定這樣的約定是出於幾個目的

  • 自動生成 CHANGELOG.md

  • 識別不重要的提交

  • 為瀏覽提交歷史時提供更好的資訊

後面簡稱 AngularJS’s commit message convention 為 conventional message。

格式

Conventional message 格式是這樣的

<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

subject

 是對變更的簡要描述。

body 是更為詳細的描述。

type 則定義了此次變更的型別,只能使用下面幾種型別

  • feat:增加新功能

  • fix:問題修復

  • docs:文件變更

  • style:程式碼風格變更(不影響功能)

  • refactor:既不是新功能也不是問題修復的程式碼變更

  • perf:改善效能

  • test:增加測試

  • chore:開發工具(構建,腳手架工具等)

footer 可以包含 Breaking Changes 和 Closes 資訊。

應用

node-trail-agent 專案遵循 conventional message,這裡以這個專案舉例,演示其應用場景。

CHANGELOG

通過 git log 可以生成 CHANGELOG.md 中版本間新增功能,

$ git log v0.4.0..v1.1.2 --grep feat --pretty=format:%s

feat: add "type" tag to distinguish client and server span
feat: instrument via Module._load hook

也可以同時獲取修復的問題,

$ git log v0.4.0..v1.1.2 --grep 'feat\|fix' --pretty=format:%s

fix: wrapper function not returned
feat: add "type" tag to distinguish client and server span
feat: instrument via Module._load hook

定位錯誤

使用 git bisect 可以定位引入問題的提交,通過 type 可以快速辨別不會引入 bug 的提交,

(master) $ git bisect start
(master) $ git bisect bad
(master) $ gco v0.1.0
(7f04616) $ git bisect good

Bisecting: 15 revisions left to test after this (roughly 4 steps)
[433f58f26a53b519ab7fc52927895e67eb068c64] docs: how to use agent

(433f58f) $ git bisect good

Bisecting: 7 revisions left to test after this (roughly 3 steps)
[02894fb497f41eecc7b21462d3b020687b3aaee2] docs(CHANGELOG): 1.1.0

(02894fb) $ git bisect good

Bisecting: 3 revisions left to test after this (roughly 2 steps)
[9d15ca2166075aa180cd38a3b4d3be22aa336575] chore(release): 1.1.1

(9d15ca2) $ git bisect good

Bisecting: 1 revision left to test after this (roughly 1 step)
[f024d7c0382c4ff8b0543cbd66c6fe05b199bfbc] fix: wrapper function not returned

(f024d7c) $ npm test
...

因為 docs 或 chore 不會引入 bug,所以可以直接執行 git bisect good

使用 git bisect skip 可以直接過濾掉這些提交,

$ git bisect skip $(git rev-list --grep 'style\|docs\|chore' v0.1.0..HEAD)

Commitizen

命令列工具 commitizen 幫助開發者生成符合 conventional message 的提交記錄。

成功安裝並初始化 commitizen 後,通過呼叫 git cz 來提交程式碼,

$ git cz

Line 1 will be cropped at 100 characters. All other lines will be wrapped after 100 characters.

? Select the type of change that you're committing: (Use arrow keys)
❯ feat:     A new feature
  fix:      A bug fix
  docs:     Documentation only changes
  style:    Changes that do not affect the meaning of the code
            (white-space, formatting, missing semi-colons, etc)
  refactor: A code change that neither fixes a bug or adds a feature
  perf:     A code change that improves performance

提交後會按照 convertional message 格式化提交記錄,

commit f024d7c0382c4ff8b0543cbd66c6fe05b199bfbc
Author: zhongchiyu <[email protected]>
Date:   Mon May 30 14:49:17 2016 +0800

    fix: wrapper function not returned

除此之外,commitizen 還依據 conventional message,建立起一個生態

  • conventional-changelog-cli:通過提交記錄生成 CHANGELOG.md

  • conventional-github-releaser:通過提交記錄生成 github release 中的變更描述

  • conventional-recommended-bump:根據提交記錄判斷需要升級 Semantic Versioning 哪一位版本號

  • validate-commit-msg:檢查提交記錄是否符合約定

使用這些工具可以簡化 npm 包的釋出流程,

#! /bin/bash

# https://gist.github.com/stevemao/280ef22ee861323993a0
# npm install -g commitizen cz-conventional-changelog trash-cli conventional-recommended-bump conventional-changelog-cli conventional-commits-detector json
trash node_modules &>/dev/null;
git pull --rebase &&
npm install &&
npm test &&
cp package.json _package.json &&
preset=`conventional-commits-detector` &&
echo $preset &&
bump=`conventional-recommended-bump -p angular` &&
echo ${1:-$bump} &&
npm --no-git-tag-version version ${1:-$bump} &>/dev/null &&
conventional-changelog -i History.md -s -p ${2:-$preset} &&
git add History.md &&
version=`cat package.json | json version` &&
git commit -m"docs(CHANGELOG): $version" &&
mv -f _package.json package.json &&
npm version ${1:-$bump} -m "chore(release): %s" &&
git push --follow-tags &&
npm publish

執行上述指令碼會更新 CHANGELOG.md、升級版本號併發布新版本到 npm,所有這些操作都基於提交記錄自動處理。

Branching Model

Vincent Driessen 的分支模型(Branching Model)介紹 Git 分支和開發,部署,問題修復時的工作流程,

workflow

Author: Vincent Driessen Original blog post: http://nvie.com/posts/a-succesful-git-branching-model License: Creative Commons BY-SA

在整個開發流程中,始終存在 master 和 develop 分支,其中 master 分支程式碼和生產環境程式碼保持一致,develop 分支還包括新功能程式碼。

分支模型主要涉及三個過程:功能開發,程式碼釋出和問題修復

功能開發

  1. 從 develop 建立一個新分支(feature/*)

  2. 功能開發

  3. 生產環境測試

  4. Review

  5. Merge 回 develop 分支

程式碼釋出

需要釋出新功能到生產環境時

  1. 從 develop 建立新分支(release/*)

  2. 釋出 feature 分支程式碼到預上線環境

  3. 測試並修復問題

  4. Review

  5. 分別 merge 回 develop 和 master 分支

  6. 釋出 master 程式碼到生產環境

問題修復

當生產環境程式碼出現問題需要立刻修復時

  1. 從 master 建立新分支(hotfix/*)

  2. 釋出 hotfix 程式碼到預上線環境

  3. 修復問題並測試

  4. Review

  5. 分別 merge 會 develop 和 master 分支

  6. 釋出 master 程式碼到生產環境

該分支模型值得借鑑的地方包括,

  • 規範的分支命名

  • 將分支和程式碼執行環境關聯起來

分支和程式碼執行環境的關係是這樣的,

  • master => 生產環境

  • release/,hotfix/ => 預上線環境

  • feature/*,develop => 開發環境

gitflow

Vincent Driessen 的分支模型將開發流程和Git分支很好的結合起來,但在實際使用中涉及複雜的分支切換,gitflow 可以簡化這些工作。

安裝並在程式碼倉庫初始化 gitflow 後,就可以使用它完成分支工作流程,

$ git flow init

No branches exist yet. Base branches must be created now.
Branch name for production releases: [master]
Branch name for "next release" development: [develop]

How to name your supporting branch prefixes?
Feature branches? [feature/]
Release branches? [release/]
Hotfix branches? [hotfix/]
Support branches? [support/]
Version tag prefix? []

功能開發

開始開發時

(develop) $ git flow feature start demo

Switched to a new branch 'feature/demo'

Summary of actions:
- A new branch 'feature/demo' was created, based on 'develop'
- You are now on branch 'feature/demo'

完成開發後

(feature/demo) $ git flow feature finish demo

Switched to branch 'develop'
Already up-to-date.
Deleted branch feature/demo (was 48fbada).

Summary of actions:
- The feature branch 'feature/demo' was merged into 'develop'
- Feature branch 'feature/demo' has been removed
- You are now on branch 'develop'

程式碼釋出

釋出程式碼前

(develop) $ git flow release start demo

Switched to a new branch 'release/demo'

Summary of actions:
- A new branch 'release/demo' was created, based on 'develop'
- You are now on branch 'release/demo'

測試完成準備上線時

(release/demo) $ git flow release finish demo

Switched to branch 'master'
Deleted branch release/demo (was 48fbada).

Summary of actions:
- Latest objects have been fetched from 'origin'
- Release branch has been merged into 'master'
- The release was tagged 'demo'
- Release branch has been back-merged into 'develop'
- Release branch 'release/demo' has been deleted

釋出 master 程式碼到線上環境

問題修復

發現線上故障時,

(master) $ git flow hotfix start demo-hotfix

Switched to a new branch 'hotfix/demo-hotfix'

Summary of actions:
- A new branch 'hotfix/demo-hotfix' was created, based on 'master'
- You are now on branch 'hotfix/demo-hotfix'

修復問題後

(hotfix/demo-hotfix) $ git flow hotfix finish demo-hotfix

Deleted branch hotfix/demo-hotfix (was 48fbada).

Summary of actions:
- Latest objects have been fetched from 'origin'
- Hotfix branch has been merged into 'master'
- The hotfix was tagged 'demo-hotfix'
- Hotfix branch has been back-merged into 'develop'
- Hotfix branch 'hotfix/demo-hotfix' has been deleted

相關連結

  • commitizen

  • gitflow

  • AngularJS Git Commit Message Conventions

  • Git Style

  • node-trail-agent

  • A successful Git branching model

  • Using git-flow to automate your git branching workflow