Closed7

AIによるコミットメッセージを試してみる

kun432kun432

2023/10/31時点。

node製。6.5k stars。最終commitは2023/05。

https://github.com/Nutlope/aicommits

node製。4.7k stars。最終commitは2023/10/05。

https://github.com/di-sukharev/opencommit

go製。774k stars。最終commitは2023/10/31。

https://github.com/appleboy/CodeGPT

所感

  • conventional commitsには全部対応してる
  • 後ろの2つがメンテされてそう
  • 日本語に対応しているのは後ろの2つっぽい。
  • goだと環境気にしなくてよさそう。homebrewでインストールできる。
  • opencommitはcommitlint対応
  • CodeGPTはコードレビュー機能

ということで個人的には導入しやすさ的にはCodeGPTがなんとなく一番良さそう、時点でopencommitって感じ。とりあえず試してみる。

kun432kun432

CodeGPT

https://github.com/appleboy/CodeGPT

  • Support Azure OpenAI Service or OpenAI API.
  • Support conventional commits specification.
  • Support Git prepare-commit-msg Hook, see the Git Hooks documentation.
  • Support customize generate diffs with n lines of context, the default is three.
  • Support for excluding files from the git diff command.
  • Support commit message translation into another language (support en, zh-tw or zh-cn).
  • Support socks proxy or custom network HTTP proxy.
  • Support model lists like gpt-4, gpt-3.5-turbo ...etc.
  • Support do a brief code review.

インストール

homebrewで。

$ brew tap appleboy/tap
$ brew install codegpt
$ version: 0.6.2 commit: 77b2e90

OpenAIのAPIキーをセット

$ codegpt config set openai.api_key sk-XXXXXXXXXXXX

設定は$HOME/.config/codegpt/.codegpt.yamlに保存されるとあるが、APIキーは別にセットされていない?というか設定ファイルが作成されるので、直接設定しろってことなのか?

色々やってみたけど更新されない。直接ファイルを設定すれば問題なさそうではあるが、一旦issueあげておいた

https://github.com/appleboy/CodeGPT/issues/126 マージされました。

設定を確認

$ codegpt config list
Key                       Value
git.diff_unified          3
git.exclude_list
git.template_file
git.template_string
openai.api_key            ****************
openai.api_version
openai.base_url
openai.frequency_penalty  <nil>
openai.headers
openai.max_tokens         300
openai.model              gpt-3.5-turbo
openai.model_name
openai.org_id
openai.presence_penalty   <nil>
openai.provider           openai
openai.proxy
openai.skip_verify        false
openai.socks
openai.temperature        1
openai.timeout            10s
openai.top_p              <nil>
output.lang               en

デフォルトでいくつか設定されているものがある。適宜設定すればよい。

$ codegpt config set output.lang  ja
$ codegpt config set openai.max_tokens 4000

実際の使い方

サンプルのレポジトリを作ってみる。

$ mkdir codegpt-sample && cd codegpt-sample
$ git init
$ echo "# codegpt-sample" > README.md
$ git add .

ではコミットメッセージを生成。--previewだと実際にコミットはされない。

$ codegpt commit --preview
Summarize the commit message use gpt-3.5-turbo model
We are trying to summarize a git diff
PromptTokens: 521, CompletionTokens: 6, TotalTokens: 527
We are trying to summarize a title for pull request
PromptTokens: 177, CompletionTokens: 7, TotalTokens: 184
We are trying to get conventional commit prefix
PromptTokens: 305, CompletionTokens: 1, TotalTokens: 306
We are trying to translate a git commit message to Japanese language
PromptTokens: 95, CompletionTokens: 42, TotalTokens: 137
================Commit Summary====================

ドキュメント: プロジェクトドキュメントにREADME.mdファイルを追加

- README.mdファイルを追加しました。

==================================================
Write the commit message to .git/COMMIT_EDITMSG file

--previewなしでコミットしてみる。

