はじめに
IBM Bob のレビューワークフロー(Code Reviews)は、Git のブランチ間の差分を AI がレビューしてくれる機能です。一通り試した内容は別記事にまとめました。
- 本編: IBM Bob のレビューワークフローを使ってみる
- 公式ドキュメント: Code Reviews - IBM Bob Docs
この記事は、リモートリポジトリを用意せず、git init しただけのローカルリポジトリでレビューワークフローを動かす方法です。
筆者の環境では、リモートが登録されていないリポジトリではレビューパネルにレビュー対象のブランチが出てこず、レビューを開始できませんでした。
ただし、以下の 1 行を実行すれば回避できます。
git symbolic-ref refs/remotes/origin/HEAD refs/heads/main
リモートを作る必要はありません。参照だけ作れば通ります。 以下、なぜこれで通るのか、どこに注意が必要かを順に説明します。
テスト環境
| 項目 | バージョン |
|---|---|
| IBM Bob | 2.0.3 |
| OS | Windows 11 |
UI のラベルや挙動は Bob のバージョンによって変わる可能性があります。以下は筆者が実際に試した時点での内容です。
手順 1: ローカルリポジトリを作る
サンプルプログラムを置いたフォルダで、リポジトリを初期化してコミットします。本編と同じ Python スクリプトを使いました。
import sqlite3
def main() -> None:
conn = sqlite3.connect("sample.db")
cursor = conn.cursor()
cursor.execute(
"create table if not exists shain (id integer primary key, name text)"
)
cursor.execute("delete from shain")
cursor.execute("insert into shain (id, name) values (?, ?)", (1, "田中"))
cursor.execute("insert into shain (id, name) values (?, ?)", (2, "佐藤"))
conn.commit()
conn.close()
if __name__ == "__main__":
main()
実行するコマンドは 4 つだけです(PowerShell で実行しました)。
git init
git add .
git commit -m "first commit"
git branch -M main
git remote add も git push もしません。実行ログは次のようになりました。
PS ...\260817reviewtestLocal> git init
Initialized empty Git repository in .../260817reviewtestLocal/.git/
PS ...\260817reviewtestLocal> git add .
PS ...\260817reviewtestLocal> git commit -m "first commit"
[master (root-commit) e1d5053] first commit
1 file changed, 30 insertions(+)
create mode 100644 sample_shain_select.py
PS ...\260817reviewtestLocal> git branch -M main
git init の既定ブランチ名が master の環境なので、git branch -M main でリネームしています。すでに main で初期化される設定(init.defaultBranch=main)なら不要です。
手順 2: origin/HEAD の参照を作る
ここが本題です。Bob はレビュー対象の既定ブランチを refs/remotes/origin/HEAD という参照から判定しているとみられ、git init から始めたリポジトリにはこの参照がありません。これを手作業で作ります。
git symbolic-ref refs/remotes/origin/HEAD refs/heads/main
意味は「既定ブランチを指す参照を作り、その中身をローカルの main に向ける」です。成功しても何も出力されません(無言で終わります)。
| 指定している値 | 内容 |
|---|---|
refs/remotes/origin/HEAD |
作る参照。Bob が見に来るのはここ |
refs/heads/main |
参照の中身。ローカルの main ブランチ |
参照先には実在するブランチを指定してください。 存在しないパスでも Bob のエラー自体は回避できてしまいますが、その場合は git rev-parse origin/HEAD が
warning: ignoring dangling symref refs/remotes/origin/HEAD
fatal: ambiguous argument 'origin/HEAD': unknown revision or path not in the working tree.
となる壊れた参照(dangling symref)ができます。ブランチ名が main でなければ、そのブランチ名に読み替えてください。
作られたことを確認する
3 つのコマンドで確認できます。
$ git symbolic-ref refs/remotes/origin/HEAD --short
main
$ git branch -a
* main
remotes/origin/HEAD -> main
$ git remote -v
(何も表示されない)
1 つ目が Bob が実行しているとみられるコマンドで、これが値を返せば通ります。3 つ目が空であることが重要で、リモートは 1 つも登録していません。 それでも git branch -a には remotes/origin/HEAD -> main が現れます。
ウィンドウを再読み込みする
参照を作ったあと、レビューパネルを開き直します。すでに開いている場合は表示が古いままなので、ウィンドウの再読み込みが確実です。
-
Ctrl + Shift + Pでコマンドパレットを開く - 開発者: ウィンドウの再読み込み(Developer: Reload Window) を実行する
再読み込みが終わると、レビューパネルにリポジトリとレビュー対象が表示されます。
手順 3: レビュー対象を選ぶ(注意点あり)
再読み込み後、「レビュー対象」のドロップダウンには次の 2 つが現れます。このうち選ぶべきは main(現在)だけです。
| 表示 | 実体 | 選んだ結果 |
|---|---|---|
main(現在) |
ローカルの main
|
これを選ぶ。 未コミット変更がレビュー対象になる |
origin/main |
存在しない | 候補から消え、レビュー対象ファイルが 0 件になる |
main(現在)を選ぶと、コミットされていない変更を含めるが自動で有効になります(レビュー対象が現在のブランチのときの Bob の既定動作です)。この状態でファイルを編集すると、レビュー対象ファイルに M バッジ付きで並びます。
つまりこの構成でレビューされるのは「main の最新コミットと、手元の未コミット変更の差分」です。リモートありの構成で「リモートの最新と手元を比較する」のとは対象が違う点に注意してください。
手順 4: レビューを実行する
あとは本編と同じです。main(現在)を選んだ状態でファイルに変更を加え、レビューを開始を押します。
本編では、f-string で SQL を組み立てるコードを追加して SQL インジェクションを検出させました。
import sqlite3
def main() -> None:
conn = sqlite3.connect("sample.db")
cursor = conn.cursor()
cursor.execute(
"create table if not exists shain (id integer primary key, name text)"
)
cursor.execute("delete from shain")
cursor.execute("insert into shain (id, name) values (?, ?)", (1, "田中"))
cursor.execute("insert into shain (id, name) values (?, ?)", (2, "佐藤"))
target_id = 1
sql_preview = f"select name from shain where id = {target_id}"
cursor.execute(sql_preview)
row = cursor.fetchone()
print(row[0] if row else "該当なし")
# target_id = 1
# cursor.execute("select name from shain where id = ?", (target_id,))
# row = cursor.fetchone()
# print(row[0] if row else "該当なし")
conn.commit()
conn.close()
if __name__ == "__main__":
main()
[画像] レビュー対象に
main(現在)を選び、レビュー対象ファイルにsample_shain_select.pyがM付きで表示された状態
指摘は下部パネルの BOB FINDINGS タブに一覧表示され、そこから Bobで修正 で修正させることもできます。この流れは本編で詳しく書いているので、そちらを参照してください。
補足: ローカルだけでブランチ間の差分をレビューする
ここまでの構成でレビューされるのは未コミット変更だけです。本来の「ブランチ間の差分」をリモートなしで試すこともできます。参照を作ったあとに分岐を作ります。
git checkout -b feature
# feature ブランチで変更してコミット
この状態でレビューパネルを開くと、作成したローカルブランチが候補に並ぶことを確認できました。
feature で作業しながらレビュー対象に main を選べば、そのままブランチ間の差分をレビューできます。
つまり、ブランチ一覧の取得が通ってしまえば、ローカルブランチ同士の比較にリモートは要りません。前述の origin/main のような実体のない候補を避けたい場合も、この形が素直です。
元に戻す・あとからリモートを付ける
作った参照は削除できます。
git symbolic-ref -d refs/remotes/origin/HEAD
なお Windows では、削除のあとに次のようなプロンプトが繰り返し出ることがあります。
Deletion of directory '.git/logs/refs/remotes/origin' failed. Should I try again? (y/n) n
Deletion of directory '.git/refs/remotes/origin' failed. Should I try again? (y/n) n
git が参照を消したあと、空になったディレクトリを片付けようとして失敗している状態です。参照そのものはすでに削除されているので、n を入力して抜けて問題ありません。git branch -a から remotes/origin/HEAD が消えていれば削除は完了しています。
ディレクトリの削除に失敗するのは、フォルダを別のプロセスが掴んでいるためです。OneDrive などの同期対象フォルダ配下にリポジトリを置いている場合は起こりやすいので、空ディレクトリまで消したい場合は VS Code を閉じ、同期を一時停止してから手動で削除してください。残っていても無害です。
あとから本物のリモートを用意する場合は、参照を削除してから通常の手順を実行します。最後の git remote set-head origin -a が、今回手作業で作った参照をリモートの実際の既定ブランチに向けて作り直してくれます。
git symbolic-ref -d refs/remotes/origin/HEAD
git remote add origin https://github.example.com/your-account/260817reviewtest.git
git push -u origin main
git remote set-head origin -a
まとめ
-
git initから始めたローカルリポジトリでは、レビュー対象のブランチが取得できないことがある。 原因は Bob が見に来るrefs/remotes/origin/HEADという参照が存在しないこと - 回避策は
git symbolic-ref refs/remotes/origin/HEAD refs/heads/mainの 1 行。リモートの登録は不要で、参照だけで足りる - 実行後はウィンドウを再読み込みする
- レビュー対象の候補に出る
origin/mainは実体がないので選ばない。選ぶとレビュー対象ファイルが 0 件になる。main(現在)を選ぶ - この構成でレビューされるのは未コミット変更。「コミットされていない変更を含める」は自動で有効になる
- 分岐を作ればローカルブランチ同士の比較もリモートなしでできる(候補に並ぶことを確認)
- うまく動かないときは、まず
git symbolic-ref refs/remotes/origin/HEAD --shortが値を返すかを確認する
なお、公式ドキュメントに書かれているレビューの前提条件は「比較したいローカル/リモートブランチにアクセスできること」だけで、リモートの登録が必須とは書かれていません。本来はリモートなしの構成でも動くべきところなので、この挙動は将来のバージョンで変わる可能性があります。