$ codegpt commit 
Summarize the commit message use gpt-3.5-turbo model
We are trying to summarize a git diff
PromptTokens: 521, CompletionTokens: 4, TotalTokens: 525
We are trying to summarize a title for pull request
PromptTokens: 176, CompletionTokens: 6, TotalTokens: 182
We are trying to get conventional commit prefix
PromptTokens: 304, CompletionTokens: 1, TotalTokens: 305
We are trying to translate a git commit message to Japanese language
PromptTokens: 93, CompletionTokens: 38, TotalTokens: 131
================Commit Summary====================

ドキュメント: プロジェクトリポジトリにREADMEファイルを追加

- READMEファイルを追加

==================================================
Write the commit message to .git/COMMIT_EDITMSG file
Git record changes to the repository
[main (root-commit) 4c9151e] ドキュメント: プロジェクトリポジトリにREADMEファイルを追加
 1 file changed, 1 insertion(+)
 create mode 100644 README.md

コミットヒストリーでも実際にコミットされていることが確認できる。

$ git log
commit 4c9151eb1aaca7bb2a9817ef29ebb1d0b269d32e (HEAD -> main)
Author: kun432 <kun432@users.noreply.github.com>
Date:   Tue Oct 31 13:03:21 2023 +0900

    ドキュメント: プロジェクトリポジトリにREADMEファイルを追加

    - READMEファイルを追加

    Signed-off-by: Kuniaki Shimizu <kun432@users.noreply.github.com>

git hookにも対応している。

$ codegpt hook install
Install git hook: prepare-commit-msg successfully
You can see the hook file: .git/hooks/prepare-commit-msg
$ echo -e "\n## Author\n\n- kun432" >> README.md
$ git add 
$ git commit

エディタが開いて、コミットメッセージが予め生成された状態となる。

git hookをアンインストールするには以下

$ codegpt hook uninstall

コードレビュー

コードレビューもできる。

ファイルを編集してgit addする。

$ echo -e "## Usage\n- just do it." >> README.md
$ git add .

レビュー

$ codegpt review
Code review your changes using gpt-3.5-turbo model
We are trying to review code changes
PromptTokens: 108, CompletionTokens: 52, TotalTokens: 160
We are trying to translate code review to Japanese language
PromptTokens: 131, CompletionTokens: 115, TotalTokens: 246
================Review Summary====================

提供されたコードパッチを基にすると、重要な変更は行われていないようです。コードパッチは単にREADME.mdファイルに新しい行を追加するだけです。

そのため、このコードパッチに対して修正が必要なバグのリスクやセキュリティの脆弱性、改善の提案はありません。

==================================================

おわりに

brewコマンドで簡単にインストールできるので、環境構築が不要なのは良い。やはりこの手のツールはgoで書かれていると良いなと思うところ。機能的にもよく使うものは一通りカバーされているし、コードレビューできるのも良いと思う。

とりあえずシンプルにまず始めてみるにはいいと思う。

kun432kun432

OpenCommit

https://github.com/di-sukharev/opencommit

ざっと見た感じ

あたりで機能が豊富そうに思える。Mac新調してからはあまりローカルに環境作らずにdevcontainerを使いたいと思ってたのだけど、グローバルなツールだとちょっと厳しいので、今回はnode環境を作りつつやってみる。

インストール

node環境作ってないのでそこから。バージョン管理はvoltaで。

$ brew install volta
$ volta setup

別ターミナルで。

$ volta install node@20

$ node -v
v20.9.0

opencommitをインストール

$ npm install -g opencommit

OpenAIのAPIキーをセット

$ oco config set OCO_OPENAI_API_KEY=sk-XXXXXXXXXX

設定ファイルは$HOME/.opencommitにある。APIキーをセットしただけだとこんな感じ。

OCO_OPENAI_API_KEY=sk-XXXXXXXXXX
OCO_OPENAI_MAX_TOKENS=undefined
OCO_OPENAI_BASE_PATH=undefined
OCO_DESCRIPTION=false
OCO_EMOJI=false
OCO_MODEL=gpt-3.5-turbo-16k
OCO_LANGUAGE=en
OCO_MESSAGE_TEMPLATE_PLACEHOLDER=$msg
OCO_PROMPT_MODULE=conventional-commit

ということで以下あたりを設定してみる。

$ oco config set OCO_MODEL=gpt-3.5-turbo
$ oco config set OCO_LANGUAGE=ja
$ oco config set OCO_OPENAI_MAX_TOKENS=3000
$ oco config set OCO_EMOJI=true

実際の使い方

サンプルレポジトリを作ってみる

$ mkdir opencommit-sample && cd opencommit-sample
$ git init
$ echo "# opencommit-sample" > README.md
$ git add .

コミットはocoコマンドで行う

$ oco

以下のように生成されるので、OKならば"Yes"を選択。

┌  open-commit
│
◇  1 staged files:
  README.md
│
◇  📝 Commit message generated
│
└  Generated commit message:
——————————————————
📝 ドキュメント(README.md): README.mdファイルを追加
——————————————————

│
◆  Confirm the commit message?
│  ● Yes / ○ No
└

コミットはされたようだけど、なんかエラー出てる。

◇  Confirm the commit message?
│  Yes
│
└  ✔ Successfully committed

│
└  [main (root-commit) fb98012] 📝 ドキュメント(README.md): README.mdファイルを追加
 1 file changed, 1 insertion(+)
│
◇  📝 Commit message generated
│
└  ✖ Command failed with exit code 128: git push
fatal: No configured push destination.
Either specify the URL from the command-line or configure a remote repository using

    git remote add <name> <url>

and then push using the remote name

    git push <name>

どうもpushまで自動的に行うのかな?一応コミットは出来てる。

$ git log
commit fb98012af1965cb17368622b3a46e570f48c60b4 (HEAD -> main)
Author: Kuniaki Shimizu <kun432@users.noreply.github.com>
Date:   Wed Nov 1 09:10:08 2023 +0900

    📝 ドキュメント(README.md): README.mdファイルを追加

リモートブランチ設定して再度やってみる。

$ echo -e "\n##  Usage\n\n- Just do it.\n" >> README.md
$ git add .
$ oco

なるほど、リモートブランチがある場合はpushするかどうかを確認してくれるのね。

┌  open-commit
│
◇  1 staged files:
  README.md
│
◇  📝 Commit message generated
│
└  Generated commit message:
——————————————————
📝 ドキュメント(README.md): 使用方法のセクションを追加

——————————————————

│
◇  Confirm the commit message?
│  Yes
│
└  ✔ Successfully committed

│
└  [main dcf1b18] 📝 ドキュメント(README.md): 使用方法のセクションを追加
 1 file changed, 5 insertions(+)

│
◆  Do you want to run `git push`?
│  ● Yes / ○ No
└
◇  Do you want to run `git push`?
│  Yes
│
◇  ✔ Successfully pushed all commits to origin

まあローカルだけっていう使い方は少ないだろうけども、ちょっとfatalで返されるとビビるよね。無効にするオプションとかないのかなー。-hつけても大したメッセージが出ない。

コミットログはこんな感じでいいですね。大したこと書いてないけども。

git hookにも対応している。

$ oco hook set
┌  setting opencommit as 'prepare-commit-msg' hook at .git/hooks/prepare-commit-msg
│
└  ✔ Hook set

コミットしてみる。

$ echo -e "\n##  Author\n\n- kun432\n" >> README.md
$ git add .
$ git commit

エディタが開いて、コミットメッセージが予め生成された状態となる。

git hookをアンインストールするには以下。

$ oco hook set

GitHub Actions

OpenCommitはGitHub Actionsにも対応している。

https://github.com/marketplace/actions/opencommit-improve-commits-with-ai

以下のようなGitHub Actionsの設定を追加しておく。

.github/workflows/opencommit.yaml
name: 'OpenCommit Action'

on:
  push:
    # 無視するブランチを列挙する
    # 通常はこのブランチのリストで十分だが、必要なら他のブランチも追加する
    branches-ignore: [main master dev development release]

jobs:
  opencommit:
    timeout-minutes: 10
    name: OpenCommit
    runs-on: ubuntu-latest
    permissions: write-all
    steps:
      - name: Setup Node.js Environment
        uses: actions/setup-node@v2
        with:
          node-version: '16'
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - uses: di-sukharev/opencommit@github-action-v1.0.4
        with:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

        env:
          # OpenAI APIキーをレポジトリのGitHub Actionsのsecretに設定しておく
          # OpenAI APIーの取得: https://platform.openai.com/account/api-keys
          # レポジトリのsecretの設定: <レポジトリURL>/settings/secrets/actions
          OCO_OPENAI_API_KEY: ${{ secrets.OCO_OPENAI_API_KEY }}

          # 好みに合わせてカスタマイズ
          OCO_OPENAI_MAX_TOKENS: 3000
          OCO_OPENAI_BASE_PATH: ''
          OCO_DESCRIPTION: true
          OCO_EMOJI: true
          OCO_MODEL: gpt-3.5-turbo
          OCO_LANGUAGE: ja
          OCO_PROMPT_MODULE: conventional-commit

OpenAI APIキーをActionsのSecretにOCO_OPENAI_API_KEYで登録しておく。

では適当なブランチを切って適当なコミットメッセージでコミットしてpushする。

$ git checkout -b sample-branch
$ echo -e "## Thanks\n\n- OpenCommit\n" >> README.md
$ git add .
$ git commit -m "fix"
$ git push --set-upstream origin sample-branch

Actionsが実行されている。

該当のブランチでPRを作成してみると、コミットメッセージが修正されているのがわかる。

CommitLintとの連携?

OpenCommitはデフォルトでConventional Commitsなコミットメッセージを生成するようになっているが、commitlintなどを既に使っている場合はそちらにあわせることもできるらしい。

commitlintあまり詳しくないので詳細は割愛するけど、適当に動かしてみた感じだと、

  • ローカルにcommitlintの設定が行われていれば、その内容を元にOpenCommit用の設定ファイルが作成される
  • 設定ファイルをみると、commitlintの設定を元にプロンプトが生成されており、これでコミットメッセージが生成される模様。

という感じなので、既にcommitlint使っている、という場合でもうまく使えるんじゃないかなという気はした。

おわりに

機能はCodeGPTよりも豊富だと思う。Node.jsなプロジェクトなら全然アリ。個人的には他言語のプロジェクトで使う場合にNode.js環境を用意するのはな〜、、、と思ったのだけど、devcontainer化しておけば気にしなくても良さそう。

kun432kun432

まとめ(2023/11/4時点)

  • まだ試してなくて、とりあえず気軽にローカルで試してみるならCodeGPTが良さそう。環境依存しないし。
  • Node.jsプロジェクトで使う、既存のcommitlint設定も維持する、CIで使う、みたいな場合はOpenCommitで。
  • 有償でもいいから、コミットメッセージ以外も含めてまるっといろいろ、ならGitHub Copilot

って感じかなぁ。いずれにせよ開発フローに影響する部分だと思うので、チーム開発の場合はチーム事情にあわせて検討することになるのではないかという気がする。

CodeGPT環境依存せずに使えて良さそう、このためにわざわざNode.js環境作るのもな~、というのが最初の印象なんだけど、翌々考えてみればVSCode+devcontainerが自分のメイン環境なので、別に全然気にすることないなと思いなおしてるところ。

Copilotは悩み中・・・コミットメッセージだけじゃなくて諸々便利になるのはわかってるんだけども、自分の場合はgitはコマンドで叩くことのほうが多い上、AI関連は他にも結構いろいろ支払いあってチリツモなのよね・・・

kun432kun432

ざっと見た限り、コミットメッセージのカスタマイズ、例えばissue番号紐付ける、とかはどちらもできるようだけども、プロンプトのカスタマイズまでは出来ない模様。コードを変更すれば出来なくはなさそうではあるけれども。まあコミットメッセージにそこまでのニーズはないのかもしれない。

このスクラップは2023/11/04にクローズされました